pax_global_header00006660000000000000000000000064145564217010014517gustar00rootroot0000000000000052 comment=ab2faeca1ba6c456333312c58f58ef9e5ef4aa8b ESS-24.01.1/000077500000000000000000000000001455642170100123165ustar00rootroot00000000000000ESS-24.01.1/.dir-locals.el000066400000000000000000000006421455642170100147510ustar00rootroot00000000000000;;; Directory Local Variables ;;; For more information see (info "(emacs) Directory Variables") ((nil (bug-reference-bug-regexp . "#\\(?2:[0-9]+\\)") (bug-reference-url-format . "https://github.com/emacs-ess/ess/issues/%s") (sentence-end-double-space)) (emacs-lisp-mode (outline-regexp . "\f\\|\\`;\\|;;\\*\\|;;;\\*\\|(def[cvum]\\|(setq\\|;;;;\\*") (indent-tabs-mode)) (ess-r-mode . ((ess-style . RRR)))) ESS-24.01.1/.gitignore000066400000000000000000000007261455642170100143130ustar00rootroot00000000000000*~ *.orig *# *.info doc/ess.* doc/info/ess.info doc/readme.* doc/refcard/refcard.* *history *VERSION *REVISION *BACKUP* *REMOTE* *LOCAL* *BASE* *.elc doc/html/*.html README ANNOUNCE MM-MISC Mail-head RPM*.spec *SVN* ess-[1-9]*.[0-9][0-9] ess-[1-9]*.[0-9][0-9][-.]??? ess-[1-9]*.[0-9][0-9]-[0-9] ess-[1-9]*.[0-9][0-9]-[0-9][-.]??? lisp/julia* lisp/ess-autoloads.el tmp* .DS_Store ._.DS_Store .dependencies NEWS ONEWS # ELPA-generated files /ess-autoloads.el /ess-pkg.el ESS-24.01.1/.mailmap000066400000000000000000000025471455642170100137470ustar00rootroot00000000000000Alex Branham David Shepherd David Whiting Ernest AdroguĂ© nfdisco Ernest AdroguĂ© nfdisco Henning Redestig Henning Redestig Mark Lunt Martin Maechler Martin Maechler Martin Maechler sfs Rodney Sparapani Shuguang Sun Shuguang Sun ShuguangSun Stefan Theussl theussl Stephen Eglen Stephen J. Eglen Wilfred Hughes Yi Liu Yi Liu Yi Liu YiLiu6240 dickmao <7578770+dickmao@users.noreply.github.com> ESS-24.01.1/.travis.yml000066400000000000000000000030421455642170100144260ustar00rootroot00000000000000language: emacs-lisp env: # When there's a new major Emacs release, also update # byte-compile-error-on-warn to the new release, below - EVM_EMACS=emacs-25.1-travis - EVM_EMACS=emacs-25.3-travis - EVM_EMACS=emacs-26.1-travis-linux-xenial - EVM_EMACS=emacs-26.2-travis-linux-xenial - EVM_EMACS=emacs-26.3-travis-linux-xenial - EVM_EMACS=emacs-27.1-travis-linux-xenial - EVM_EMACS=emacs-git-snapshot-travis-linux-xenial before_install: - echo "deb https://cloud.r-project.org/bin/linux/ubuntu trusty/" | sudo tee -a /etc/apt/sources.list - sudo add-apt-repository ppa:marutter/c2d4u -y - sudo apt-get update -qq - sudo apt-get install -y --no-install-recommends --allow-unauthenticated r-recommended r-cran-roxygen2 texinfo texlive-latex-base texlive-latex-recommended texlive-latex-extra - git clone https://github.com/rejeep/evm.git $HOME/.evm - export PATH=$HOME/.evm/bin:$PATH - evm config path /tmp - evm install $EVM_EMACS --use --skip before_script: # link R executable to test defining runners based on other R # versions found on PATH. We're lying here that it is in fact a # different R version but that doesn't matter. - mkdir ess-r - ln -s $(which R) $PWD/ess-r/R-3.2.1 - export PATH=$PATH:$PWD/ess-r/ script: - emacs --version - R --version - cd lisp; make julia-mode.elc - cd .. - make -C test -k all - make -C doc ../README # Create package.el-installable tar file, test that it installs # successfully: - make package - emacs --script targets/travis-install-package.el ESS-24.01.1/0001-ess-request-a-process-Honor-ess-gen-proc-buffer-name.patch000077500000000000000000000041121455642170100256400ustar00rootroot00000000000000From 68984a5a0a1df5a5a2619b579f23f70128e979cd Mon Sep 17 00:00:00 2001 Message-ID: <68984a5a0a1df5a5a2619b579f23f70128e979cd.1705837631.git.yantar92@posteo.net> From: Ihor Radchenko Date: Sun, 21 Jan 2024 12:44:32 +0100 Subject: [PATCH] ess-request-a-process: Honor ess-gen-proc-buffer-name-function * lisp/ess-inf.el (ess-request-a-process): Do not make processes not matching `ess-gen-proc-buffer-name-function' current. --- lisp/ess-inf.el | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lisp/ess-inf.el b/lisp/ess-inf.el index 9ca3f455..aaff314c 100644 --- a/lisp/ess-inf.el +++ b/lisp/ess-inf.el @@ -820,7 +820,7 @@ (defun ess-request-a-process (message &optional noswitch ask-if-1) (delete-dups (list "R" "S+" (or (bound-and-true-p S+-dialect-name) "S+") "stata" (or (bound-and-true-p STA-dialect-name) "stata") "julia" "SAS"))))) - (pname-list (delq nil ;; keep only those matching dialect + (pname-list (delq nil ;; keep only those matching dialect and `ess-gen-proc-buffer-name-function' (append (mapcar (lambda (lproc) (and (equal ess-dialect @@ -828,6 +828,8 @@ (defun ess-request-a-process (message &optional noswitch ask-if-1) 'ess-dialect (process-buffer (get-process (car lproc))))) (not (equal ess-local-process-name (car lproc))) + (equal (buffer-name (process-buffer (get-process (car lproc)))) + (funcall ess-gen-proc-buffer-name-function (car lproc))) (car lproc))) ess-process-name-list) ;; append local only if running -- 2.43.0 ESS-24.01.1/COPYING000066400000000000000000001045151455642170100133570ustar00rootroot00000000000000 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 . ESS-24.01.1/ChangeLog000066400000000000000000006300021455642170100140710ustar00rootroot000000000000002024-01-25 ESS Maintainers * Version 24.01.0 released. 2018-11-10 ESS Maintainers * Version 18.10.2 released. 2018-10-23 ESS Maintainers * Version 18.10-1 released. 2018-10-20 ESS Maintainers * Version 18.10 released. 2018-07-17 Rodney Sparapani * lisp/ess-sas-l.el (SAS-log-mode) and (SAS-listing-mode): add (buffer-disable-undo) since these buffers are buffer-read-only and they can get quite large. Furthermore, when they are re-generated/reverted/reloaded with (ess-revert-wisely) & friends; these large buffers trigger an error: undo-outer-limit exceeded. 2017-11-13 ESS Maintainers * Version 17.11 released. 2016-10-22 ESS Maintainers * Version 16.10 released. 2016-05-07 ESS Maintainers * Version 16.04 released. 2015-12-11 ESS Maintainers * Version 15.09-2 released. 2015-10-26 ESS Maintainers * Version 15.09-1 released. 2015-09-24 ESS Maintainers * Version 15.09 released. 2015-04-23 ESS Maintainers * Version 15.03-1 released. 2015-03-31 ESS Maintainers * Version 15.03 released. 2014-09-13 ESS Maintainers * Version 14.09 released. 2013-12-07 ESS Maintainers * Version 13.09-1 released. 2013-09-27 ESS Maintainers * Version 13.09 released. 2013-05-14 ESS Maintainers * Version 13.05 released. 2013-01-12 ESS Maintainers * Version 12.09-2 released. 2012-12-21 ESS Maintainers * Version 12.09-1 released. 2012-09-24 ESS Maintainers * Version 12.09 released. 2012-06-07 ESS Maintainers * Version 12.04-4 released. 2012-06-01 ESS Maintainers * Version 12.04-3 released. 2012-05-11 ESS Maintainers * Version 12.04-2 released. 2012-04-05 ESS Maintainers * Version 12.04 released. 2012-03-30 ESS Maintainers * Version 12.03 released. New numbering scheme. 2011-07-30 ESS Maintainers * Version 5.14 released. 2011-06-20 Henning Redestig * etc/ess-roxy-tests.R (trickyInArgsComments): small examples I used to try out ess-roxy 2011-05-03 Rodney Sparapani * doc/unixlike.texi (Unix installation): * Makeconf (LISPDIR): Installing everything into site-lisp is sloppy; better to create an ess sub-directory and install there. 2011-04-26 Rodney Sparapani * doc/help-sas.texi (ESS(SAS)--TAB key): removing all references to uncommenting ess-site.el code since we moved away from that several years ago, however, the vestiges still linger (OK, but isn't that what vestiges do?) 2011-03-07 Stephen Eglen * doc/help-s.texi (ESS(S)--Editing files): Document calling R-mode directly. 2011-03-01 Stephen Eglen * doc/ess.texi (Debugging R): New node. 2011-02-28 Rodney Sparapani * doc/requires.texi: update BUGS info and include texi2dvi WARNING 2011-02-03 ESS Maintainers * Version 5.13 released. 2010-12-15 Dirk Eddelbuettel * etc/pkg-Maintainers (Debian): updated 2010-11-09 Rodney Sparapani * doc/announc.texi (Announce): \ * doc/currfeat.texi (Current Features): \ * doc/requires.texi (Requirements): \ * doc/stabilty.texi (Stability): \ Minor tweaks to bring it slightly more up-to-date. 2010-11-08 ESS Maintainers * Version 5.12 released. 2010-08-13 Stephen Eglen * doc/ess.texi (Org): New section describing interaction with Org mode, contributed by Dan Davison and Eric Schulte. 2010-07-13 ESS Maintainers * Version 5.11 released. 2010-06-08 ESS Maintainers * Version 5.10 released. 2010-05-21 ESS Maintainers * Version 5.9.1 released. 2010-05-21 ESS Maintainers * Version 5.9 released. 2010-04-25 Henning Redestig * doc/ess.texi (Roxygen): added documentation for ess-roxy 2010-04-08 Rodney Sparapani * doc/ess.texi (Top): Cosmetic change to see if the web page is updating like it should 2010-03-03 ESS Maintainers * Version 5.8 released. 2009-12-07 ESS Maintainers * Version 5.7.1 released. 2009-12-07 ESS Maintainers * Version 5.7 released. 2009-12-04 ESS Maintainers * Version 5.6 released. 2009-11-22 Stephen Eglen * doc/help-s.texi (iESS(S)--Inferior ESS processes): Add documentation about how exec-path determines which directories are searched to find R versions. 2009-10-07 ESS Maintainers * Version 5.5 released. 2009-10-02 Martin Maechler * doc/{windows|unixlike}.texi: fix *wrong* e-mail for ess-help 2009-06-08 ESS Maintainers * Version 5.4 released. 2009-05-27 Rodney Sparapani * Makefile (downloads): new target for creation of .tgz and .zip only 2009-04-22 Stephen Eglen * doc/ess.texi (TAGS): Describe R CMD rtags. (TAGS): Expand on documentation, thanks to feedback from Martin. 2009-03-05 Rodney Sparapani * doc/newfeat.texi, doc/help-bugs.tex, doc/help-jags.texi: ESS[BUGS] and ESS[JAGS]: typing = now results in <- 2009-02-23 Rodney Sparapani * Makeconf: update LISPDIR, INFODIR, ETCDIR for XEmacs. Use the modern default /usr/local/share/xemacs rather than the deprecated /usr/local/lib/xemacs. Also, default to the site-packages subdirectory rather than xemacs-packages, this allows you more freedom to update the SUMO packages without touching your ESS installation and vice versa. 2009-01-23 ESS Maintainers * Version 5.3.11 released. 2009-01-21 Rodney Sparapani * Makefile (all install clean distclean): @for loop throws away exit code, probably due to cd .. which always returns 0; @for no longer used 2009-01-13 Rodney Sparapani * doc/windows.texi and doc/unixlike.texi (Installation): replace fake double quotes in examples with real double quotes 2009-01-12 Rodney Sparapani * doc/Makefile, doc/ess.texi, doc/readme.texi, doc/windows.texi, doc/unixlike.texi (Installation): new simplified installation instructions for Windows and Unix/Unix-like including Mac OS X (major changes now complete) 2009-01-07 Rodney Sparapani * doc/Makefile (TEXISRC): add help-jags.texi to list * doc/help-jags.texi (ESS(JAGS)--Log files): the "log" of the run is now .jog (like BUGS which is .bog); .out created too many problems since the BOA output files have that extension as well (ESS(JAGS)--Model files): adding 2 new local variables: ess-jags-burnin and ess-jags-update. ESS[BUGS] has similar variables, but the modern defaults are an order of magnitude bigger, so it seemed like creating new variables was warranted 2008-12-17 Rodney Sparapani * doc/windows.texi (Microsoft Windows installation): this file will replace the Windows portion of inst_tar.texi 2008-12-15 Rodney Sparapani * doc/Makefile (install-other-docs): fixing yet another bug related to DOCDIR, was there no testing at all before foisting this on us? 2008-12-09 Rodney Sparapani * Makeconf and doc/Makefile (DOCDIR): belatedly document and defensively create 2008-12-03 Rodney Sparapani * Makeconf and doc/readme.texi (README re-organization): Add TOC for plaintext format only, requires re-defining MAKETXT accordingly. 2008-12-02 Rodney Sparapani * doc/readme.texi and doc/Makefile (README re-organization): re-arrange so that installation information comes in the 4/5th sections rather than much further down (7/8th); also massaged wording in the intro which no longer requires as much perl (which I never really understood since I don't speak perl; shall we stick to what we all know: e-lisp/make/texi/not perl/etc.) 2008-11-14 Stephen Eglen * doc/ess.texi (Indenting): Describe roxygen 2008-07-28 ESS Maintainers * Version 5.3.8 released. 2008-04-10 ESS Maintainers * Version 5.3.7 released. 2007-09-13 ESS Maintainers * Version 5.3.6 released. 2007-08-15 ESS Maintainers * Version 5.3.5 released. 2007-07-20 Stephen Eglen * doc/help-s.texi (iESS(S)--Inferior ESS processes): Document R-newest. 2007-04-26 ESS Maintainers * Version 5.3.4 released. 2006-12-16 Martin Maechler * doc/ess.texi (Help): do look up the 's *' bindings and mention differences R <-> S(-plus) 2006-09-26 ESS Maintainers * Version 5.3.3 released. 2006-09-19 ESS Maintainers * Version 5.3.2 released. 2006-06-03 ESS Maintainers * Version 5.3.1 released. 2006-04-07 ESS Maintainers * Version 5.3.0 released. 2006-04-07 Martin Maechler * doc/refcard/refcard.tex: update for ESS 5.3.0 2006-02-09 Anthony Rossini * doc/newfeat.texi: documentation for @code{ess-use-inferior-program-name-in-buffer-name}, 2006-02-07 ESS Maintainers * Version 5.2.12 released. 2006-01-06 Stephen Eglen * doc/ess.texi (Help with emacs): New section, referring people to Emacswiki and FAQs. 2005-11-14 ESS Maintainers * Version 5.2.11 released. 2005-09-09 ESS Maintainers * Version 5.2.10 released. 2005-08-30 ESS Maintainers * Version 5.2.9 released. 2005-05-12 ESS Maintainers * Version 5.2.8 released. 2005-04-18 ESS Maintainers * Version 5.2.7 released. 2005-03-14 ESS Maintainers * Version 5.2.6 released. 2005-02-01 ESS Maintainers * Version 5.2.5 released. 2005-01-06 ESS Maintainers * Version 5.2.4 released. 2004-12-31 Stephen Eglen * doc/inst_tar.texi (Unix installation): Remove note regarding GNU Make, as this is relevant only for developers, and so does not need to be in the user's guide [the shorter the installation instructions, the better!] 2004-12-29 Stephen Eglen * doc/newfeat.texi: Mention changes to completion. * doc/inst_tar.texi (Unix installation): Comment out optional step about creating database files for slow computers; delete later. * doc/ess.texi (Completion details): Comment out note about slow completion on old systems; delete later. (Imenu): Add note about imenu regexps. 2004-10-27 Martin Maechler * doc/ess.texi: added Debian patches from Camm Maguire * lisp/* : dito for six files 2004-09-21 ESS Maintainers * Version 5.2.3 released. 2004-07-27 Martin Maechler * Moved from CVS to Subversion 2004-07-08 ESS Maintainers * Version 5.2.2 released. 2004-06-28 ESS Maintainers * Version 5.2.1 released. 2004-05-22 Stephen Eglen * doc/ess.texi (Interactive ESS): At the start of the chapter on iESS, introduce a few general terms before getting into specifics. 2004-05-17 Stephen Eglen * doc/ess.texi: Few typos; add brief description of Imenu and document the 'l' key when viewing help files. 2004-05-05 Stephen Eglen * doc/ess.texi (winjava): Put empty lines around example to get proper formatting. 2004-05-04 Stephen Eglen * doc/help-s.texi (ESS-help--assistance with viewing help): Refer to Help chapter. * doc/ess.texi (Multiple ESS processes): ess-request-a-process not bound to C-c C-k. Commented out some doc for ess-plain-first-buffername. (System dependent): Change of section name from "Other variables ..." to "Variables ...". 2004-04-28 Stephen Eglen * doc/ess.texi: Document winjava, inferior-ess-own-frame and ess-help-own-frame. 2004-02-22 Stephen Eglen * doc/bugrept.texi: Describe how to make a *Backtrace* buffer. 2004-02-19 Stephen Eglen * doc/ess.texi (ESS processes on Remote Computers): add brief notes on how to get a ssh buffer. Note that URL currently spills into right margin in ess.pdf; anyway to prevent that? 2002-11-29 Stephen Eglen * doc/ess-defs.texi: New file to provide macros for formatting R, S, SPLUS. * doc/ess.texi: Quite a few updates to the documentation: Include ess-defs.texi for @Sl macro. Add Stephen to author list. Remove bold from ESS/S. Remove Variable and command index (had just two entries). Use "X window system" or "X11" rather than "X-windows" (see `man X'). Add section on editor=emacsclient. Change "more historic"->"older" Correct exit() entry in the variable and command index. Remove multiple references to Emacs/XEmacs differences in .emacs/init.el for init file. 2002-08-07 Martin Maechler * VERSION: new version -- Makefile did not commit (aarggh).. * lisp/Makefile, Makefile: more Makefile tweaks: lisp/ess-cust.el with proper version number must be committed (in time before tagging etc) * lisp/ess-cust.el: new version -- Makefile did not commit (aarggh).. * info/ess.info-3, info/ess.info-4, info/ess.info-1, info/ess.info, info/ess.info-2: Updating info for new version * ANNOUNCE, README: Updating README, ANNOUNCE for new version * doc/newfeat.texi: prepare for release of 5.1.23 (with *correct* version number)! * Makefile: dist: also update lisp/ess-cust.el rel : also `tag' 2002-08-06 rsparapa * info/ess.info-1: Updating info for new version * ANNOUNCE, doc/authors.texi, doc/getting.texi, doc/inst_cvs.texi, doc/newfeat.texi, doc/requires.texi, info/ess.info-1, info/ess.info, info/ess.info-2, info/ess.info-3, info/ess.info-4, README: docs: I was trying to create a PDF version of ANNOUNCE with texi2dvi and dvipdf (is there a better way?). And, certain functions like @email and @code betray unsightly behavior. I replaced @email with @uref:mailto and @code with @display. You may note that a better translation of @code would be @example, but @example misbehaves as well. @display doesn't make a difference for info or HTML, but it does for PDF. However, there doesn't appear to be an alternative for the moment. Another bug, is texi2html ignores the @enumerate argument (besides mishandling @macro statements). Oh joy! 2002-08-05 rsparapa * ANNOUNCE, doc/announc.texi, doc/Makefile, doc/readme.texi, README, info/ess.info-1: docs: some final minor changes to docs before release. Also, attempted to address Martin's concern in doc/Makefile with respect to install. Now, you can differentiate between making in the doc directory and installing elsewhere as the documentation indicates. The target install has returned for info files only. 2002-08-02 rsparapa * doc/dir, doc/help-sas.texi, doc/Makefile, info/ess.info-1, info/ess.info, README, info/ess.info-2: info: Rich's comment made me realize that we may also need to "install" the dir file. So, I changed the Makefile to: $(INFODIR)/ess.info: $(TEXISRC) @echo "making Info documentation..." $(MAKEINFO) ess.texi $(INSTALL) ess.info* $(INFODIR) test -f $(INFODIR)/dir || $(INSTALL) dir $(INFODIR) I suppose that a more sophisticated approach could be taken, but this is probably good enough for now. I believe that all issues that I was working on are now complete. I'm going on vacation on 8/7 and then to JSM the following week, but I should have e-mail and internet access the whole time. Did someone once say "Release early and release often"? 2002-08-01 rsparapa * info/dir: dir: I discovered what the problem is with @direntry and GNU Emacs 21. Apparently, the functionality differs between XEmacs and Emacs. Under XEmacs, the @direntry has precedence over the dir file. Emacs appears to be just the opposite. So, I edited the dir file by hand. Not sure where this file comes from. info/emacs does not create this file in a directory that doesn't already have one. The file doesn't seem to be created by makeinfo and that's where the problem lies. There is no synchronization between @direntry and dir once dir has been created (however that happens). The best solution at present is to keep the two in synch by hand. Which really isn't that big of a deal since we are only talking about one line being identical in dir and ess.texi * doc/ediff-sas.gif, doc/ess-demo.jpg, doc/ess-intro.pdf, doc/ess-intro.tex, doc/font-cor-s.gif, doc/font-cor-s.jpg, doc/font-incor-s.gif, doc/font-incor-s.jpg, doc/hilock-sas.gif, doc/Makefile, README, fontlock-test/baseball.sas, info/ess.info, info/ess.info-1, info/ess.info-2, info/ess.info-3, info/ess.info-4: docs: committing files based on recent discussion 2002-07-31 rsparapa * doc/ess.texi, README: HTML docs: a few tweaks to the texinfo to create a reasonable HTML table of contents * doc/ess.texi, README: doc bug: I was testing out the info docs and I realized that the "Detailed Node List" and the actual nodes for Installation were different. In this case, it would lead you to believe that there weren't any relevant topics in the Installation section because you see the "Detailed" list first, but there's nothing on it. I suppose you could carefully check each "Detailed" vs. actual node combination, but that would be time-consuming and prone to failure. And, I also realized that nobody would want a 100 item list when they can drill-down from a 10 item list anyways. So, I was lazy and just commented out the entire "Detailed Node List". * ANNOUNCE, doc/Makefile, README, doc/announc.texi, doc/authors.texi, doc/credits.texi, doc/ess.texi, doc/help-sas.texi, doc/inst_tar.texi, doc/readme.texi, info/ess.info-1, info/ess.info, info/ess.info-2, info/ess.info-3, info/ess.info-4: more doc changes: Where should I begin? I realized that having info files might not be helpful if you didn't already have ESS installed. So, I decided to create HTML docs and put them @ software.biostat.washington.edu:/ess/doc/html But, texi2html doesn't work with version.texi. After pulling my hair out, I decided to read the documentation. Guess what? texi2html doesn't support @macro commands. So, instead of @essver{}, I replaced those references by @include ../VERSION which seems to work. Of course, this was after I re-did the doc/Makefile thinking there was something wrong in there. The HTML docs are now on the net. And, lots of other "improvements" to the docs. * doc/ess.texi, info/ess.info, README, info/ess.info-1, info/ess.info-2, info/ess.info-3, info/ess.info-4: info: running some long SAS jobs, ZZZZZzzzzZZZZZ... Meanwhile, re-wrote parts of the intro and re-arranged some of the documentation categories; boy is that fun. NOT! Promoted "Help for the S family" and "Help for SAS" to main categories so you don't have to poke around so long. One bugaboo that remains with GNU Emacs 21.1-21.3 is the @direntry which is set to: * ESS: (ess). Emacs Speaks Statistics (S/S+/R, SAS, BUGS, Stata, XLisp-Stat). but, Emacs sadly reports: ESS Version 5.x.y (was: S-mode). This works fine on XEmacs 21.4.8 and I'm using texinfo 4.2 * lisp/ess-utils.el: ess-kermit-get, ess-kermit-send I had to replace (shell) with ess-sas-goto-shell; maybe we should generalize ess-sas-goto-shell and ess-sas-shell-buffer in ess-utils.el too 2002-07-30 rsparapa * lisp/Makefile: lisp/Makefile: essa-sas.el should not be compiled since it is required by essl-sas.el and therefore, already compiled * lisp/Makefile: lisp/Makefile: fixed a bug testing whether a directory is . 2002-07-29 rsparapa * doc/ess.texi, doc/help-sas.texi, info/ess.info, info/ess.info-1, info/ess.info-3, README, info/ess.info-4: Help for SAS: more updates and fixes; now ready for release 2002-07-27 rsparapa * doc/Makefile, Makefile: Makefile: changed target info to the more descriptive and appropriate docs 2002-07-26 rsparapa * doc/ess.texi, doc/help-sas.texi: ESS[SAS] info documentation: lots of minor changes that should make it a better intro as well as a more complete and correct manual * doc/Makefile, lisp/Makefile, Makeconf, Makefile: more Makefile mods: made INSTALL comments more explicit and removed install as the target from main Makefile, it was only present in the lisp Makefile in any case * Makefile: main Makefile: realclean target deleted; doc and lisp Makefile's don't have it anyway; ESSVERSIONDIR changed to ESSDIR * Makeconf: Makeconf: made 2 comments more explanatory * doc/Makefile, Makeconf, Makefile, doc/newfeat.texi: more Makefile/Makeconf improvements: I think this should do it for the next release. Enjoy! * info/ess.info-1, info/ess.info: Updating info for new version * ANNOUNCE, README: Updating README, ANNOUNCE for new version * Makeconf, README, doc/Makefile, info/ess.info-1, info/ess.info, info/ess.info-2, info/ess.info-3, info/ess.info-4, lisp/Makefile: more Makefile changes: Apparently, we had two different methods for replacing old version numbers with new ones. For some reason, the old method based on perl stopped working. So, we created a new method based on @essver{}. However, the old version targets and dependencies remained. I have no idea what kind of weirdness resulted from that. Just in case, I'm removing the old method. 2002-07-25 rsparapa * lisp/essa-sas.el: ESS[SAS]: ess-sleep-for now defaults to 5 seconds on Windows only (which was where the problem was initially) * lisp/essa-sas.el: ESS[SAS]: fixed bug in ess-sas-submit-sh for Kermit file transfers; noticed that ess-kermit- functions call (shell) when it probably should be ess-sas-goto-shell 2002-07-24 rsparapa * doc/Makefile, fontlock-test/baseball.sas, Makeconf, Makefile, VERSION: Makefile happy-land: I think I finally figured this maze out. We'll see when we try to release 5.1.21 * lisp/ess-utils.el: ess-utils.el: fixed a bug in ess-save-and-set-local-variables; more exhaustive testing later tonight * lisp/essa-sas.el: ESS[SAS]: ess-save-and-set-local-variables is now called from ess-sas-submit-sh, ess-sas-submit-windows and ess-sas-submit-mac rather than save-buffer which formerly appeared in ess-sas-submit. Not, sure what to do with ess-sas-submit-iESS, but it should not be called in ess-sas-submit-region. Also, now called in ess-sas-data-view so you can take advantage of the recently added ess-sas-data-view-fsview-statement buffer-local variable. * lisp/ess-utils.el: ess-utils.el: added 2 new functions ess-search-except: searches forward for a regexp, stores as match 1 and optionally, ignores results that also match a second regexp parameter, and optionally, searches backward for a third non-nil parameter ess-save-and-set-local-variables: if a buffer is modified, save the buffer and if Local Variables are defined, update them with revert returning t if buffer was modified and nil otherwise * lisp/essa-sas.el: ESS[SAS], ess-sas-data-view: Now, I'm adding features just for myself. I've always wanted the capability to add a PROC FSVIEW statement to an ess-sas-data-view call, but I just never got around to it. You can configure it with the string ess-sas-data-view-fsview-statement. Also, you can now change the PROC FSVIEW command itself with ess-sas-data-view-fsview-command and I renamed ess-sas-data-view-options to ess-sas-data-view-submit-options to make it more clear what it does (i.e. so you don't confuse -options with -fsview-command). * Makeconf, doc/Makefile, info/ess.info-1, info/ess.info, info/ess.info-2, info/ess.info-3, Makefile, info/ess.info-4, lisp/Makefile: Makeconf/Makefile tweaking: still need to re-organize doc Makefile which is currently in the main Makefile and the doc Makefile 2002-07-23 rsparapa * Makeconf: Makeconf: minor improvements in anticipation of a more important role for this method of installing ESS * lisp/make-regexp.el: make-regexp.el: timing functions removed due to name collisions with Gnus 2002-07-22 rsparapa * lisp/essa-sas.el: ESS[SAS]: extended ess-sas-goto-shell to take an optional argument if non-nil, then set-buffer rather than switch. This new call replaces code chunks in ess-sas-submit-region, ess-sas-data-view and ess-sas-graph-view. Furthermore, this behavior is what was intended in nearly all (ess-sas-goto-shell) calls and I have replaced them all with (ess-sas-goto-shell t); except for the key-bindings for F8/F3 and the code that deals with kermit file transfers which require the old behavior. Have only tested on XEmacs and 'sh, so YMMV. * lisp/essa-sas.el: ESS[SAS]: ess-sas-goto-shell resurrected! Our recent discussion with respect to each SAS program, perhaps, needing it's own ess-sas-submit-method brought me back to ancient discussions of asynchronous shell buffer names. Emacs and XEmacs named them differently. Our solution was to use & for 'sh and start for 'ms-dos to make synchronous processes asynchronous. However, this made ess-sas-goto-shell unnecessary since the buffer was always *shell*. Now, I added the variable ess-sas-shell-buffer which is buffer-local and defaults to *shell*. If you set this to something else, then you will get another shell buffer. And, ess-sas-goto-shell will take you to whichever one you need. So, we are back to the original function. I also moved the add-hook call to the shell creation step since it seemed like over-kill to call it every time you did ess-sas-submit-sh. Is this enough explanation or am I boring you? 2002-07-19 rsparapa * lisp/essa-sas.el: ESS[SAS]: tweaks to -> ess-sas-submit-mac for JSM presentation * lisp/essa-sas.el: ESS[SAS]: ess-sas-submit-method needs to be buffer-local so that ess-sas-submit can submit different buffers in different ways with the Local Variables trick 2002-07-16 rsparapa * lisp/ess-utils.el: ess-utils.el: added ess-kermit- functions; now, it's really ready for testing * lisp/ess-cust.el: ess-cust.el: added ess-kermit- variables * lisp/essa-sas.el: ESS[SAS]: moved ess-kermit- variables to ess-cust.el and ess-kermit- functions to ess-utils.el * lisp/ess-cust.el: ess-cust.el: applied Stephen's patch; also changed more :types from "string" to 'string; finally, fixed custom-ize for SAS; it always worked if you specified 'ess-sas for the group, but never worked if you specified 'ess; this was because defgroup defined 'ess-SAS rather than 'ess-sas; and, now I understand what :prefix does; we discussed this previously and nobody knew (the documentation doesn't say either); :prefix is the beginning of the variable name that the custom-ize buffer doesn't show you; therefore, it seems that :prefix should be "ess-" for 'ess-sas; I think this is what it always was, but now I know this is right; only tested this on XEmacs 21.4.8 which is nearly bullet-proof; please test on buggier versions of (x)emacs 2002-07-11 rsparapa * lisp/essa-sas.el: ess-search-except, ess-sas-data-view, ess-sas-graph-view: improvements to all; simplification of the latter -view's with ess-search-except and other minor changes * lisp/essa-sas.el: ess-search-except: I forgot to include the bloody example of it's use; now see ess-sas-data-view. * lisp/essa-sas.el: ess-search-except: I believe it does what we want now. Sorry, to make this a multi-stage commit, but I can think in SAS, not elisp yet :o) * lisp/essa-sas.el: ess-search-except: I had some free time and I decided to write a function to perform the complex searches that are necessary for ess-sas-data-view. I suppose a function like this would be valuable for ess-sas-graph-view and for other packages as well. After a bit more testing, I'll put it some place more appropriate. I suppose we don't have a lot of time left before 5.2.0 * lisp/essa-sas.el: ess-sas-data-view: the code will make your head hurt, but the search for a permanent SAS data just got a little smarter. After it finds a tentative candidate in a forward search, it checks if it is a work./first./last. If so, then it backward searches. I suppose a better approach would be to write an ess-search function that takes arguments for regexp, direction, and exceptions to ignore. I don't have time right now, but let's add it to the TODO. 2002-07-02 rsparapa * doc/ess.texi: updated copyright to 2002. Deep thought: does everything need a person to copyright it? Wouldn't it be better to have something like: Copyright (C) 2002 ESS Developers? 2002-06-24 rsparapa * lisp/essa-sas.el: ess-sas-data-view: Now ignoring WORK datasets since there is no way to open them anyway. It would be nice if this function (as well as ess-sas-graph-view) could also be accessible via the mouse. Any hints as to how to do it would be appreciated. Currently, you have to move the point manually or re-type the dataset/graph that you want to view. Just clicking on a dataset/graph would be easier. 2002-06-24 Martin Maechler * lisp/essdsp6w.el, lisp/essd-r.el, lisp/essd-s3.el, lisp/essd-s4.el, lisp/essd-sp3.el, lisp/essd-sp4.el, lisp/essd-sp5.el, lisp/essd-sp6.el: activate imenu for S+modes, using the ess-[SR]-use-imenu variable (in R and S+) 2002-06-20 rsparapa * lisp/ess-emcs.el, lisp/ess-inf.el, lisp/ess-menu.el, lisp/ess-mode.el, lisp/ess-mous.el, lisp/ess-trns.el, lisp/noweb-mode.el: all ess-running-xemacs have now been replaced with (featurep 'xemacs) * VERSION: VERSION: 5.2.0 2002-06-19 rsparapa * lisp/ess-emcs.el: ess-emcs.el: (featurep 'xemacs) has been implemented according to Rich's suggestion; however, ess-running-xemacs is rather pervasive among numerous other ESS lisp files; I don't have time to go into every file and change them all; but, this will certainly be the recommended route to take with ESS 6 2002-06-19 rmh * lisp/essdsp6w.el, lisp/ess-emcs.el, lisp/essd-sp4.el, lisp/ess-site.el: w32-short-file-name win32-short-file-name 2002-06-19 rsparapa * README, ANNOUNCE: Updating README, ANNOUNCE for new version 2002-06-18 rsparapa * doc/ess.texi, doc/inst_tar.texi: Unix Installation: massive changes; I really don't understand points 7 and 8, but I assume the XEmacs parts of 8 will change once 5.2.0 is an "official" XEmacs package; I suggest similar changes be made to Microsoft Windows Installation, but I made none. Enjoy! 2002-06-18 Martin Maechler * lisp/essd-r.el: allow prompt "Browse[1]> " -- i.e. add "[]" to valid prompt chars (but not as first one!) 2002-06-18 rsparapa * lisp/essa-sas.el: ess-kermit-get: last bug-fix ; it's about as user-friendly as I can imagine at the moment 2002-06-17 rsparapa * doc/help-sas.texi, doc/inst_tar.texi, doc/newfeat.texi, doc/requires.texi: doc: minor improvements * doc/currfeat.texi, doc/newfeat.texi: doc: a few minor changes in preparation for the 5.2.0 release * lisp/essa-sas.el: ESS[SAS]: fixed a newly introduced bug in ess-kermit-get; synchronized ess-kermit-send with ess-kermit-get; replaced equal with string-equal (do we need to do this globally?); I'd like to do a little bit more testing before 5.2.0; I'll try to get it done tonight * lisp/essa-sas.el: ESS[SAS]: changes for more user friendly kermit file transfers; ess-kermit-prefix default is now # which should be os-independent; former defaults, : or ], could be problematic and were based on ange-ftp/efs/tramp (an unnecessary restriction it turns out); when ess-sas-goto is passed the suffix "log" or "lst" ess-kermit-get is called if the file starts with ess-kermit-prefix; other extensions could be dangerous since you might have altered the local copy whereas .log and .lst files are only being modified by the SAS batch job; as long as the integrity of the .sas program is maintained .log and .lst can always be retrieved if an unwanted transfer overwrites them 2002-06-04 rsparapa * lisp/ess-utils.el: ess-utils: explanatory comment on the recent change in ess-revert-wisely 2002-05-28 rmh * doc/ess.texi, doc/help-sas.texi, info/ess.info-1, info/ess.info, info/ess.info-2, info/ess.info-3, info/ess.info-4: M-x SAS does not work with MS Windows 2002-05-28 rsparapa * Makefile: Makefile: made compile the default; also fixed problem with make all 2002-05-27 Martin Maechler * doc/README.SPLUS4WIN: 5.1.21, not *.20 (is this not yet integrated in *.texi ?) 2002-05-21 rmh * doc/dir, info/dir: dir file needed in same directory as *.info* files * doc/ess.texi, doc/help-sas.texi, info/ess.info-1, info/ess.info, info/ess.info-2, info/ess.info-3, info/ess.info-4, README: improve documentation for ess-remote 2002-05-20 rsparapa * Makefile: Makefile: commented out a stray reference to info in the doc directory * ANNOUNCE, README: Updating README, ANNOUNCE for new version 2002-05-17 rmh * doc/ess.texi, info/ess.info-1, info/ess.info, info/ess.info-2, info/ess.info-3, info/ess.info-4: document ess-remote, S+elsewhere, ess-elsewhere * doc/ess.texi, doc/help-s.texi, doc/inst_tar.texi, info/ess.info-1, info/ess.info, info/ess.info-2, info/ess.info-3, info/ess.info-4, README: add reference to ~/.xemacs/init.el as the Xemacs alternate for the Gnu emacs file .emacs 2002-05-16 rsparapa * lisp/essa-sas.el: ESS[SAS]: ess-sas-data-view; oops that was not right. now fixed. dataset names may end in macro variables, but libraries must not 2002-05-14 rsparapa * lisp/essa-sas.el: ESS[SAS]: ess-sas-data-view will now recognize a permanent SAS dataset name that ends in a macro variable. You will be prompted with the portion of the name up to, but not including the macro variable, since it wouldn't be valid otherwise. You will need to complete the dataset name. You cannot use a macro variable for the library since &libname.dataname is macro concatenation. 2002-05-13 rsparapa * lisp/essa-sas.el: ESS[SAS] doc-strings: updated doc-strings for ess-sas-submit-method * doc/help-sas.texi: ESS[SAS] help: ess-sas-submit-method discussed, with respect to both local and remote SAS batch jobs including Kermit 2002-05-12 rmh * info/ess.info-1, info/ess.info, info/ess.info-2, info/ess.info-3, info/ess.info-4: repair trailing garbage by removing [] from node names * doc/ess.texi, doc/help-sas.texi, doc/help-s.texi: @node lines cannot contain []. I replaced them with () in the node lines and left them at [] in the section heads and in the body of the text. 2002-05-10 rsparapa * doc/help-sas.texi: ESS[SAS] help: discussion of ess-sas-submit-command etc. But, still need to discuss ess-sas-submit-method and kermit too. 2002-05-10 rmh * doc/ess.texi: Thank you Martin, I was starting do essentially the same thing to ess.texi. Now I don't have to. I did one extra step. We had an empty chapter in the dvi that I commented out. @comment @chapter Help for Statistical Packages Then I promoted both S and SAS to chapter status. @chapter Help for the S family @chapter Help for SAS There is a fundamental problem in both help-s.texi and help-sas.texi. Make the ess.dvi and then look at the S and SAS chapters. Both chapters have a trailing piece of the node-name as the last line in each section. I tried several ways to make that go away with no success. Can you figure out what is going on and fix it? Thanks 2002-05-10 Martin Maechler * doc/ess.texi, doc/inst_tar.texi: comment empty chapter; update nodes and menus (in Emacs) and hand fix 2002-05-10 rmh * lisp/essd-els.el: gnuclient doesn't work across tcpip (or at least I don't yet know how), so I removed it from inferior-ess-language-start for ess-remote. * lisp/essdsp6w.el, lisp/essl-s.el: S-Plus 6 help() function uses pager=options()$help.pager I modified inferior-S-language-start in essl-s.el to always define options()$help.pager to have the same value as options()$pager. Only S-Plus 6 uses this new value. The way the statement is constructed, it does not get used for R and it generates a harmless extra component to the options() in earlier versions of S-Plus. 2002-05-10 rsparapa * doc/getting.texi, doc/newfeat.texi: doc: updates for next release 2002-05-10 rmh * lisp/essd-sas.el: put ess-eval-line-and-step-invisibly on C-c i on sas-mode-local-map * lisp/essd-els.el: ess-remote for SAS needs shell-mode * lisp/ess-inf.el: ess-eval-line-and-step-invisibly is needed for ess-remote to work with sas * lisp/essd-els.el: ess-remote now works for "sas -stdio" 2002-05-09 rsparapa * doc/announc.texi: ANNOUNCE: missed a reference to @essver{} 2002-05-08 Martin Maechler * lisp/ChangeLog, lisp/ess-trns.el: clean-region fix for new menu function 2002-05-07 Martin Maechler * doc/Makefile: better Makefile fixes; add "pdf" target * doc/ess.info-1, doc/ess.info, doc/ess.info-2, doc/ess.info-3, doc/ess.info-4, doc/Makefile: Makefile fixes; ess.info* only in ../info * doc/requires.texi: @footnote properly * doc/help-s.texi: some @item s fixed --- do NOT use manual "-" for items! * doc/requires.texi: minor typo in footnote * doc/Makefile: run pdftex twice 2002-05-07 rsparapa * README: Updating README, ANNOUNCE for new version 2002-05-06 rmh * doc/ess.info-1, doc/ess.info, doc/ess.info-2, doc/ess.info-3, doc/ess.info-4, doc/help-s.texi: @display * Makefile: add ess.info-4 2002-05-05 rsparapa * lisp/essa-sas.el: ESS[SAS]: ess-kermit-send incorporated into ess-sas-submit-sh kermit is almost as transparent as tramp and ange-ftp/EFS just execute ess-sas-submit like any other file 2002-05-05 rmh * lisp/ess-trns.el: install Thomas Baumann repair to ess-transcript-clean-region 2002-05-04 rsparapa * lisp/essa-sas.el: ESS[SAS]: ess-sas-submit-sh now works with local copies of kermit transfer files. just need some documentation. 2002-05-03 rsparapa * lisp/essa-sas.el: ESS[SAS]: ess-kermit-send now works although I haven't tested it completely. still need to fix ess-sas-submit-sh * lisp/essa-sas.el: ESS[SAS]: updated ess-kermit-get per the latest proposal; created a variable ess-kermit-prefix which is customize-able that can be used to specify the files that are recognized as local kermit copies of remote files. : is the default and the only other value that is recommended is ] also, created ess-kermit-remote-directory which is buffer local and the default is customize-able; currently $HOME when you run ess-kermit-get you can reset this variable and ess-kermit-get is now documented haven't fixed ess-kermit-send, but it should be trivial also note, that if you have just done an ess-kermit-send then ess-sas-submit-sh should work as long as we handle the cd command appropriately, i.e. "cd ." 2002-05-02 rmh * lisp/essd-els.el: change SAS to SAS-customize-alist * lisp/essd-els.el: add &optional proc-name to ess-remote 2002-05-01 rmh * lisp/essd-els.el: ess-remote First draft of what I consider the right way to do what we have previously called S+elsewhere and ESS-elsewhere. Please test this. Start a telnet or other protocol to a remote computer, start S or R (or maybe something else), M-x ess-remote, and tell it which dialect. You are now talking to an inferior-ess process. I added all the *-customize-alist to ess-select-alist-dialect. I added only sp6 to the dialects we prompt for, but all will be recognized. Rodney, dialect "sas" points to S+elsewhere-customize-alist rather than to SAS-customize-alist. If this works then ess-add-ess-process should be moved from essa-sas.el to ess-inf.el * lisp/essdsp6w.el, lisp/ess-site.el: tweaks to S+6 for S-Plus 6.1 for Windows beta 1 Delay time is now a user variable ess-S+6-startup-delay. No delay time for S+6-existing. We verify the version of S-Plus 6 and hide and make read-only the file we check. ESS now prompts for the correct directory. 2002-04-29 rmh * lisp/essdsp6w.el: S-Plus 6.1 beta for Windows works correctly with ESS. 6.0 didn't work correctly. I modified M-x S+6 to "Verify that `inferior-S+6-program-name' points to S-Plus 6. Start normally for S-Plus 6.1. Inform the user to start S-Plus 6.0 from the icon and than connect to it with `S+6-existing'. Give an error message if `inferior-S+6-program-name' doesn't point to S-Plus 6." S-Plus 6.1 starts up exceedingly slowly. I changed the delay time in M-x S+6-initiate to 60 seconds (double what we needed for M-x S+4). The is the delay needed for my 300MHz machine. I will make this a variable so the users can customize it for their speed. 2002-04-27 Martin Maechler * lisp/ess-trns.el: ..-DO-clean-region; added to Menu; see ChangeLog * lisp/essd-sp6.el: ess-setup-directory-fun etc from Jeff Mincy 2002-04-26 Martin Maechler * lisp/ess-cust.el: version number was lost -- bug in perl in Makefile ??? * doc/Makefile: ess.info -> ../info * lisp/ess-cust.el: new ess-directory-function and ess-history-directory stuff from Jeff Mincy * lisp/ess-site.el: wrap file-name-as-directory around ess-lisp-dir... [from Jeff Mincy] 2002-04-25 rossini * lisp/essd-r.el: we don't want the semantic stuff "live" yet! * lisp/essd-r.el, lisp/r.bnf, lisp/sas.bnf, lisp/semantic-r.el, lisp/semantic-sas.el: These files are the start of semantic.el support. Useful for using the CEDET tools (cedet.sourceforge.net), including ECB. Definitely worth a bit of time, but they get awfully confusing. 2002-04-21 rmh * lisp/essa-sas.el: simplify ess-sas-toggle-sas-log-mode for legibility, no change in what it does, see email for details. 2002-04-17 rmh * doc/ess.info-4, doc/Makefile: we now have ess.info-4 * doc/ess.info-1, doc/ess.info, doc/ess.info-2, doc/ess.info-3, doc/ess.texi, doc/help-sas.texi, doc/help-s.texi, doc/inst_tar.texi, doc/Makefile: I fixed up help-sas, installed help-s, fixed up some style issues, cleaned up cross references to empty pages. All occurrences of @essver MUST have braces @essver{} or else the remainder of the source line is treated as a comment. The doc/Makefile doesn't depend on the *.texi files. I attempted to change it to $(ESSINFODIR)/ess.info: *.texi but that doesn't work. So I used $(ESSINFODIR)/ess.info: ess.texi help-sas.texi inst_tar.texi The @display requires everything to be left justified. Otherwise the indentations are interpreted as hard spaces. Why are some lines in @display and others in @example? They look the same. This is inst_tar.texi, lines 29-36 @example gunzip ess-@essver{}.tar.gz tar vxf ess-@essver{}.tar @end example @display (or: @code{gunzip < ess-@essver{}.tar.gz | tar vxf -} ). (or using GNU tar: @code{tar zvxf ess-@essver{}.tar.gz}). @end display I added the control-function keys to help-sas.texi I fixed the help menu pointers to the empty operating system nodes. As long as I am doing info, I fixed up help-s.texi and installed it. It compiles correctly. It still needs to be read carefully to make sure it is coherent. I think the various doc/README* files now need to be regenerated from the appropriate *.texi files. 2002-04-16 rsparapa * doc/ess.info-1, doc/ess.info, doc/ess.info-2, doc/ess.info-3, doc/Makefile: Updating docs for new version * README: Updating README, ANNOUNCE for new version * doc/readme.texi: Updating docs for new version * README: Updating README, ANNOUNCE for new version * doc/ess.info-1, doc/ess.info, doc/ess.info-2, doc/ess.info-3, doc/ess.texi, doc/inst_tar.texi, doc/readme.texi: Updating docs for new version * README: Updating README, ANNOUNCE for new version * doc/inst_tar.texi: doc: added one @display that I forgot earlier 2002-04-16 rmh * doc/help-sas.texi: make last line less than 80 columns * doc/help-sas.texi: typos and introduce filetype-2 earlier * doc/help-s.texi, doc/readme.texi: @essver and s-plus 6 references 2002-04-16 rsparapa * Makefile: Makefile(xemacs-links): updated to reflect the new location of info files which makes a very logical connection in this case as well. * info/ess.info-1, info/ess.info, info/ess.info-2, info/ess.info-3, info/ess.info-4: info: need a directory with nothing else in it for a concise display and this seemed like a logical choice 2002-04-15 rsparapa * README: Updating README, ANNOUNCE for new version * doc/ess.info-1, doc/ess.info, doc/ess.info-2, doc/ess.info-3, doc/help-sas.texi, doc/inst_tar.texi, VERSION: 5.1.21: more doc changes for release * ANNOUNCE, README: Updating README, ANNOUNCE for new version * doc/ess.info-1, doc/ess.info, doc/ess.info-2, doc/ess.info-3, doc/ess.texi, doc/help-sas.texi, doc/inst_tar.texi, doc/Makefile, doc/readme.texi, lisp/ess-emcs.el, Makefile: 5.1.21: lots of changes for 5.1.21 release * doc/ess.info-1, doc/ess.info, doc/ess.info-2, doc/ess.info-3, doc/getting.texi, doc/help-sas.texi, doc/requires.texi: doc: many changes addressing Rich's concerns (please see rsparapa discussion if you are interested). Before 5.1.21 can be released, we need to figure out how to get texinfo to generate the proper version number in all documents. 2002-04-12 rsparapa * doc/newfeat.texi, lisp/essl-sas.el: ESS[SAS]: corrected font-locking for in: operator * doc/announc.texi, doc/help-sas.texi, doc/newfeat.texi: doc: changes for 5.1.21 release * doc/ess.info, doc/ess.info-1, doc/ess.info-3, doc/help-sas.texi: doc: First attempt at creating info documentation for SAS. It is basically README.SAS with a few additions/corrections. Fine for this release, but could use a lot of work. * lisp/essa-sas.el: ESS[SAS]: F12 (graph view) now defined for all locales 2002-04-10 rsparapa * lisp/essl-sas.el: ESS[SAS]: estimate and contrast keywords are now highlighted 2002-04-09 rsparapa * doc/announc.texi, doc/ess.info-1, doc/ess.info, doc/ess.info-2, doc/ess.info-3, doc/ess.texi, doc/help-s.texi: doc: first attempt at creating user manual with texinfo. I thought that I could just mimic help-s.texi. However, help-s.texi appears to be a basket case. It has no @menu statements. This made it impossible for me to makeinfo. So, instead I created help-sas.texi from scratch based on README.SAS. Note that the @menu commands will cause problems if they contain : so I've been using --. Also note that makeinfo appears to create working info pages, but texi2dvi does not create documents correctly. It's a shame since they are very nice, except for garbage which appears to be mangled next, previous, and up. This will cause us a lot of problems if we want to maintain one source and produce .info, .html and .pdf (I actually only tried viewing with xdvi, but I suspect the problem exists with other formats, but I pray not). 2002-04-04 hornik * lisp/essddr.el: Add '\docType'. 2002-03-27 rossini * xemacs/README: files and build/export for xemacs package 2002-03-22 rsparapa * lisp/essa-sas.el, lisp/essl-sas.el: ESS[SAS]: added font-lock support for legacy COMMENT...; style comments 2002-03-19 rsparapa * lisp/essa-sas.el: ESS[SAS]: Somehow managed to have to two functionally identical versions of ess-sas-file-path; now only one. 2002-03-18 rsparapa * doc/requires.texi: doc: added "custom" link 2002-03-17 rsparapa * doc/requires.texi: doc: noted that certain geriatric versions of emacs are no longer supported 2002-03-12 rmh * lisp/essd-r.el, lisp/ess-inf.el: make C-c C-q work with R I checked it on windows with rw1041. Please verify the repair for unix. essd-inf.el I modified ess-quit to treat R as a special case because R asks the question "Save workspace image? [y/n/c]: ". essd-r.el I modified inferior-ess-exit-command and added inferior-ess-exit-prompt 2002-03-03 rmh * lisp/ess-iw32.el: ess-command on windows. fix last week only needed if buf is t. 2002-02-27 rmh * lisp/Makefile: add mouseme.el to lisp/Makefile 2002-02-27 rsparapa * lisp/essa-sas.el: ESS[SAS]: GSASFILE viewing for Emacs 21.1; I figured out how to view image files in Emacs 21.1. But, apparently it only works for Unix at the moment. You have to turn on the minor mode auto-image-file-mode. Then opening a .jpg or .jpeg file will display it in a buffer. It is supposed to work with .gif files, but it doesn't for me; so I'm only activating this feature for JPEG. 2002-02-26 rsparapa * lisp/ess-emcs.el: lisp(ess-emcs.el): added a function to display graphical images per the XEmacs documentation (for 21.4 and higher) * lisp/essa-sas.el: ESS[SAS]: viewing GSASFILEs; XEmacs supports .gif and .jpg natively. So, on XEmacs, those formats are displayed in an empty buffer. Otherwise, graphics are handled as before (with an image viewer program). 2002-02-26 rmh * lisp/ess-iw32.el: The repair of the C-c C-l problem reported by S.McClatchie and Bj”©Ìrn-Helge Mevik required a change to ess-command in ess-iw32.el. I believe the problem was limited to Windows machines and first appeared in 5.1.19 when I added ess-command to ess-iw32.el. The temporary buffer buf was not associated with an ESS process. Now it is. This is a consequence of how I created a windows version of ess-command. Part of loading a file is checking whether the new file would overwrite any old S language objects. This in turn requires running search() which uses ess-command. The temporary buffer created to hold the results of the search was not associated with an ESS process. Therefore when ess-command checks whether it is running under Windows, it finds instead that it is in the tbuffer which is not connected with an ESS process so it can't decide and quits. Since the original buffer that the user was trying to load was correctly connected to an ESS process, the user is justifiably confused. The repair is done at the most central point, at the ess-command for windows. 2002-02-25 rsparapa * lisp/Makefile: lisp Makefile: added ess-mous.el, but have not tested it 2002-02-20 rsparapa * lisp/essa-sas.el: ESS[SAS]: added a missing F11 key definition and new functionality for F12; pressing F12 searches for a GSASFILE definition, otherwise defaults to SAS program name and opens the image file in an image viewer application available on that OS (defaults to the CDE sdtimage for Unix and kodakimg for MS) 2002-02-20 rsparapa * Makefile: Makefile: Oops. We don't want tag to depend on rel. For tagging we have to rely on the user to do the appropriate thing. 2002-02-19 rossini * lisp/ess-cust.el: edited ess-source-directory doc string to include my favorite setting. It's amazing what you find when you start looking... 2002-02-19 rsparapa * Makefile: Makefile: after make rel goes flawlessly; do a make tag; you might want to wait a few days just to be sure since the tag must be unique and we don't want micro number escalation 2002-02-19 rsparapa * doc/currfeat.texi: Current Features: deleted SPSS 2002-02-13 rsparapa * Makefile: Makefile: Removed the JCGS paper from the distributions and fixed some problems. First of all, zip will update a .zip if it already exists. I found no way to change this behavior. Also, gzip will prompt you before overwriting a .gz. So, I just delete the files if they already exist with a test && rm || true. Also, tar would occasionally give me an error about symbolic links. So, I did a mv instead of an ln -s. * doc/ess.info-1: Updating docs for new version 2002-02-07 rsparapa * Makefile: Makefile: updated for new repository 2002-02-07 rsparapa * doc/ess.info-1, doc/ess.info, doc/ess.info-2, doc/ess.info-3: Updating docs for new version * ANNOUNCE, README: Updating README, ANNOUNCE for new version * lisp/essa-sas.el: ESS[SAS]: last change before 5.1.20; forgot to add C-TAB to the globalization for PC keys * doc/announc.texi, doc/credits.texi, doc/inst_cvs.texi, doc/inst_tar.texi, doc/mailing.texi, doc/newfeat.texi, doc/readme.texi, doc/stabilty.texi: Doc changes for pending ESS-5.1.20 release. 2002-01-31 rsparapa * lisp/essl-sas.el: ESS[SAS]: mult-line comments of the /* */ variety are always fontified correctly because they are handled by grammar rather than regular expressions. OTOH, * ; and %* ; comments have only worked in the past on single line comments. This is particularly annoying in SAS-log-mode since a single-line comment will often be flowed and not fontified correctly. There is no solution TIKO for the multiple line problem so I changed the regular expression to just fontify the first line which will at least allow you to recognize that a comment is beginning which is better than the way it was before. * lisp/essl-sas.el: ESS[SAS]: improved macro statements syntax highlighting, i.e. you have more freedom of placement than you do for SAS statements in general 2002-01-28 Martin Maechler * lisp/ess-help.el: doc string * lisp/ess-utils.el: comment * doc/newfeat.texi, lisp/ChangeLog, lisp/essddr.el: C-c C-f (finally!) 2002-01-24 rsparapa * lisp/essl-bug.el: ESS[BUGS]: working, but no elsewhere yet 2002-01-23 rsparapa * lisp/essl-bug.el: ESS[BUGS]: let's schedule elsewhere for the next release * lisp/essa-sas.el: ESS[SAS]: should be good to go for the next release; will test tomorrow * lisp/essa-sas.el: ESS[SAS]: a uniform interface for batch elsewhere may be a bit too ambitious at this time * lisp/essa-sas.el: ESS[SAS]: a few adjustments * lisp/essa-sas.el, lisp/ess-batch.el, lisp/essl-bug.el: ESS-elsewhere: moving towards a common codebase for batch ESS-elsewhere 2002-01-21 rmh * lisp/essdsp6w.el: change *ddeclient ESS* to '(ddeESS [S+6])' * lisp/essd-sp4.el: 1. change strings from *ddeclient ESS* to '(ddeESS [S+4])' 2. There is a weird error in this version that I don't understand. The environment variable PATH gets the value of MANPATH. I cannot figure out why. It is MANPATH for me on two machines so far, I don't know if that is related to my personal list of environment variables or something else. The fix I installed here works on my machine, I hope it works on others. I did attempt a generalization, but that didn't work for me. * lisp/ess-site.el: change default to (fset 'S 'S+6) etc. * lisp/ess-inf.el: remove commented out .in.ESS. This was replaced with options()$STERM yesterday. 2002-01-20 rmh * doc/ess.info, doc/ess.info-2, doc/ess.info-3: matches ess.texi from a few minutes ago. * doc/ess.info-1, doc/ess.texi, doc/inst_tar.texi, doc/newfeat.texi, lisp/ess-site.el: 1. In ess-site.el section 2.1 I made two changes. For the item a I want an opinion. a. I changed the default in this section from S-Plus 4,5,3 to S-Plus 6 for all three of those operating systems? Is there still a need to distinguish linux from other unixen? b. I added (fset 'Sqpe 'Sqpe+6) for Windows 2. I edited inst_tar.texi to match. 3. While in inst_tar.texi I added to the SAS discussion and fixed up the installation section to xref the Unix and MS sections to each other. 4. The current ess.texi and ess.info-2 have only the unix information. I deleted the whole installation section from ess.texi and replaced it with @include inst_cvs.texi 5. Tony, please fix up inst_cvs.texi once the anonymous cvs server in washington is working. 6. Rodney, please put Macintosh instructions into inst_cvs.texi. 7. I promised Terry Therneau that I would comment on indentation and fancy comments in the *info*. I did so in ess.texi. While there I added Rodney to the author list. 8. I added the STERM discussion to ess.texi. 9. I started to add the pager and editor discussion to ess.texi and realized that I can't until the "@node Edit buffer" section is completely rewritten. I may do this, but not tonight. This entire section describes the behavior pattern that we do not encourage. It describes the "S objects are real" philosophy deprecated in the README.S file. The revision can leave that in, but must have a section based on the "Source code is real" philosophy. * lisp/ess-cust.el, lisp/essd-els.el, lisp/essd-r.el, lisp/essd-s3.el, lisp/essd-s4.el, lisp/essd-sp3.el, lisp/essd-sp4.el, lisp/essd-sp5.el, lisp/essd-sp6.el, lisp/essdsp6w.el: I installed options("STERM") in the rest of the S language essd*.el files. I documented it in ess.texi and in newfeat.texi. STERM has the value "iESS" for all except S+4 and S+6 for Windows. In those two situations it has value "ddeESS". Suggestions for non-ESS values are in the ess.texi. I also installed options("editor") and options("pager"). Default definitions are in ess-cust.el Windows Unix Macintosh R-pager nil nil nil R-editor gnuclient emacsclient nil S-pager gnuclientw emacsclient nil S-editor gnuclient emacsclient nil When the ESS value is nil, then nothing gets sent to the S language process. ess-cust defcustomed all new variables essd-r revised from last week a. R-editor and R-pager b. defun R-transcript and fset r-transcript c. moved R-mode to follow R essd-s3 a. I changed two (setq-default ess-customize-alist S3-customize-alist) to use setq. b. moved S3-mode to follow S3 essd-s4 essd-sp3 essd-sp5 essd-sp6 essd-sp4 essdsp6w essd-els I made it match, but it needs rethinking. The right plan is something along the lines of a. telnet to the remote, b. start remote ess process, c. `ess-add-ess-process' 2002-01-18 rsparapa * lisp/essa-sas.el: ESS[SAS]: automated ess-sas-suffix-regexp and commented out ess-sas-smart-backtab 2002-01-17 rmh * lisp/tmpfile: I got a newer version of cygwin. Now PCL-CVS works from the office. I will check from home later. * lisp/tmpfile: test commit with PCL-CVS 2002-01-16 rmh * lisp/essa-sas.el, lisp/ess-mous.el: Tony, what is `ordinary-insertion-filter' in `essl-sta.el'. doing in the middle of `ess-command' in ess-inf.el? Rodney, please look at the cvs log ess-mous.el There are several questions and comments about ess-processes in the Jan 14 log that overlap what you are doing in essa-sas.el essa-sas.el: I finally understand why we have been having trouble communicating about S+elsewhere. `ess-add-ess-process' is a much simpler functional equivalent to the kludge in `S+elsewhere' and `ESS-elsewhere'. I revised the doc-string to make it more accurate and also simplified the function while I was there. ess-mous.el: I got rid of the end-of-line-problem I was having. 2002-01-16 rsparapa * lisp/essl-sas.el: ESS[SAS]: fixed bug in PROC syntax highlighting; updated doc-string for sas-program 2002-01-16 Martin Maechler * lisp/ChangeLog, lisp/ess-menu.el: improved imenu-expression from Stephen E 2002-01-16 rsparapa * lisp/essl-bug.el: ess-revert definition removed, call to ess-revert replaced by ess-revert-wisely * lisp/essa-sas.el: SAS on Mac now accepts ess-sas-submit-command-options like the others * lisp/essl-sas.el: sas-program defaults to sas except on Mac where it is the AppleScript equivalent * lisp/ess-utils.el: added ess-revert-wisely 2002-01-15 rsparapa * lisp/essa-sas.el: ESS[SAS]: tweak to local variable recognition in ess-sas-submit 2002-01-15 rmh * lisp/essl-sas.el: force SAS-listing-mode * lisp/essl-sas.el: force minor-mode * lisp/essa-sas.el, lisp/essl-sas.el: The ess-sas-toggle-log-sas-mode I posted yesterday didn't quite work. It go hung because the log and LOG options stepped on each other's toes. So I put it all into a single if statement, renamed it to ess-sas-toggle-sas-log-mode, made it refer to SAS-log-mode, and redefined SAS-log-mode to agree with current usage. 2002-01-15 Martin Maechler * lisp/ChangeLog, lisp/essl-s.el: add-log (Changelog) 2002-01-15 rmh * lisp/essa-sas.el: I finally read the latest essa-sas.el 1. I found ess-sas-toggle-sas-mode several months ago and started to use it. I like it. Now that I have read it closely I revised it and renamed it. ;;; this version of ess-sas-toggle-log-sas-mode ;;; 1. can be included in .emacs as ;;; (ess-sas-toggle-log-sas-mode t) ;;; because it doesn't need to find a .log file. ;;; 2. works if there is already an association for .log files. ;;; 3. restores the old association when SAS-mode is deleted. ;;; 4. works with the file it has, doesn't kill it and get a fresh copy. ;;; This matters for large log files and slow telephone connections. ;;; 5. I changed its name to be more descriptive. 2. How is kermit used by ESS? I see definitions for ess-kermit-command ess-kermit-get ess-kermit-send, but do not see any places they are used. I think these three items should be separated into a new ess-kermit.el rather than buried in essa-sas.el. Are they restricted to ess in any way? Might they be better as a new kermit.el? 3. You hardwired the `txt' extension into ess-sas-file-path. That should be sensitive to the value of ess-sas-suffix-1 and ess-sas-suffix-2. 4. ess-sas-submit-mac is the only ess-sas-submit* that does not have ess-sas-submit-command-options. I don't understand ess-sas-submit-command-options. Why is it buffer-local? I think it should depend on the host and the version of sas, not on the myfile.sas command file. Am I misunderstanding what is going on? 5. ess-revert-wisely in essa-sas.el and ess-revert in essl-bug.el are identical. This suggests that the ess-revert name should be used and moved to ess-utils.el * lisp/ChangeLog, lisp/ess-inf.el, lisp/ess-mode.el, lisp/ess-mous.el, lisp/ess-trns.el: ess-mous is ready for testing. ess-mous.el: put ess-mous on submenu of C-mouse-3 for ess-transript-mode, inferior-ess-mode, ess-mode This feature is still beta. ess-inf.el: ess-ddeclient-p. now depends on ess-local-process-name get-ess-process. I changed error message to say buffer is not associated with an ESS process (instead of saying that no ESS process is running) inferior-ess-mode-menu. Added "What is this? (beta)" ess-trns.el: ess-transcript-mode-menu. Added "What is this? (beta)" ess-mode.el: ess-mode-menu. Added "What is this? (beta)" ChangeLog: ess-mous changes. I tested it on windows for R, S+4, and Sqpe+4. I am having line-ending problems with Sqpe+4 but otherwise it looks ok. Please look at it. I found a problem which I am unsure how to solve. The variable `ess-current-process-name' in the `*R*' buffer can have the value "S+4". All I have to do is open an S+4 process and an R process, then C-c C-s the file.s buffer to S+4 and then switch to the R process. I think, but am willing to hear arguments against it, that anytime an inferior-ess-mode buffer is made current, then it should automatically reset `ess-current-process-name' to refer to itself. I'm not sure how to do that. This is explicitly not a buffer-local variable. Is there a hook that gets called when we change into a buffer, either by C-x b or by clicking? 2002-01-14 rsparapa * lisp/essa-sas.el: ESS[SAS]: if Local Variables are defined, a revert is necessary to update them if changed; anybody know a better way? 2002-01-14 rsparapa * lisp/essl-sas.el: ESS[SAS]: some minor changes/corrections to customize variables * lisp/essa-sas.el: ESS[SAS]: ess-sas-submit-command and ess-sas-submit-command-options are buffer-local with appropriate adjustments in the ess-sas-submit- methods 2002-01-11 rmh * lisp/essd-r.el: STERM only. Keep S-pager S-editor variables, but initialized to nil 2002-01-11 rsparapa * lisp/essa-sas.el: ess-revert-wisely: vc-revert-buffer acting strangely in Emacs 21.1; commented out until workaround is found * lisp/essa-sas.el: ESS-elsewhere: ess-kermit-get works and it is no longer ESS[SAS] specific other than the location of the defun 2002-01-11 rmh * lisp/ChangeLog, lisp/essd-r.el, lisp/ess-inf.el: STERM pager editor 2002-01-10 rmh * doc/newfeat.texi: add mouse-me 2002-01-10 rsparapa * lisp/essa-sas.el: ESS-elsewhere: ess-sas-submit really, really works now with ess-kermit-send 2002-01-10 Martin Maechler * lisp/ChangeLog, lisp/ess-help.el: ess-help-bogous-..buffer fix 2002-01-10 rsparapa * lisp/essa-sas.el: ESS-elsewhere: kermit transfer really works with ssh, but not telnet; YMMV 2002-01-10 rsparapa * lisp/essa-sas.el: ESS-elsewhere: ok, nearly working; more debugging of ess-kermit-get and ess-kermit-send * lisp/essa-sas.el: ESS-elsewhere: first working version that uses kermit as the transfer protocol 2002-01-09 rmh * lisp/essdsp6w.el: changed a stray sp4 to sp6 2002-01-09 rsparapa * lisp/essa-sas.el: ESS-elsewhere: debugging kermit method * lisp/essa-sas.el: ESS-elsewhere: re-defined ess-sas-submit-method to make it more useful; also re-defuned ess-sas-data-view * lisp/essa-sas.el: ESS-elsewhere: first attempt to get it to work with kermit when tramp is unavailable * lisp/essa-sas.el: ESS[SAS]: removed some debugging 2002-01-09 rmh * lisp/ess-mous.el: ess-mous keys * lisp/ess-cust.el, lisp/essd-sp4.el, lisp/essdsp6w.el, lisp/ess-site.el: splus6 for windows bug and embedded blanks in splus[46] 2002-01-08 rsparapa * lisp/essa-sas.el: ESS[SAS]: put (save-match-data) around searches in ess-sas-goto and ess-sas-data-view * lisp/essa-sas.el: ESS-elsewhere: tweaked dependencies of * lisp/essa-sas.el: ESS-elsewhere: changed dependencies from w32-dos-shell-semantics to ess-sas-submit-method; a convenient way to set ess-sas-submit-pre-command and ess-sas-submit-post-command; now using ess-microsoft-p rather than system-type as well 2002-01-08 rossini * ChangeLog: moved repository, checking CVS commit stuff. 2002-01-08 ess * lisp/essa-sas.el: ESS-elsewhere: adjusted ess-sas-submit-method, ess-sas-data-view-options, ess-sas-submit-post-command, ess-sas-submit-pre-command * lisp/essl-sas.el: ESS[SAS]: changed doc-string of sas-pre-run-hook * lisp/essl-sas.el: ESS[SAS]: changed doc-string of sas-program * lisp/essl-sas.el: ESS[SAS]: reverted default of sas-program to sas * lisp/essa-sas.el: ESS[SAS]: changed doc-string for ess-sas-tab-stop-alist * lisp/essa-sas.el: ESS[SAS]: changed doc-strings for ess-sas-goto and ess-sas-file * lisp/essa-sas.el: ESS[SAS]: 1 fix to ess-sas-file-goto; ESS-elsewhere for SAS batch is fully functional!; at least for me; YMMV * lisp/essa-sas.el: ESS[SAS]: 1 fix to ess-sas-file-path 2002-01-08 A.J. Rossini * moved repository to U Washington. 2001-08-10 ESS Maintainers * Version 5.1.19 released. 2000-10-17 ESS Maintainers * Version 5.1.18 released. 2000-10-17 A.J. Rossini * doc/ess.info, doc/ess.info-1, doc/ess.info-2, doc/ess.info-3: upgrade to 5.1.18 and rebuild doc * doc/readme.texi, doc/announc.texi: upgrade to 5.1.18 * doc/README.SPLUS4WIN, lisp/ess-cust.el: upgraded to 5.1.18 2000-10-11 maechler * lisp/ChangeLog, lisp/essl-s.el, doc/newfeat.texi: ess-smart-underscore 2000-10-10 A.J. Rossini * doc/inst_tar.texi: fixed documentation for XLispStat under windows. * doc/authors.texi: fixed Rodney's homepage pointer. * VERSION: upgrade version to 5.1.18 * doc/ess.info-1: Updating docs for new version [make dist] * ANNOUNCE, README: Updating README, ANNOUNCE for new version [make dist] * lisp/ChangeLog: small changes. This log is incomplete. * ChangeLog: updated change log. * doc/README.SPLUS4WIN, doc/ess.info, doc/ess.info-1: Misc changes * doc/inst_tar.texi: @enumerate can't have a @bullet. * doc/newfeat.texi: added 5.1.17 new features * doc/announc.texi: update for 5.1.17 * doc/README.SAS: Merged Rich's comments/changes. * doc/inst_tar.texi: added Rich H's README changes. * doc/mailing.texi: itemize the "flat text list". * doc/readme.texi: Small changes. * doc/authors.texi: added Rodney to authors list. * doc/stabilty.texi: comment re: some versions better than others. 2000-10-10 ESS Maintainers * Version 5.1.17 released. 2000-10-10 ESS Maintainers * Version 5.1.17 released. 2000-10-10 ESS Maintainers * Version 5.1.17 released. 2000-10-10 ESS Maintainers * Version 5.1.17 released. 2000-10-10 A.J. Rossini * doc/README.SPLUS4WIN, doc/ess.info, doc/ess.info-1: Misc changes * doc/inst_tar.texi: @enumerate can't have a @bullet. * doc/newfeat.texi: added 5.1.17 new features * doc/announc.texi: update for 5.1.17 * doc/README.SAS: Merged Rich's comments/changes. * doc/inst_tar.texi: added Rich H's README changes. * doc/mailing.texi: itemize the "flat text list". * doc/readme.texi: Small changes. * doc/authors.texi: added Rodney to authors list. * doc/stabilty.texi: comment re: some versions better than others. 2000-10-09 A.J. Rossini * lisp/ess-vars.el: Merged with changes in another location. 2000-10-09 maechler * lisp/ChangeLog, lisp/essl-s.el: new (ess-fix-miscellaneous) & (ess-toggle-underscore) 2000-10-08 A.J. Rossini * Makefile.in: autoconf precursor to Makefile 2000-10-07 A.J. Rossini * lisp/ess-vars.el: ess-vars is obsoleted. 2000-10-06 maechler * lisp/essl-s.el: 2 comments 2000-10-04 maechler * lisp/ChangeLog, lisp/ess-cust.el, lisp/ess-inf.el, lisp/ess-mode.el, lisp/ess-vars.el, lisp/essl-s.el: ess-S-assign and redefine "_" in ..MM-keys 2000-09-14 A.J. Rossini * lisp/ess-inf.el: ess-proc-name: need to ensure ALL concat args are strings (or at least, are not numbers). Thanks to WDMcCoy for reporting this. 2000-09-10 A.J. Rossini * DEBIAN/control, DEBIAN/md5sums, DEBIAN/postinst, DEBIAN/prerm: Copied from ESS 5.1.13 debian package * LDA/ex1.nw: Newer example * LDA/README: Initial Documentation 2000-09-05 ess * lisp/essa-sas.el: A few enhancements (ess-sleep-for/re-defining ess-sas-submit-command: see documentation) and bug-fixes for Win 95/NT. 2000-09-05 A.J. Rossini * lisp/ess-site.el: rearranged for coherency. * lisp/ess-menu.el: added C example. * lisp/ess-menu.el: 1st pass at S and XLS menus. Not integrated yet 2000-09-04 A.J. Rossini * lisp/ess-inf.el, lisp/essd-r.el, lisp/essd-sp3.el: Changes suggested by Ed Kademan * lisp/ess-inf.el: cleaning up docs and reunderstanding inferior-ess/ess-multi * lisp/ess-inf.el: comment on R handling for exit. 2000-09-03 A.J. Rossini * lisp/ess-inf.el: cleaning and correcting comments. Some ancient comments removed. * lisp/ess-comp.el: removed extraneous comments * lisp/ess-comp.el: now, the byte-compile fun is really removed. ess-message now has doc-string in "right" place. * lisp/ess-comp.el: cleaned up code. Removed extraneous comments, and the byte-compiler fun. * lisp/Makefile, lisp/ess-comp.el, lisp/ess-cust.el, lisp/ess-dump.el, lisp/ess-font-lock.el, lisp/ess-inf.el, lisp/ess-site.el, lisp/ess-vars.el, lisp/ess.el: refactoring code for cleaning, in process of debugging * lisp/19.29/README: backwards compatibility. * configure.in: merged with W3, added languages. Need to set languages. * aclocal.m4: new version from 4.0pre.46 * configure.in: somewhat complete. Needs redundant work later. * configure.in: Starting to do autoconf. Looking at W3 and R for examples. 2000-08-27 A.J. Rossini * lisp/ess-site.el: Documentation and cleaning. 2000-08-17 maechler * lisp/ChangeLog, lisp/essd-r.el: no spurious windows warning anymore 2000-08-09 maechler * lisp/ChangeLog, lisp/ess-help.el: help: inherit syntax-table ==> "h" in help : "default prompt"! 2000-07-13 A.J. Rossini * doc/newfeat.texi: set up for 5.1.15--17 * VERSION: upgraded version. * README: Updating README, ANNOUNCE for new version [make dist] * doc/ess.info-1: slightly new doc * lisp/ess-comp.el, lisp/ess-site.el: documentation and code cleanup * lisp/19.29/README: backwards compat doc 2000-07-13 ESS Maintainers * Version 5.1.16 released. 2000-06-30 ESS Maintainers * Version 5.1.14 released. 2000-06-30 A.J. Rossini * ChangeLog, VERSION, lisp/ess-inf.el, lisp/essd-arc.el, lisp/essd-vst.el: XLS fixes not quite right. No startfile if non existent * doc/ess.info-1: Updating docs for new version [make dist] * Makefile: wrong doc/docs. * Makefile: doc or docs? * ANNOUNCE, README: Updating README, ANNOUNCE for new version [make dist] * lisp/essa-sas.el, lisp/essd-els.el, lisp/essl-sas.el, lisp/essnt204.el: RMH/RS changes for SAS, ESS-elsewhere, NT Emacs 20.4 * lisp/ess-site.el: merged RMH/RS's changes for SAS. * VERSION: upgrade version * doc/README.Microsoft: not ready to generate this on the fly, yet. * doc/README.SPLUS4WIN, doc/announc.texi, doc/ess.info, doc/ess.info-1, doc/inst_tar.texi, doc/newfeat.texi, doc/readme.texi: docs updated to 5.1.14, cleaned up. * doc/newfeat.texi: added 5.1.14 stuff. * lisp/ess-cust.el: added ViSta/ARC support * lisp/ess-inf.el: added flags/checks for XLS systems. Might help for others * lisp/essd-arc.el: first version of ARC mode * lisp/Makefile: added essd-arc.el to targets. * lisp/ess-site.el: documentation. ViSta and ARC added. * lisp/essd-vst.el: now it actually might work. * lisp/ess-vars.el: added Arc, Vista. cleaned up code. a bit of documentation. 2000-06-30 maechler * etc/ess-s4.S, etc/ess-sp3.S: comments 1999-11-22 ess * VERSION, lisp/ess-vars.el: Updated to 5.1.11 1999-11-17 ess * lisp/essddr.el: 'bold isn't defined in XEmacs. Using reference-face instead of Rd-bold-face. 1999-11-16 ess * Makefile, etc/replace-version-numbers, lisp/ess-vars.el: Fixed small version update errors * ANNOUNCE, Makefile, README, doc/README.SPLUS4WIN, doc/announc.texi, doc/inst_tar.texi, doc/readme.texi, lisp/Makefile, lisp/ess-help.el, lisp/ess-site.el, lisp/essd-els.el, lisp/make-regexp.el, lisp/noweb-mode.el: updated version numbers * doc/newfeat.texi: cleaned up NTEmacs requirements. * lisp/essl-sta.el: added local variables for editing and indexing. * lisp/essl-sta.el: added Brendan's suggested function. * doc/inst_tar.texi: added change to doc, that "make" is done by "make install" * doc/ESS_intro.tex: Martin suggested a small fix. * doc/ESS_intro.tex: Another bit of documentation * doc/announc.texi: shortened header -- this is for announc, after all! * doc/announc.texi: moved license to the end, New Features to the beginning. * doc/newfeat.texi: added new features for 5.1.11. * doc/README.SPLUS4WIN: comment at the beginning about new reading material. * doc/README.SPLUS4WIN: added David Brahm's HELP INSTRUCTIONS for the license manager. * lisp/essl-sta.el: added make-regexp to ESS, and finished integrating Brendan's code. Need to test it now! * lisp/make-regexp.el: needed for Stata-mode extensions * lisp/essl-sta.el: added Brendan Halpin's corrections. * lisp/ess-inf.el: concat needs number-to-string conversion. * lisp/essd-omg.el: Omegahat fixes (for commandline flags) 1999-11-11 ess * lisp/noweb-mode.el: C-c C-n shouldn't be TeX-normalmode, since it is too close to submit-line with ESS! (overwrite). * lisp/essd-omg.el: Use prefix for setting Omegahat arguments. 1999-11-10 ess * lisp/ChangeLog: fixed up to now. * lisp/essl-omg.el: S- becomes OMG- Comments redone (to use //, ///, and //// for levels of indentation) OMG-syntax started, variable defined, needs to be fixed. * lisp/essd-omg.el: further Omegahat dialect changes (use OMG syntax, which needs fixing!) 1999-11-05 maechler * lisp/ChangeLog, lisp/ess.el, lisp/noweb-mode.el: functionp definition if necessary * lisp/noweb-mode.el: functionp for emacs-19.34 1999-11-04 ess * lisp/essd-els.el: fixed paren error. * ANNOUNCE, Makefile, README, VERSION, doc/README.SPLUS4WIN, doc/announc.texi, doc/ess.texi, doc/inst_tar.texi, doc/readme.texi, etc/replace-version-numbers, lisp/Makefile, lisp/ess-site.el, lisp/ess-vars.el, lisp/essd-sas.el: Changed version numbers * ChangeLog: 5.1.10 released. * doc/newfeat.texi: added 5.1.10 stuff. 1999-11-03 ess * doc/README.elsewhere, lisp/Makefile, lisp/ess-inf.el, lisp/ess-site.el, lisp/ess-vars.el, lisp/essd-sp5.el: Changes for ESS-elsewhere. * lisp/essd-els.el: added a generic ESS-elsewhere function. 1999-11-03 Anthony Rossini * fixed Stata again, added ESS-elsewhere. * Release 5.1.10 Tue Sep 14 17:00:19 1999 A.J. Rossini * Release 5.1.9 * added stata mode fixes, noweb/literate data analysis fixes. 1999-09-01 Martin Maechler * Finally upgraded version number to 5.1.9 (for pre-release) after fixing etc/replace-version-numbers 1999-07-23 Martin Maechler * Release 5.1.8 1999-04-05 A.J. Rossini * Makefile, doc/Makefile, doc/README.SPLUS4WIN, doc/inst_tar.texi, doc/readme.texi, doc/requires.texi, lisp/ess-site.el, lisp/ess-vars.el: text from 5.1.7 to 5.1.8 * lisp/ : -->>> lisp/ChangeLog <<<<< * ANNOUNCE, README, doc/ajr-talk.tex, doc/ess.texi, lisp/ChangeLog: doc updates * ChangeLog: *** empty log message *** * doc/README.SPLUS4WIN, doc/announc.texi, Makefile, doc/Makefile, doc/inst_tar.texi, doc/readme.texi, doc/requires.texi, lisp/ess-site.el, lisp/ess-vars.el: 5.1.6 to 5.1.7 changes for possible release * ChangeLog: more stuff. 1999-04-05 A.J. Rossini * doc/README.SPLUS4WIN, doc/announc.texi, Makefile, doc/Makefile, doc/inst_tar.texi, doc/readme.texi, doc/requires.texi, lisp/ess-site.el, lisp/ess-vars.el: 5.1.6 to 5.1.7 changes for possible release * ChangeLog: more stuff. Fri Apr 2 10:10:35 1999 A.J. Rossini * doc/getting.texi: fixed links. Wed Mar 31 14:08:39 1999 A.J. Rossini * Makefile (ESSVERSION): updated * Makefile (ESSVERSIONMSDOS): updated * Makefile (ESSVERSIONTAG): new variable, use it. * Makefile (dist): fixed to export both zip and gzip files. 1999-03-17 A.J. Rossini * ANNOUNCE, README, doc/Makefile, doc/README.SPLUS4WIN, doc/announc.texi, doc/inst_tar.texi, doc/readme.texi, doc/requires.texi: version number update * lisp/essd-r.el, Makefile, doc/README.Microsoft, doc/README.SPLUS4COMMAND, lisp/ess-site.el, lisp/ess-vars.el: RMH's changes 1999-03-17 maechler * doc/README: README explaining a bit about ./doc/ directory 1999-03-16 A.J. Rossini * Makefile: *** empty log message *** * Makefile: for dist target, use export, not co. * lisp/essd-r32-sh-dos.el, lisp/essd-sp4com.el: MS Dos stuff for R, S+4.x * ChangeLog, Makefile, doc/announc.texi, doc/inst_tar.texi, doc/readme.texi, doc/requires.texi, lisp/ChangeLog: Prep for 5.1.4 * lisp/essd-sp4.el, lisp/ess-iw32.el: RMH changes. * doc/README.SPLUS4COMMAND: New file * doc/README.SPLUS4WIN: added RMH's mods. * lisp/ess-site.el: Merged RMH's work. * lisp/ess-vars.el: incremented. * lisp/ess-inf.el: RMH's changes. 1999-03-16 maechler * lisp/ChangeLog: mini change "foobar.Sout-45" * lisp/ess-site.el: auto-mode-alist: "foobar.Sout-4.5" also turns on S-transcript-mode 1999-03-16 A.J. Rossini * lisp/essd-sp4.el, lisp/ess-iw32.el: RMH changes. * doc/README.SPLUS4COMMAND: New file * doc/README.SPLUS4WIN: added RMH's mods. * lisp/ess-site.el: Merged RMH's work. * lisp/ess-vars.el: incremented. * lisp/ess-inf.el: RMH's changes. 1999-03-16 maechler * lisp/ChangeLog: mini change "foobar.Sout-45" * lisp/ess-site.el: auto-mode-alist: "foobar.Sout-4.5" also turns on S-transcript-mode 1999-03-15 A.J. Rossini * lisp/ess-vars.el: RMH - 15Mar1999. Added inferior-S+4-editor-pager-command. * lisp/essd-r32.el: 15Mar1999 version. * lisp/essd-r.el: added `R-microsoft', which is the "right-thing" to do under Microsoft Windows 32-bit platforms. Need to merge this with `R'. 1999-03-09 maechler * lisp/ess-help.el: add `inferior-ess-help-command' to doc string 1999-03-08 A.J. Rossini * lisp/ess-inf.el: add stata to deal with input properly. 1999-03-05 A.J. Rossini * ANNOUNCE, ChangeLog, Makefile, README: top level stuff, sigh! * doc/announc.texi, doc/authors.texi, doc/bugs.texi, doc/inst_tar.texi, doc/requires.texi: Cleaned up text. * doc/requires.texi: cleaned/formatted up requirements * doc/currfeat.texi: pretty-printing. * lisp/essd-sta.el: new command for help: turn off more, and continue. * lisp/ess-help.el: stata hates ess-nuke-help-bs, since it (stata) is clean. * lisp/ess-inf.el: fixed command sender for stata. more like R than like XLS. * lisp/essl-sta.el: more help file corrections. * lisp/ess-inf.el: STA same as XLS/SAS. * lisp/essd-sta.el: ess-*-lastvalue-command needed to be fixed! * lisp/essl-sta.el: stat help regex is evil * lisp/essl-sta.el: whitespace cleanup. * lisp/essl-sta.el: double var defs. whoops! * lisp/essl-sta.el (ess-help-STA-sec-regex): fixed section header grabbing. * lisp/essd-sta.el: need to manually turn off paging, I think... * lisp/essl-sta.el: help section regex not quite right. * lisp/ess-help.el: Stata is like XLS and SAS wrt help. * lisp/essd-sta.el: fixed help facility. * lisp/essl-sta.el: added help section regexes * lisp/essd-sta.el: make description "same as" objects. * lisp/essd-sta.el: secondary prompt identical to primary prompt. * lisp/essd-sta.el: redid help so that no paging is present. * doc/ess.texi: cleared up the bug report section. * doc/bugrept.texi: combined multiple sources (ess.texi and README). * doc/credits.texi: moved content from ess.texi here, for piecemeal editing and reuse. * doc/ess.texi: added placeholders for README.OS files and README.StatPackage files, to be migrated here. * doc/announc.texi, doc/authors.texi, doc/bugrept.texi, doc/currfeat.texi, doc/getting.texi, doc/inst_cvs.texi, doc/inst_tar.texi, doc/license.texi, doc/mailing.texi, doc/newfeat.texi, doc/readme.texi, doc/requires.texi, doc/stabilty.texi: Migrating all documentation into texinfo format, including ../README and ../ANNOUNCE * doc/ess.texi: removed README, cleaning out duplicate texinfo code. * doc/ess.texi: moved README text into sub-texinfo files. (to be called by readme.texi and announc.texi for documentation construction). 1999-03-05 A.J. Rossini * doc/announc.texi, doc/authors.texi, doc/bugs.texi, doc/inst_tar.texi, doc/requires.texi: Cleaned up text. * doc/requires.texi: cleaned/formatted up requirements * doc/currfeat.texi: pretty-printing. * lisp/essd-sta.el: new command for help: turn off more, and continue. * lisp/ess-help.el: stata hates ess-nuke-help-bs, since it (stata) is clean. * lisp/ess-inf.el: fixed command sender for stata. more like R than like XLS. * lisp/essl-sta.el: more help file corrections. * lisp/ess-inf.el: STA same as XLS/SAS. * lisp/essd-sta.el: ess-*-lastvalue-command needed to be fixed! * lisp/essl-sta.el: stat help regex is evil * lisp/essl-sta.el: whitespace cleanup. * lisp/essl-sta.el: double var defs. whoops! * lisp/essl-sta.el (ess-help-STA-sec-regex): fixed section header grabbing. * lisp/essd-sta.el: need to manually turn off paging, I think... * lisp/essl-sta.el: help section regex not quite right. * lisp/ess-help.el: Stata is like XLS and SAS wrt help. * lisp/essd-sta.el: fixed help facility. * lisp/essl-sta.el: added help section regexes * lisp/essd-sta.el: make description "same as" objects. * lisp/essd-sta.el: secondary prompt identical to primary prompt. * lisp/essd-sta.el: redid help so that no paging is present. * doc/ess.texi: cleared up the bug report section. * doc/bugrept.texi: combined multiple sources (ess.texi and README). * doc/credits.texi: moved content from ess.texi here, for piecemeal editing and reuse. * doc/ess.texi: added placeholders for README.OS files and README.StatPackage files, to be migrated here. * doc/announc.texi, doc/authors.texi, doc/bugrept.texi, doc/currfeat.texi, doc/getting.texi, doc/inst_cvs.texi, doc/inst_tar.texi, doc/license.texi, doc/mailing.texi, doc/newfeat.texi, doc/readme.texi, doc/requires.texi, doc/stabilty.texi: Migrating all documentation into texinfo format, including ../README and ../ANNOUNCE * doc/ess.texi: removed README, cleaning out duplicate texinfo code. * doc/ess.texi: moved README text into sub-texinfo files. (to be called by readme.texi and announc.texi for documentation construction). 1999-03-04 A.J. Rossini * lisp/essd-sta.el: let stata have command line options just like R. * lisp/essd-sta.el: by default, provide login screen just like splus/r do. * lisp/essd-sta.el: fixed help. * lisp/essd-sta.el: added stata's prompt * lisp/ess-vars.el: added inferior stata program variable. * lisp/essd-sta.el: spelling error, nil -> 'nil. * lisp/essl-sta.el: reversed variable alist ordering. * lisp/essd-sta.el: commented out ESS-help for Stata, for compiling, initial testing. * lisp/essl-sta.el: added STA-syntax-table, but it's wrong (for Splus). * lisp/essl-sta.el: moved STA-editing-alist to beginning. * lisp/essl-sta.el: added an STA-editing-alist variable, BUT it looks like Splus, :-(. Needs to be edited a bit! * doc/ess.texi: included README in texinfo file. Now, need to extract README from it. * lisp/essd-s_2b4.el: RMH's patches, Mar 3 1999 * lisp/essd-sp4.el: updated using RMH's patches. 1999-03-03 A.J. Rossini * lisp/ChangeLog: updated lisp directory changelog. * ChangeLog: updated changelog file. * lisp/Makefile: updated version information converted s+3 to sp3. * lisp/ess-vars.el: updated version information. * doc/README.Microsoft: Added ess-bugs.cmts to this file. * lisp/ess-iw32-load-file.el, lisp/essd-s+3.el, lisp/essd-s+4.el, lisp/essd-s+5.el, lisp/essd-s_2b4-msdos-existing.el, lisp/essd-s_2b4-msdos.el: Tidied up ess-iw32*.el files. * lisp/ess-iw32.el: copied all changes from ess-iw32-load-file.el here. * lisp/ess-iw32-load-file.el: fixed. * doc/README.Microsoft: Combination of 2 of RMH's text/help files. * lisp/essd-s_2b4.el: essd-s_2b4-msdos*.el were not needed. Contents moved into base file. * doc/README.SPLUS4WIN: Changed history of Splus 4.5 stuff; added new information for using Splus 4.5 and R under Windows NT. * doc/TODO: moved from mailbox to TODO list. * lisp/ess-iw32-load-file.el, lisp/ess-iw32.el, lisp/essd-r32.el, lisp/essd-s_2b4-msdos-existing.el, lisp/essd-s_2b4-msdos.el, lisp/essd-s_2b4.el, lisp/msdos.el: RMH's changes, up to March 2nd 1999-03-03 A.J. Rossini * lisp/Makefile: updated version information converted s+3 to sp3. * lisp/ess-vars.el: updated version information. * doc/README.Microsoft: Added ess-bugs.cmts to this file. * lisp/ess-iw32-load-file.el, lisp/essd-s+3.el, lisp/essd-s+4.el, lisp/essd-s+5.el, lisp/essd-s_2b4-msdos-existing.el, lisp/essd-s_2b4-msdos.el: Tidied up ess-iw32*.el files. * lisp/ess-iw32.el: copied all changes from ess-iw32-load-file.el here. * lisp/ess-iw32-load-file.el: fixed. * doc/README.Microsoft: Combination of 2 of RMH's text/help files. * lisp/essd-s_2b4.el: essd-s_2b4-msdos*.el were not needed. Contents moved into base file. * doc/README.SPLUS4WIN: Changed history of Splus 4.5 stuff; added new information for using Splus 4.5 and R under Windows NT. * doc/TODO: moved from mailbox to TODO list. * lisp/ess-iw32-load-file.el, lisp/ess-iw32.el, lisp/essd-r32.el, lisp/essd-s_2b4-msdos-existing.el, lisp/essd-s_2b4-msdos.el, lisp/essd-s_2b4.el, lisp/msdos.el: RMH's changes, up to March 2nd 1999-02-24 A.J. Rossini * lisp/ess-iw32.el: temp val left in distribution. whoops (RMH). 1999-02-22 A.J. Rossini * lisp/essd-els.el, lisp/essd-s3.el, lisp/essd-s4.el, lisp/essd-sta.el, lisp/ess-site.el, lisp/essd-sp4.el, lisp/essd-sp5.el, lisp/essd-sp3.el: Removed s+# to sp# for S-PLUS commands 1999-02-12 Martin Maechler * lisp/Makefile: emacs, not "19.34" 1999-02-11 Martin Maechler * doc/README.SPLUS4WIN: added pointer to NTEmacs. * README, ANNOUNCE: corrected documentation for R, added pointer to NTEmacs 1999-02-10 Martin Maechler * etc/other/Tags/Lubinsky-S-tags/desc: reformatted material. * README: set up for 5.1.2 release * Makefile: Set up for 5.1.2 release * ANNOUNCE: set up for 5.1.2 release * doc/rmh-essi121098-msw32.tex: rmh-essi121098-msw32.tex is obsolete. * lisp/essd-sas.el: added RMH's new fixes for the 5.1.2 version. * doc/README.S: RMH's documentation additions for Splus 4.5 * doc/README.SAS: RMH's doc additions for 5.1.2 * doc/README.SPLUS4WIN: Includes RMH's changes for Splus 4.5 documentation * etc/other/Tags/README: cleaned text. * ANNOUNCE, README: updating for 5.1.2 1999-02-02 Martin Maechler * lisp/ess-inf.el: (last commit was with unsaved file) * lisp/ChangeLog, lisp/ess-inf.el: fix regex for "help(..);" also work for "?" with R-input-sender 1999-01-13 Martin Maechler * lisp/Makefile: added ess-debug essd-s+4 ess-iw32 * lisp/ess-iw32.el: RMH`s workaround for ess-inf.el ess-setq-values-default (instead of ..-local) 1999-01-12 Martin Maechler * lisp/ess-inf.el: still "-default", not "local" * lisp/ess-inf.el, lisp/ess.el: more dribble output * lisp/ess.el: add dribble-info about comint-process-echoes 1999-01-11 Martin Maechler * lisp/ess-site.el: minor comments only * lisp/essd-sq4.el: removed [RMH] * lisp/ess-site.el: RMH changes (Dec 28) * lisp/ess-trns.el: RMH added some ess-inf..-prompt.. * lisp/ess-vars.el: RMH added S+4 & dde (& removed some "ess-external") * lisp/essd-els.el: RMH added S+elsewhere-mode * lisp/ess-iw32.el, lisp/essd-s+4.el: new from Rich Dec 28 * lisp/ess-inf.el: 2 lines for S+4 1999-01-04 Martin Maechler * lisp/essddr.el: R CMD Rd2txt 1998-12-18 A.J. Rossini * ANNOUNCE, README: Updating Announce/Readme. Need to merge announce to readme, and just subset out the relevant section for Announce. 1998-12-17 Kurt Hornik * lisp/ess-vars.el: Match R `require(' in ess-change-sp-regexp. * lisp/Makefile: Add `essd-els.el' to SOURCES. 1998-12-16 Martin Maechler * ChangeLog: ess.texi * doc/ess.texi: 5.0 -> 5.1.x * doc/ess.texi: MM: (CVS) Date also for info * doc/ess.texi: MM: (CVS) Date added * doc/ess.texi: added '$Date: 2004/07/08 15:03:06 $'; 5.0 -> 5.1.x Mon Dec 14 20:23:55 1998 A.J. Rossini * README: added 5.1.x comments, updated to current state of affairs. * etc/other/Tags/README: stuff for emacs text mode for editing. * etc/other/Tags/README: Information on tagging for Emacs/VI and ESS. * etc/other/Tags/Lubinsky-S-tags/README, etc/other/Tags/Lubinsky-S-tags/desc, etc/other/Tags/Lubinsky-S-tags/etags.c: Modifications to gnu tag programs for S * lisp/ess-mode.el: fixed copyright and header information * lisp/ess-site.el: commented out SHOME definition. Fri Dec 11 19:51:18 1998 A.J. Rossini * lisp/ess-vars.el: fixed copyright, rossini's email address. * lisp/ess-iw32.el: fixed rossini's email address, headers, copyright. * lisp/essd-els.el, lisp/essd-s+4.el: fixed rossini's email address. * lisp/essd-sq4.el: fixed copyright and header attributions. * lisp/essd-els.el: fixed header files and copyright. * lisp/essd-s+4.el: added changes to copyright and header docs. * etc/other/S-spread/gradexmp.s, etc/other/S-spread/sprd-emc.s, etc/other/S-spread/sprd-grd.s, etc/other/S-spread/sprd-int.el, etc/other/S-spread/sprd-spr.s, etc/other/S-spread/sprd-txt.s, etc/other/S-spread/sprd3d.how, etc/other/S-spread/README, etc/other/S-spread/S-spread.el, etc/other/S-spread/asaprc.ps: RMH's S-spread, Oct 1997 version * doc/rmh-essi121098-msw32.tex: Adding Rich's documentation for Windows stuff. * lisp/ess-vars.el: Merged RMH's changes. * lisp/ess-iw32.el, lisp/essd-els.el, lisp/essd-s+4.el, lisp/essd-sq4.el: New files for ESS for Splus/MSW/NT/98/95 New files for remote-ESS on Unix. * lisp/ess-site.el: Added RMH's changes for Microsoft Windows and Splus. Mon Nov 30 17:37:57 1998 Kurt Hornik * lisp/Makefile: Add essd-s+5.el to SOURCES (as it gets required in ess-site). Mon Nov 23 20:03:17 1998 A.J. Rossini * lisp/ChangeLog: *** empty log message *** Fri Nov 20 20:57:33 1998 A.J. Rossini * lisp/ess-vars.el: ess-help-w3-url-prefix points to pyrite. * lisp/ess-vars.el: removed spurious comment about generic function, in front of a variable. * lisp/essd-s+5.el: trimmed out old S4 stuff. Mon Nov 16 17:29:25 1998 Martin Maechler * lisp/ess-inf.el: do not need comint echo anymore.. Sat Nov 14 00:23:19 1998 A.J. Rossini * Makefile, lisp/ChangeLog, ChangeLog: whitespace editing. * doc/Makefile: added info target. removed spurious ess.info/ess.texi target. Fri Nov 13 23:47:27 1998 A.J. Rossini * Makefile: added comment re: export vs checkout for "dist" target. * lisp/ess-site.el: added sample entry for S+5. * lisp/ChangeLog: *** empty log message *** * lisp/ess-site.el: added suffix for StatSci's script files. Thu Nov 12 17:27:30 1998 Martin Maechler * lisp/essd-r.el, lisp/essd-s+3.el, lisp/essd-s+5.el, lisp/essd-s3.el: newline in dribble buff * lisp/ess-inf.el: more details in prompt for ess-get-dir; more dribble; WHITE SPACE * lisp/ess.el: slightly better dribble output * lisp/essd-s4.el: drop doubled comments * lisp/ess-vars.el: . Wed Nov 11 15:54:34 1998 Martin Maechler * Makefile: -X CVS * lisp/essd-s+5.el: omit .Smode() extras; new "S+" instead of "S+3" * lisp/essl-s.el: new "S+" instead of "S+3" * lisp/ess-inf.el: comint-echo : OFF for S+5 * lisp/essd-s3.el: comments only * lisp/essd-s+3.el: comment out ess-mode-edit * lisp/Makefile, lisp/ess-vars.el: new version numbers * lisp/essd-s+5.el: several more s4 -> s+5 changes; still not ok * lisp/essd-s+3.el: transpose to defs * lisp/ess-vars.el: require s+5 Tue Nov 10 17:45:11 1998 Martin Maechler * lisp/ess-site.el: s+5 is now distributed * lisp/essd-s+5.el: provide typo fixed Mon Nov 9 23:50:26 1998 A.J. Rossini * ChangeLog: *** empty log message *** * Makefile: uses scp to put the tar file where it belongs. * Makefile, lisp/ChangeLog, lisp/Makefile, lisp/ess-site.el: New material for Makefiles * lisp/essl-sta.el: removed possible problems from stata mode. * ChangeLog: *** empty log message *** * Makefile: added new top-level dist target. * lisp/essd-s+5.el: This is for Splus5, based on S4. * lisp/ess-web.nw: last change, sigh. * lisp/ess-web.nw: emacs lisp mode is wrong, sigh. * lisp/ess-web.nw: Contains interface code between Noweb and ESS * lisp/ChangeLog: added stata-dialect/lang to makefile * lisp/Makefile: added Stata stuff. Thu Sep 24 23:32:14 1998 A.J. Rossini * lisp/ChangeLog: more stuff. * lisp/essd-sta.el: should be sta, not stt * lisp/ChangeLog: update for ess-site. * lisp/ess-site.el: added stata mode, which is now STA (ref: Thomas Lumley) Thu Sep 17 09:11:51 1998 Martin Maechler * lisp/ChangeLog, lisp/ess-utils.el: several small things Fri Sep 11 14:25:59 1998 Martin Maechler * lisp/ChangeLog: . * lisp/Makefile, lisp/ess-inf.el, lisp/ess-mode.el, lisp/ess-utils.el, lisp/ess.el: Adaptions to new ess-utils * lisp/essl-s.el: LOTS in "pretty edit source" * lisp/essd-r.el: new function (R-fix-T-F) Thu Sep 10 06:15:55 1998 Kurt Hornik * lisp/essddr.el: Change old `ess-doc' to `essddr'. Expand Rd-mode-abbrev-table (abbrevs). Change Rd-indent-level default to 4. Add a preliminary Rd-mode menu. Add a preliminary Rd-submit-bug-report(). * lisp/ess-vars.el: Change ess-mode-font-lock-keyword so that assignment function declarations are also fontified correctly (hopefully ...). * doc/Makefile: Get rid of old LISPDIR code. * Makefile: Use `$(MAKE)' instead of `make'. Wed Sep 9 23:49:12 1998 A.J. Rossini * lisp/ChangeLog: new stuff. * lisp/essd-sta.el: modified for stata commands. What is quit? * lisp/essl-sta.el: Small mods. * lisp/essd-sta.el: Added first pass at a stata file. * lisp/Makefile: BATCHFLAGS should be --no-init-file, not --no-init-fil Wed Sep 9 08:45:26 1998 Martin Maechler * lisp/essl-s.el: minor (save-recursion..) -- Committing from Shell to see permissions Tue Sep 8 21:18:33 1998 Martin Maechler * lisp/essl-s.el: more things for (ess-dump-to-src), (ess-fix-comments),.... ess-MM-fix-src * lisp/ess-mode.el: add optional quiet argument to (set-ess-style) * lisp/ess-mode.el: only white space * lisp/ChangeLog: .. * lisp/essl-s.el: added "&optional dont-ask" argument to ess-dump-to-src, ess-fix-comments,.... ess-MM-fix-src Mon Sep 7 16:27:37 1998 Martin Maechler * lisp/ChangeLog: .. * lisp/essl-s.el: 4 digit year in ess-time-string! * doc/README.SAS: Added paragraph about ess-sas-sh / PATH problems at very end -- for RMH Wed Aug 26 12:18:54 1998 Martin Maechler * lisp/ChangeLog, lisp/essl-s.el: font-lock: "." as word constituent Mon Aug 24 12:50:45 1998 Martin Maechler * ANNOUNCE, README, doc/ess.texi: stat.ethz short for www.stat.math.ethz Thu Aug 20 06:48:48 1998 Martin Maechler * lisp/ChangeLog: .. * lisp/essddr.el: Expanded Rd-section-names and Rd-keywords [following Kurt's suggestion] Tue Aug 18 08:44:54 1998 Martin Maechler * lisp/essd-s+3.el, lisp/essd-r.el, lisp/ChangeLog: "--no-readline" for R; S+3-dialect-name for S-plus Fri Aug 14 16:32:23 1998 Martin Maechler * lisp/ess-vars.el, lisp/Makefile: calling new version "pre5.1" * lisp/essl-s.el: "ease:" replaced by "ess-"; fixed some comments Mon Apr 27 07:53:02 1998 Martin Maechler * lisp/essl-s.el: improved ess-num-var-round Fri Apr 17 12:29:46 1998 Martin Maechler * lisp/essd-sas.el: ../etc/ is place for sas-sh-command * etc/function-outline.S, lisp/essl-s.el: function-outline-file now in ../etc/ * Makefile, doc/Makefile, lisp/Makefile: Makefiles separated; new for ./doc Mon Apr 6 20:35:04 1998 A.J. Rossini * lisp/ChangeLog: Storing updates. * lisp/ess-comp.el, lisp/ess-inf.el, lisp/ess-site.el, lisp/ess-vars.el: See ChangeLog for more details. Not tagged. Tue Dec 16 00:17:44 1997 A.J. Rossini * lisp/ChangeLog: *** empty log message *** * lisp/essd-s4.el (S4-mode): New function, use it. Wed Dec 10 15:36:29 1997 A.J. Rossini * lisp/ChangeLog, lisp/essd-xls.el: XLS-mode is now the mode-name symbol. (instead of ess-mode). This is required for noweb-mode to work nicely. ChangeLog documented to reflect this fact. Tue Dec 9 22:55:40 1997 A.J. Rossini * lisp/ChangeLog: *** empty log message *** * lisp/essd-r.el: removed non-necessary autoload for a non-existent function (was intended for start-args, but never was written or used). * lisp/essl-sta.el: Changed essl-sta.el to not use stat.el in the documentation comments. * lisp/ChangeLog: *** empty log message *** * lisp/essddr.el: one too many parens. * lisp/essddr.el: added commented out face. DB's error doesn't exist for me, though. Fri Dec 5 15:13:59 1997 A.J. Rossini * lisp/ChangeLog: *** empty log message *** * lisp/ChangeLog: ChangeLog file install * lisp/ess-site.el: added comments about Emacs 20.2 errors. Fri Dec 5 14:46:38 1997 ess * Makefile: Added top-level Makefile. Needs definitions, though. * etc/ess-s+3.S, etc/ess-s4.S: Initial revision 1998-12-14 A.J. Rossini * README : updated to 5.1.x Tue Dec 2 08:49:07 1997 Anthony Rossini * Makefile: info isn't a valid target, and cleaned up doc targets. (KH). Mon Dec 1 16:55:17 1997 Anthony Rossini * ess.el: removed blank lines. Mon Dec 1 16:51:46 1997 Anthony Rossini * ess.texi: small edit. Mon Dec 1 16:48:14 1997 Anthony Rossini * ess.texi: changed wording around ess-plain-first-buffername (RMH). Mon Dec 1 16:42:47 1997 Anthony Rossini * Makefile: new branch (5.1.1.1). Mon Dec 1 16:36:13 1997 Anthony Rossini * Makefile: Batchflags are user serviceable. Mon Dec 1 10:59:29 1997 Anthony Rossini * RELEASED: version 5.0. Mon Dec 1 10:45:55 1997 Anthony Rossini * README.SAS: added noise about ess-sas-sh-command stupidity that AJR has personally experienced. Sun Nov 30 13:44:55 1997 Anthony Rossini * Makefile: comments for indexing. Sun Nov 30 13:41:00 1997 Anthony Rossini * ess.texi: more fixes. Many more to go. Sun Nov 30 12:38:26 1997 Anthony Rossini * README.SAS: added more information. Sun Nov 30 12:15:19 1997 Anthony Rossini * essl-lsp.el: small typo in comments. Sun Nov 30 12:14:33 1997 Anthony Rossini * Makefile: added revision, added other changes. Sun Nov 30 12:12:26 1997 Anthony Rossini * README.SAS: new material on autoexec.sas added. Sun Nov 30 12:09:30 1997 Anthony Rossini * essl-s.el (S-editing-alist): need indent-line-function defined. (RMH). Sun Nov 30 12:08:24 1997 Anthony Rossini * essl-sas.el: removed sas-indent-region. Sun Nov 30 12:07:05 1997 Anthony Rossini * essl-sas.el (SAS-editing-alist): need indent-line-function (RMH). Sun Nov 30 12:06:00 1997 Anthony Rossini * ess-mode.el (ess-mode): fixed doc string. (RMH). Sun Nov 30 12:03:34 1997 Anthony Rossini * essd-sas.el: useless comments removed. Sun Nov 30 12:03:10 1997 Anthony Rossini * essd-sas.el: useless comments removed. (RMH). Sun Nov 30 12:02:58 1997 Anthony Rossini * essd-sas.el (inferior-SAS-args-temp): docstring, explaining stupidity of this variable Sun Nov 30 12:00:24 1997 Anthony Rossini * ess-sas-sh-command: better shell scripting (RMH). Wed Nov 26 16:33:10 1997 Anthony Rossini * RELEASED: 5.0-gettingcloser. Wed Nov 26 16:10:02 1997 Anthony Rossini * Makefile (dist): do the right thing w/ README. Wed Nov 26 16:05:20 1997 Anthony Rossini * ess-sas-sh-command: more information. cleaned up for current essd-sas.el arg passing. Wed Nov 26 15:51:04 1997 Anthony Rossini * essd-sas.el: modified args to try to have "one set" for SAS process (2nd is for redirect). Wed Nov 26 15:43:10 1997 Anthony Rossini * essd-sas.el: renamed and reordered inferior-SAS-args... Wed Nov 26 14:29:40 1997 Anthony Rossini * ess-sas-sh-command: added more documentation on I/O. Wed Nov 26 14:01:23 1997 Anthony Rossini * ess-inf.el: cleaned up comments. Wed Nov 26 13:58:42 1997 Anthony Rossini * ess-sas-sh-command: cleaned up comments. Wed Nov 26 11:01:36 1997 Anthony Rossini * essddr.el: switch-to-S to switch-to-ESS. Wed Nov 26 11:01:07 1997 Anthony Rossini * essddr.el (Rd-mode-map): switch-to-S is now switch-to-ESS. Wed Nov 26 11:00:06 1997 Anthony Rossini * ess-mode.el (ess-mode): added "indent-region" binding to doc-string. Wed Nov 26 10:52:11 1997 Anthony Rossini * ess-trns.el (ess-transcript-mode-map): added 2 lines for consistency. (RMH) Wed Nov 26 10:51:29 1997 Anthony Rossini * ess-trns.el: ispell-checked. File name / header name mismatch corrected. (AJR) Wed Nov 26 10:49:58 1997 Anthony Rossini * ess-inf.el: ispell checked, typos fixed (RMH/AJR). Wed Nov 26 10:42:58 1997 Anthony Rossini * essl-sas.el (SAS-editing-alist): function definitions are useless. Remove. Wed Nov 26 10:37:44 1997 Anthony Rossini * essl-s.el (S-editing-alist): removed function definitions. They don't work. Wed Nov 26 10:29:00 1997 Anthony Rossini * ess-site.el: ispell-checked (AJR/RMH) Tue Nov 25 15:37:37 1997 Anthony Rossini * Doc/TODO: Real dump suggested programming fix. * README.S: Real dump user correction. Tue Nov 25 15:37:00 1997 Anthony Rossini * README.S : Real Dump user correction Tue Nov 25 13:06:38 1997 Anthony Rossini * ess-inf.el (inferior-ess-mode): Make sure that silly moves like "ess-dialect=S" are not cause for a bailout. (AJR). Tue Nov 25 12:38:21 1997 Anthony Rossini * README.S: changes for font-lock "Dump" problem. (RMH) Tue Nov 25 12:36:48 1997 Anthony Rossini * Makefile: chmod 444 ess.info* ess.dvi on release (RMH) Tue Nov 25 08:53:54 1997 Anthony Rossini * RELEASED: 5.0-honestlylastpre. * README.S: added comment re: \" and fontlock. Tue Nov 25 08:50:56 1997 Anthony Rossini * Doc/TODO: removed SAS tabbing, added S dumping (RMH). Tue Nov 25 08:49:18 1997 Anthony Rossini * essd-sas.el (SAS-mode): construct a sas-mode-local-map, from ess-mode-map, for modifying the tab key. Tue Nov 25 08:24:42 1997 Anthony Rossini * ess-mode.el (ess-mode): removed white space, spurious comment. Mon Nov 24 12:14:38 1997 Anthony Rossini * Doc/TODO: SAS indent fixes. Mon Nov 24 11:33:00 1997 Anthony Rossini * README: fixed Kurt's address. Mon Nov 24 11:32:13 1997 Anthony Rossini * ess-mode.el: put back functions; see 10:48 change. Mon Nov 24 10:58:12 1997 Anthony Rossini * essl-s.el: ess to S. Mon Nov 24 10:50:51 1997 Anthony Rossini * essl-s.el: inadvertent placement of ess-indent-line function. Mon Nov 24 10:50:19 1997 Anthony Rossini * essl-s.el (S-editing-alist): inadvertent placement of indent-line-function. Mon Nov 24 10:48:19 1997 Anthony Rossini * ess-mode.el: commented out some language specific functions. Moved to essl-s.el Mon Nov 24 10:45:21 1997 Anthony Rossini * essl-s.el: new functions; S for ESS. Use them. Mon Nov 24 10:43:36 1997 Anthony Rossini * essl-s.el (S-comment-indent): * essl-s.el (S-indent-line): * essl-s.el (S-calculate-indent): new functions; used to be ess-*. Mon Nov 24 10:39:41 1997 Anthony Rossini * essl-sas.el: removed some lisp-isms. Mon Nov 24 10:36:48 1997 Anthony Rossini * essl-sas.el (sas-indent-region): New function. Use it. Mon Nov 24 10:25:07 1997 Anthony Rossini * essd-s4.el (S4-customize-alist): ess-object-name-db-file is "ess-s4-namedb.el". (RMH) Mon Nov 24 10:18:42 1997 Anthony Rossini * README.SAS: 2 typos (RMH). Mon Nov 24 10:17:46 1997 Anthony Rossini * ess-mode.el: added ess-quit autoload. Mon Nov 24 10:16:40 1997 Anthony Rossini * ess-inf.el (ess-quit): since now possible to call from ess-mode, make sure that we are connected to a process. Mon Nov 24 10:01:33 1997 Anthony Rossini * ess-vars.el (ess-mode-font-lock-keywords): finish off line. Mon Nov 24 09:59:39 1997 Anthony Rossini * Doc/TODO: quotes need fixing (RMH). Mon Nov 24 09:55:43 1997 Anthony Rossini * ess-mode.el (ess-mode-map): added ess-quit. (RMH). Mon Nov 24 09:48:15 1997 Anthony Rossini * essd-sas.el (SAS-customize-alist): inferior-ess-exit-command should be `endsas;\n'. (RMH). Sat Nov 22 19:16:40 1997 Anthony Rossini * Doc/README-19.28: new version of file (RMH). Fri Nov 21 17:37:26 1997 Anthony Rossini * Doc/TODO: added 2 more from RMH, with comments. Fri Nov 21 17:31:50 1997 Anthony Rossini * ess-site.el: fixed comments to reflect reality (RMH). Fri Nov 21 17:05:05 1997 Anthony Rossini * ess-trns.el: ess-mode -> ESS. (RMH) ess-mode-map -> ess-transcript-mode-map Fri Nov 21 17:02:45 1997 Anthony Rossini * Makefile (DISTSCRIPTS): commented out. (RMH) * Makefile (dist-doc): commented out. Will do by hand for 5.0. (RMH) * Makefile: Added comments for structure of Makefile. (RMH) Fri Nov 21 10:26:53 1997 Anthony Rossini * Doc/TODO: incr version. Fri Nov 21 10:26:25 1997 Anthony Rossini * Doc/TODO: added dir directions for info. Fri Nov 21 10:22:17 1997 Anthony Rossini * Doc/rmh-talk.tex: removed trailing \\. Fri Nov 21 10:19:50 1997 Anthony Rossini * Makefile (dist): ess.dvi and ess.info need to be up to date. Thu Nov 20 18:38:51 1997 Anthony Rossini * essl-sta.el: * essl-sas.el: * essl-s.el: * essl-lsp.el: * essddr.el: * essd-xls.el: * essd-vst.el: * essd-sas.el: * essd-s4.el: * essd-s3.el: * essd-s+3.el: incr version. * essd-r.el: incr version, comments. * ess.texi: small edits, incr version * ess.el: ess-mode is ESS. incr version * ess-vars.el: incr version, added comments. Thu Nov 20 18:21:01 1997 Anthony Rossini * ess-site.el: part of ESS; comments. Thu Nov 20 18:20:12 1997 Anthony Rossini * Makefile: incr, edits. Thu Nov 20 18:19:24 1997 Anthony Rossini * Makefile: errors. Thu Nov 20 18:17:13 1997 Anthony Rossini * COPYING: trying. Thu Nov 20 18:15:01 1997 Anthony Rossini * ess-trns.el: added copyright, incr version. Thu Nov 20 18:12:06 1997 Anthony Rossini * ess-mode.el: edited copyright. incr version. Thu Nov 20 18:11:02 1997 Anthony Rossini * README: removed silly university locations. incr version. Thu Nov 20 18:09:00 1997 Anthony Rossini * ess-inf.el: added copyright, edited comments, incr version. Thu Nov 20 18:07:51 1997 Anthony Rossini * ess-help.el: edited comments, incr version. Thu Nov 20 18:03:09 1997 Anthony Rossini * ess-debug.el: edit, end, upgraded version. Thu Nov 20 18:00:55 1997 Anthony Rossini * ess-comp.el: removed log file, edited comments, upgrade to 4. Thu Nov 20 16:41:51 1997 Anthony Rossini * RELEASED: 5.0-verylastpre. * ess-inf.el: fixed menus. Thu Nov 20 16:40:29 1997 Anthony Rossini * ess-trns.el: fixed menus. Thu Nov 20 16:38:35 1997 Anthony Rossini * ess-mode.el: formatting. extra ). Thu Nov 20 16:37:23 1997 Anthony Rossini * ess-mode.el: cleaned up menus. removed useless comments. Thu Nov 20 16:29:15 1997 Anthony Rossini * ess-mode.el: fixed goto-info stuff. Thu Nov 20 16:13:43 1997 Anthony Rossini * ess-help.el (ess-goto-info): ess isn't ess-mode. Split window, not other-window. Thu Nov 20 10:04:28 1997 Anthony Rossini * README: added comments on help file editing. Thu Nov 20 10:01:47 1997 Anthony Rossini * Doc/TODO: added inferior-ess rewrite. Thu Nov 20 09:54:51 1997 Anthony Rossini * README.XLispStat: Splus removed, XLispStat added. Thu Nov 20 09:53:48 1997 Anthony Rossini * README.S: retitled the FAQ. Thu Nov 20 09:52:57 1997 Anthony Rossini * README: changes (RMH). Thu Nov 20 09:46:20 1997 Anthony Rossini * ess.texi: archive is on Franz. Thu Nov 20 09:43:47 1997 Anthony Rossini * README: more comments about dir. Thu Nov 20 09:41:53 1997 Anthony Rossini * Makefile: "it" to "they". Thu Nov 20 09:40:44 1997 Anthony Rossini * Makefile: put dir back into the Docs. Thu Nov 20 09:38:54 1997 Anthony Rossini * Doc/TODO: truns :-). Thu Nov 20 09:38:12 1997 Anthony Rossini * Doc/ajr-talk.tex: added typoout for fonts. Thu Nov 20 09:35:28 1997 Anthony Rossini * Doc/rmh-talk.tex: fixed my typo, line wrap. Thu Nov 20 09:33:16 1997 Anthony Rossini * Doc/README.additions: added essdd*.el Thu Nov 20 09:22:02 1997 Anthony Rossini * Doc/TODO: added new for fix to About. Thu Nov 20 09:19:52 1997 Anthony Rossini * ess-trns.el (ess-transcript-mode-menu): * ess-inf.el (inferior-ess-mode-menu): * ess-mode.el (ess-mode-menu): removed About from menu, for now. Wed Nov 19 12:24:22 1997 Anthony Rossini * RELEASED 5.0, lastpre. * Makefile: removed veryclean. unnecessary target. Fixed dist-doc target. Wed Nov 19 12:21:38 1997 Anthony Rossini * Doc/rmh-talk.tex: no changes. Wed Nov 19 12:21:02 1997 Anthony Rossini * Doc/ajr-talk.tex: final version. Not best, but we've got docs provided. Wed Nov 19 12:03:03 1997 Anthony Rossini * Doc/ajr-talk.tex: use the ugly version Wed Nov 19 12:01:53 1997 Anthony Rossini * essd-sas.el (ess-SAS-pre-run-hook): never take name from a running process buffer. Wed Nov 19 11:56:09 1997 Anthony Rossini * essd-xls.el: added transcript mode. Wed Nov 19 11:43:24 1997 Anthony Rossini * ess-mode.el (ess-mode-menu): bug in "About". Wed Nov 19 11:25:01 1997 Anthony Rossini * README: database creation works. Wed Nov 19 11:20:28 1997 Anthony Rossini * ess-inf.el (ess-create-object-name-db): use temporary name for ess-object-name-db; since we make it buffer local to accommodate different languages, need to handle it carefully. In particular, might be better to make buffer local upon demand, rather than always buffer local. But lots of considerations, here. Wed Nov 19 11:14:10 1997 Anthony Rossini * ess-inf.el (ess-create-object-name-db): added *ESS* messages. Wed Nov 19 10:56:47 1997 Anthony Rossini * ess.el (ess-load-object-name-db-file): no warning when object database name fails to exist; the code is still there. Wed Nov 19 10:55:38 1997 Anthony Rossini * essd-s+3.el: setq-default to setq * essd-r.el: setq, not setq default. Wed Nov 19 10:52:28 1997 Anthony Rossini * README: added statement about object-name db being broken. Wed Nov 19 10:33:47 1997 Anthony Rossini * essd-s+3.el (S+3-transcript-mode): make interactive. Wed Nov 19 10:32:28 1997 Anthony Rossini * ess-site.el (s-transcript-mode): make interactive. Wed Nov 19 10:31:54 1997 Anthony Rossini * essd-r.el (r-transcript-mode): make interactive. Tue Nov 18 17:38:56 1997 Anthony Rossini * essddr.el: updated to 0.1.7. (KH) Tue Nov 18 17:37:11 1997 Anthony Rossini * ess-inf.el: ess-create-object-name-db, format Tue Nov 18 17:21:37 1997 Anthony Rossini * essd-s+3.el (S+3-customize-alist): changed var name for consistency. Tue Nov 18 17:20:21 1997 Anthony Rossini * essd-r.el (R-customize-alist): use R-help-sec-keys-alist. Tue Nov 18 17:19:23 1997 Anthony Rossini * ess-vars.el: removed spurious variable. Tue Nov 18 17:18:29 1997 Anthony Rossini * ess-vars.el: removed ess--help-S-sec-keys-alist; second def! Tue Nov 18 17:14:33 1997 Anthony Rossini * essl-s.el (ess-help-*-sec-keys-alist): renamed to *-help-sec-keys-alist. defvars to defconst. Tue Nov 18 17:03:40 1997 Anthony Rossini * ess-inf.el (inferior-ess): removed "switch-to" logic in inferior-ess. Now should strictly start-up a buffer. Tue Nov 18 16:58:06 1997 Anthony Rossini * Makefile: added warnings for set-keymap-parent; XEmacs, non-Emacs. Tue Nov 18 16:52:52 1997 Anthony Rossini * essl-s.el: added Martin's fix to documentation. Mon Nov 17 09:59:20 1997 Anthony Rossini * ess-inf.el (inferior-ess-mode-menu): reinstalled info connection. Mon Nov 17 09:58:37 1997 Anthony Rossini * ess-mode.el: reinstalled info connection. Mon Nov 17 09:25:24 1997 Anthony Rossini * Doc/rmh-talk.tex: added updates. (RMH) Mon Nov 17 09:09:09 1997 Anthony Rossini * README.S: fixed grammar. Mon Nov 17 09:05:50 1997 Anthony Rossini * README/ess.texi: R uses ess-r-namedb.el. (RMH) Mon Nov 17 09:04:41 1997 Anthony Rossini * README/ess.texi: changed phrasing for creating object database files. (RMH) Mon Nov 17 09:00:38 1997 Anthony Rossini * ess-inf.el (inferior-ess): doc string edited. Wrong comments removed (RMH). Mon Nov 17 08:57:54 1997 Anthony Rossini * Makefile: fixed documentation dependencies (RMH) Mon Nov 17 08:56:41 1997 Anthony Rossini * ess.el: fixed Lisp-Dir-Entry; franz.stat.wisc.edu, not ftp.math.sc.edu. (RMH). Mon Nov 17 08:54:59 1997 Anthony Rossini * Doc/ajr-talk.tex: added comments for changing font usage (RMH). Fri Nov 14 17:44:14 1997 Anthony Rossini * README: added more of an introduction and "history" statement. * README.S: added a small "FAQ" at the end. * Doc/TODO: Added last of the SAS things to do for 5.2 or 5.4. Fri Nov 14 17:27:27 1997 Anthony Rossini * README: more comments. Fri Nov 14 16:59:05 1997 Anthony Rossini * Doc/TODO: added SAS fontlock, graphics. R Help Fri Nov 14 13:49:40 1997 Anthony Rossini * README.XLispStat: fixed small typos. Fri Nov 14 11:24:05 1997 Anthony Rossini * Makefile (DOCS): reordered variable. Added info/dvi files. Fri Nov 14 11:22:03 1997 Anthony Rossini * ess.el: more comment work. * ess.el: verified using lisp-mnt.el; standard package formatting. Fri Nov 14 11:06:18 1997 Anthony Rossini * Makefile (clean): don't remove .dvi or .info* * Makefile (veryclean): new target, for removing what clean used to remove Fri Nov 14 10:13:49 1997 Anthony Rossini * Makefile: version to 5.0 Fri Nov 14 10:13:40 1997 Anthony Rossini * Makefile (VERSION): version to 5.0 Fri Nov 14 10:13:24 1997 Anthony Rossini * ess-vars.el: version to 5.0 Fri Nov 14 10:13:04 1997 Anthony Rossini * ess-vars.el (ess-version): version to 5.0. Fri Nov 14 10:12:34 1997 Anthony Rossini * README.S: added notes for starting R with prefix arguments. Fri Nov 14 09:59:25 1997 Anthony Rossini * ess.texi: added @itemize markers. Thu Nov 13 21:45:27 1997 Anthony Rossini * Release: 5.0-pre5 * Makefile (VERSION): incremented. * ess-vars.el (ess-version): incremented. Thu Nov 13 21:40:12 1997 Anthony Rossini * essd-sas.el: works again. shooze... Thu Nov 13 20:51:36 1997 Anthony Rossini * ess.el (ess-load-object-name-db-file): don't bomb if file doesn't exist.. Thu Nov 13 20:31:21 1997 Anthony Rossini * ess-inf.el: back to initial, except for new unused, commented out, variable) Thu Nov 13 20:28:06 1997 Anthony Rossini * ess-inf.el: New temp variables for when we rewrite the initialization routines; NEED TO DO THIS FOR 5.2!!! LOGIC HAS CHANGED, FOR THE "SIMPLER"! * ess-inf.el: doesn't work. This is a mess. * ess-inf.el (inferior-ess): use language instead of dialect for "*language*" and "*language:1*" buffer names; old version commented out. Thu Nov 13 20:11:10 1997 Anthony Rossini * ess-vars.el (ess-plain-first-buffername): use it. Thu Nov 13 20:07:42 1997 Anthony Rossini * ess-inf.el: forgot ")". Thu Nov 13 20:06:12 1997 Anthony Rossini * essd-sas.el: fixed R then SAS buffer name problem. Thu Nov 13 19:56:57 1997 Anthony Rossini * ess-site.el: added commented example for ess-plain-first-buffername. TRUE by default, i.e. for "novice" mode. Thu Nov 13 19:54:23 1997 Anthony Rossini * ess-vars.el: moved database loading to ess-mode and inferior-ess-mode; removed old comments. Thu Nov 13 19:52:31 1997 Anthony Rossini * ess-inf.el (ess-proc-name): If ess-plain-first-buffername is true, don't add "process number" to the first process. Thu Nov 13 19:35:59 1997 Anthony Rossini * ess.el (ess-load-object-name-db-file): new function, use it. Thu Nov 13 19:35:27 1997 Anthony Rossini * ess-inf.el: C-c tab is ess-complete-object-name. Thu Nov 13 19:34:48 1997 Anthony Rossini * ess-inf.el (inferior-ess-mode-map): C-c TAB is ess-complete-object-name, same as in ess-mode. Thu Nov 13 19:27:55 1997 Anthony Rossini * ess-inf.el (inferior-ess-mode): load object-name db file if exists. Thu Nov 13 19:19:37 1997 Anthony Rossini * ess-mode.el (ess-mode): load object-name db file if exists. Thu Nov 13 19:17:59 1997 Anthony Rossini * ess.texi: bare-bones description of how to create object-name databases. Thu Nov 13 19:09:07 1997 Anthony Rossini * README: added notes for database creation Thu Nov 13 10:16:12 1997 Anthony Rossini * README.XLispStat : XLispStat isn't a trademark. Thu Nov 13 09:59:05 1997 Anthony Rossini * Makefile (ess.elc): fixed action * Makefile (ess-vars.elc): fixed action Thu Nov 13 09:58:42 1997 Anthony Rossini * ess-vars.el: removed ancient comments. Thu Nov 13 09:58:23 1997 Anthony Rossini * README.S: added means for using second philosophy. Thu Nov 13 09:51:19 1997 Anthony Rossini * README.S: fixed line break. Thu Nov 13 09:40:56 1997 Anthony Rossini * Doc/ajr-talk.tex: added location of talk. Thu Nov 13 09:39:52 1997 Anthony Rossini * Doc/rmh-talk.tex: pointed to FRANZ. added comment about where given. 1998-11-13 A.J. Rossini * doc/Makefile: added "info" target. Removed spurious ess.info/ess.texi dependency, i.e. the first. Thu Nov 13 08:54:40 1997 Anthony Rossini * Makefile (dist-doc): new target. Use it * Makefile (ESS-doc): new target. Use it. Wed Nov 12 17:32:49 1997 Anthony Rossini * Doc/ajr-talk.tex: de latex-2-html'd. Wed Nov 12 17:26:25 1997 Anthony Rossini * ess-inf.el: args passes all the way through. Wed Nov 12 16:30:34 1997 Anthony Rossini * essd-r.el: added prefix to R. Wed Nov 12 15:15:06 1997 Anthony Rossini * README: added stata comment, site-init.el Wed Nov 12 15:12:25 1997 Anthony Rossini * ess.texi: added installation (from README). Use @file{} for file names. Wed Nov 12 14:56:41 1997 Anthony Rossini * Makefile: added warning messages for ignorable errors. Wed Nov 12 14:43:07 1997 Anthony Rossini * ess-inf.el: can't seem to remove last byte compiler error. Wed Nov 12 14:30:00 1997 Anthony Rossini * ess-trns.el: * ess-help.el: added compile requires to remove byte-compiler warnings. Wed Nov 12 14:21:33 1997 Anthony Rossini * essddr.el: paren balance. whoops. Wed Nov 12 14:20:41 1997 Anthony Rossini * essddr.el: added "require 'ess-help" to solve byte compiler errors. Wed Nov 12 14:16:37 1997 Anthony Rossini * essd-sas.el: require 'shell to fix byte-compile errors. Wed Nov 12 02:45:44 1997 Anthony Rossini * Release: 5.0-pre4 * ess-vars.el: updated version number for release * Makefile: Updated version number for release Wed Nov 12 02:27:16 1997 Anthony Rossini * essd-sas.el: seems to work, now. Tue Nov 11 19:20:50 1997 Anthony Rossini * essd-sas.el: might need comint. Tue Nov 11 19:09:18 1997 Anthony Rossini * README.XLispStat: fixed small errors. Tue Nov 11 19:04:51 1997 Anthony Rossini * README.XLispStat : bad key-seq "C-c C-f" isn't find-file. Tue Nov 11 19:01:22 1997 Anthony Rossini * README.S: merged rewrite (RMH) Tue Nov 11 16:49:41 1997 Anthony Rossini * essd-sas.el: format cleaning. Tue Nov 11 16:42:28 1997 Anthony Rossini * essd-sas.el: ess-SAS-pre-run-hook now called from SAS, not inferior-ess. Tue Nov 11 16:34:38 1997 Anthony Rossini * essl-sta.el: wrong header! Tue Nov 11 16:32:51 1997 Anthony Rossini * ess.texi: added to New Features. Tue Nov 11 16:30:26 1997 Anthony Rossini * README: small typos. Distributed from Wisconsin. Tue Nov 11 16:27:21 1997 Anthony Rossini * README: added Splus 3.4. Removed "futures". Tue Nov 11 16:25:59 1997 Anthony Rossini * ess-vars.el: inferior S -> inferior ESS Tue Nov 11 16:24:38 1997 Anthony Rossini * ess-site.el: small doc changes (RMH). Tue Nov 11 16:21:34 1997 Anthony Rossini * README.S: edited how to find key-sequences (RMH) Tue Nov 11 16:19:51 1997 Anthony Rossini * ess-inf.el: removed comint symbols. (RMH). Need to read comint docs (AJR). Tue Nov 11 16:19:00 1997 Anthony Rossini * Makefile: small typos corrected. Tue Nov 11 16:04:26 1997 Anthony Rossini * ess-inf.el (ess-read-object-name): use ess-read-object-name-dump. * ess-inf.el (ess-read-object-name-default): reverted back to old behavior. * ess-inf.el (ess-read-object-name-dump): new function. Use it. Tue Nov 11 15:56:03 1997 Anthony Rossini * ess.texi: XLisp-Stat, uniformly. Tue Nov 11 15:51:48 1997 Anthony Rossini * ess.texi: fixed titles (no @_{} commands). Updated menus. (MM) Tue Nov 11 15:38:52 1997 Anthony Rossini * README.XLispStat: removed "S(tm)". * README.SAS: major overhaul (RMH). * README.S: removed "S(tm)". Tue Nov 11 10:02:44 1997 Anthony Rossini * ess-inf.el (ess-read-object-name-default): new version (KH). Tue Nov 11 10:00:54 1997 Anthony Rossini * ess-site.el ((assoc "\\.[rR]\\'" auto-mode-alist)): added man format again for R internal man pages. Mon Nov 10 23:17:28 1997 Anthony Rossini * Makefile: added latex/tex for talks on ESS 5.0. Mon Nov 10 23:02:36 1997 Anthony Rossini * Releasing 5.0-pre3. * essd-sas.el: changes made. Watch out. * ess-vars.el (ess-version): 5.0-pre3 * Makefile (VERSION): 5.0-pre3 Mon Nov 10 22:58:39 1997 Anthony Rossini * ess-mode.el: more S to ESS Mon Nov 10 22:52:55 1997 Anthony Rossini * ess-inf.el: more S/ESS fixes (RMH) Mon Nov 10 22:49:31 1997 Anthony Rossini * README.SAS: typo Mon Nov 10 22:43:59 1997 Anthony Rossini * ess-inf.el (ess-read-object-name-default): handle defaults better. Mon Nov 10 22:34:11 1997 Anthony Rossini * README.S: typo. Mon Nov 10 17:28:28 1997 Anthony Rossini * README.SAS: added some suggestions by RMH. Mon Nov 10 17:26:11 1997 Anthony Rossini * README.S: edited as suggested by RMH. Mon Nov 10 17:17:21 1997 Anthony Rossini * README.S: stuff. Mon Nov 10 17:16:21 1997 Anthony Rossini * README: changed mode/revision. Mon Nov 10 17:14:53 1997 Anthony Rossini * README: fixes (RMH) Mon Nov 10 17:04:38 1997 Anthony Rossini * ess-trns.el (ess-transcript-mode): * ess-help.el (ess-help-mode): * ess-inf.el (inferior-ess-mode): * ess-mode.el (ess-mode): keep tabs out of the code. Mon Nov 10 16:48:00 1997 Anthony Rossini * ess.texi: @code -> @email when appropriate. Mon Nov 10 15:58:23 1997 Anthony Rossini * ess.texi: added most, approx 300, of MM's changes. A very few differences, though. Mon Nov 10 15:05:45 1997 Anthony Rossini * ess-vars.el: S -> ESS (MM) Mon Nov 10 15:02:32 1997 Anthony Rossini * ess-trns.el: S -> ESS (MM) Mon Nov 10 14:59:39 1997 Anthony Rossini * ess-mode.el: S -> ESS (MM). Mon Nov 10 14:51:30 1997 Anthony Rossini * ess-inf.el: S -> ESS (MM). Mon Nov 10 14:41:30 1997 Anthony Rossini * ess-help.el: removed comment re: S.el. * ess-help.el: updated docs and functions, S -> ESS (MM) Mon Nov 10 14:34:35 1997 Anthony Rossini * Makefile (MAKEHTML): change target (MM) * Makefile (clean): more to clean (MM) * Makefile (dvi): new target. Use it (MM) Sun Nov 9 16:30:38 1997 Anthony Rossini * Doc/TODO: cleaned out my email of TODO problems, except for SAS). Sun Nov 9 16:24:39 1997 Anthony Rossini * Doc/TODO: updated for what has been accomplished by this stage, for 5.0. Sun Nov 9 15:32:34 1997 Anthony Rossini * essl-sta.el: cleaned up errors via lets. Sun Nov 9 15:26:33 1997 Anthony Rossini * essl-sas.el: removing unusable commands. Sun Nov 9 15:08:56 1997 Anthony Rossini * ess-vars.el (no-doc): new variable. use it for autoload documentation. Sun Nov 9 15:08:13 1997 Anthony Rossini * Makefile: ess-vars/ess/ess-site dependencies cleared up. Sun Nov 9 15:02:29 1997 Anthony Rossini * essd-sas.el: changed documentation for autoloads. Sun Nov 9 14:56:32 1997 Anthony Rossini * essl-sas.el: one too many ")" (in editing sas-narrow-to-page). Sun Nov 9 14:48:55 1997 Anthony Rossini * ess-site.el: cleaned up. Sun Nov 9 14:44:06 1997 Anthony Rossini * ess-comp.el: cleaned up. Sun Nov 9 14:38:29 1997 Anthony Rossini * essl-sta.el: cleaned up format. Sun Nov 9 14:33:18 1997 Anthony Rossini * essd-sas.el: cleaned up byte-compiler warnings and lisp. Sun Nov 9 14:32:54 1997 Anthony Rossini * essl-sas.el: need the right name at top. * essl-sas.el: cleaned up byte-compiler warnings. Sun Nov 9 14:17:36 1997 Anthony Rossini * Makefile: cleaned dependencies for essd-*.el Sun Nov 9 14:00:56 1997 Anthony Rossini * ess-vars.el (ess-version): upgrade to 5.0 * Makefile: upgrade version to 5.0 1998-11-09 A.J. Rossini * Makefile (dist): new top-level target. (dist): uses scp to put it where it belongs. Fri Nov 7 19:43:11 1997 Anthony Rossini * Released 5.0-pre2. * Makefile (dist): copy makefile into the appropriate place. Fri Nov 7 19:41:02 1997 Anthony Rossini * essd-sas.el (ess-SAS-pre-run-hook): fixed process name synch problem. Fri Nov 7 19:18:57 1997 Anthony Rossini * essd-sas.el (ess-SAS-pre-run-hook): set explicit-shell-file-name to "/bin/sh" to aviod prompt evilness. Fri Nov 7 18:33:29 1997 Anthony Rossini * Doc/TODO: SAS problems. Fri Nov 7 18:28:40 1997 Anthony Rossini * ess-inf.el (inferior-R-input-sender): patch to avoid problems with R, for "help()" (MM). Fri Nov 7 18:17:54 1997 Anthony Rossini * ess-site.el: added comments re: TT commenting/editing styles. Fri Nov 7 18:10:25 1997 Anthony Rossini * ess-mode.el: indentation. Fri Nov 7 14:42:45 1997 Anthony Rossini * ess-mode.el: changes for TT (RMH). Fri Nov 7 14:31:35 1997 Anthony Rossini * essl-sas.el (sas-require-confirmation): doc string edit. Fri Nov 7 14:30:33 1997 Anthony Rossini * ess-vars.el (ess-transcript-minor-mode): * ess-vars.el (ess-listing-minor-mode): new variables. Use. (RMH) Fri Nov 7 14:29:49 1997 Anthony Rossini * essl-sas.el: fixes for multiple SAS processes. (RMH) Fri Nov 7 13:53:16 1997 Anthony Rossini * essd-sas.el: changes for SAS mode (RMH-2Nov). Fri Nov 7 13:47:31 1997 Anthony Rossini * ess-vars.el: patches for Terry Thernau's suggested indentation (RMH) Fri Nov 7 13:37:41 1997 Anthony Rossini * README.XLispStat: new file. read it. * README.SAS: New file. Read it. * README.S: revision, not version. Fri Nov 7 11:41:01 1997 Anthony Rossini * README.S: added gen'l features, id -> version. Fri Nov 7 09:23:55 1997 Anthony Rossini * README.S: New file. Include it. Fri Nov 7 09:20:30 1997 Anthony Rossini * README: pointer to README.S, README.SAS, and README.XLispStat Fri Nov 7 09:17:52 1997 Anthony Rossini * README: changes to mailing list and WWW documentation location (MM). Thu Nov 6 10:42:10 1997 Anthony Rossini * Makefile (DOCS): added README.LANGUAGE files to the Makefile. Need to fill them in. Wed Oct 29 14:08:52 1997 Anthony Rossini * README: rearranged, as suggested by Don Cram. (DC). Mon Oct 27 14:50:18 1997 Anthony Rossini * ess.texi: readded "New Features" section. Mon Oct 27 13:05:13 1997 Anthony Rossini * ess.texi: started editing section 1. In particular, @b{S} refers to a generic statistical process, at this point. Mon Oct 27 10:44:44 1997 Anthony Rossini * ess.texi (Local Variables): TeX-master ought to be ess.texi. Whoops. Mon Oct 27 10:25:49 1997 Anthony Rossini * Doc/TODO: added RMH's SAS suggestions. Mon Oct 27 10:22:17 1997 Anthony Rossini * essd-sas.el (ess-SAS-pre-run-hook): removed interactive call. * essd-sas.el (ess-SAS-pre-run-hook): make sure buffer name of any running *shell* buffers is unique for changes. Mon Oct 27 10:03:34 1997 Anthony Rossini * Makefile (SOURCES): removed ess-debug from distributed sources. Mon Oct 27 09:01:24 1997 Anthony Rossini * Makefile (dist): Doc should not be writable, again. Fri Oct 24 16:31:12 1997 Anthony Rossini * Makefile (install): -ne should be !=, since doing string, not integer, comparison. (KH) Fri Oct 24 12:25:40 1997 Anthony Rossini * ess-vars.el (ess-version): * Makefile (VERSION): 5.0-pre2 * ess-site.el ((assoc "\\.[rR]\\'" auto-mode-alist)): changes for R, 0.50 vs. 0.60. Fri Oct 24 08:56:26 1997 Anthony Rossini * ESS-5.0-pre1 released. Fri Oct 24 08:55:10 1997 Anthony Rossini * ess-vars.el (ess-version): * Makefile (VERSION): updated version name to 5.0-pre1, skipping beta-17. Fri Oct 24 08:51:27 1997 Anthony Rossini * essd-sas.el (ess-SAS-pre-run-hook): We need to make sure that no shells are currently running. put back the stuff removed 1.5 hours ago. Cleaned up variable usage using let. Fri Oct 24 08:13:58 1997 Anthony Rossini * essl-sas.el (SAS-log-mode): fundamental mode, with read-only. Same as listing mode, pretty much. Fri Oct 24 08:11:41 1997 Anthony Rossini * essl-sas.el (set-sas-file-buffer): sasl-mode isn't real, anymore. Fri Oct 24 08:07:48 1997 Anthony Rossini * essd-sas.el (ess-SAS-pre-run-hook): after accepting process input, sleep-for to allow the rest of the input to appear! Else, we don't read the correct tty. Alternative: would have to grep for tty, and figure out if we mean BSD or SYSV style unix. Bleach. Fri Oct 24 07:21:33 1997 Anthony Rossini * essd-sas.el (ess-SAS-pre-run-hook): removed ess-sas-shell-buffer-name stuff. Necessary? Fri Oct 24 07:21:16 1997 Anthony Rossini * ess-sas-sh-command: use /bin/sh Fri Oct 24 07:20:56 1997 Anthony Rossini * Makefile (dist): make sure scripts are executable before packaging. Thu Oct 23 17:24:23 1997 Anthony Rossini * essd-sas.el (ess-sas-shell-buffer-name-flag): use it. * essd-sas.el (ess-sas-shell-buffer-name): use it. Thu Oct 23 17:20:42 1997 Anthony Rossini * essd-sas.el (ess-SAS-pre-run-hook): removed 'interactive' call. Should only be run from a run-hooks call? * essd-sas.el (ess-SAS-pre-run-hook): ess-shell-buffer-name-p should be ess-shell-buffer-name-flag; -p and p suffices are reserved for functions, -flag reserved for variables. Thu Oct 23 13:17:28 1997 Anthony Rossini * ess-inf.el (ess-eval-line-and-next-line, ess-eval-line, ess-eval-function, ess-eval-buffer): ess-force-buffer-current Thu Oct 23 09:08:24 1997 Anthony Rossini * Makefile (install): test lispdir to see if needs install (MM). Thu Oct 23 09:07:42 1997 Anthony Rossini * essl-sas.el (ess-transcript-mode): should be autoloaded. Thu Oct 23 09:01:45 1997 Anthony Rossini * ess-site.el (s-transcript-mode): generic. Moved here. Thu Oct 23 09:00:02 1997 Anthony Rossini * essd-r.el (r-transcript-mode): moved here. Thu Oct 23 08:57:04 1997 Anthony Rossini * Makefile (AUXFILES): added SCRIPTS * Makefile (SCRIPTS): new variable, use it. Thu Oct 23 08:52:27 1997 Anthony Rossini * ess-inf.el (ess-eval-visibly): DOCSTRING lied; text -> text-withtabs. Thu Oct 23 08:30:21 1997 Anthony Rossini * Makefile (dist): remove write permission from ChangeLog for distribution. Thu Oct 23 08:23:52 1997 Anthony Rossini * Makefile (DOCS): new variable. Use it. Thu Oct 23 08:22:09 1997 Anthony Rossini * Makefile (SOURCES): Need to include ess-debug, ess-comp. Wed Oct 22 15:53:46 1997 Anthony Rossini * ess-vars.el (ess-version): updated version number (17) * Makefile (VERSION): updated version number (17) * beta 16 released. Wed Oct 22 15:10:26 1997 Anthony Rossini * Makefile (dist): dist target now works; being too ambitious resulted in the loss of below. 1997-10-22 Anthony Rossini * WHOOPS. Stupid mistake, lost 2 days of ChangeLog activity. Mon Oct 20 14:20:51 1997 Anthony Rossini * ess-help.el (ess-display-help-on-object): set the customization variables properly. Thu Oct 16 14:25:59 1997 Anthony Rossini * essd-sas.el (ess-mode): added autoload. * essd-s+3.el: editing of spaces. * Makefile (SOURCES): changed edd-doc appropriately.i Fri Oct 10 12:05:40 1997 Anthony Rossini * beta 15 released. * ess-trns.el (ess-transcript-mode): start up in read-only mode. Wed Oct 8 14:50:03 1997 Anthony Rossini * ess-inf.el (ess-proc-name): takes stringname for buffer; was ess-dialect. Use it. Wed Oct 8 13:56:51 1997 Anthony Rossini * essd-s4.el (S4-customize-alist): inferior-ess-*-command variables must end in "\n". * essd-s+3.el (S+3-customize-alist): inferior-ess-*-command variables must end in "\n". Wed Oct 8 08:50:58 1997 Anthony Rossini * ess-vars.el (inferior-ess-names-command): add "\n" to end of names(%s) command (KH). Wed Oct 8 05:36:04 1997 Anthony Rossini * ess-debug.el: new file for debugging and development. Use it. Tue Oct 7 15:46:59 1997 Anthony Rossini * ess-site.el: commented out debug-on-error. Tue Oct 7 15:42:49 1997 Anthony Rossini * ess-inf.el (ess-get-words-from-vector): don't concat "\n", since we might have multi-line commands. Make them do it in the command definition (KH). Tue Oct 7 13:21:57 1997 Anthony Rossini * Makefile (SOURCES): add ess-doc.el Thu Oct 2 08:52:58 1997 Anthony Rossini * Makefile (install): create INFODIR and LISPDIR as well as parents before installing. Thu Oct 2 08:42:46 1997 Anthony Rossini * ess-inf.el (ess-multi): removed ess-pre-run-hook execution; it should only happen in inferior-ess. Thu Oct 2 01:12:22 1997 Anthony Rossini * essl-s.el (r-transcript-mode, s-transcript-mode): new functions. Use it, and fset it. Thu Oct 2 01:12:07 1997 Anthony Rossini * ess-trns.el (ess-transcript-mode): added alist parameter. Use it. Thu Oct 2 00:35:30 1997 Anthony Rossini * ess-vars.el (ess-function-pattern): tied the non-quoted function name to either the beginning of a line or a space, instead of beginning of a word. Wed Oct 1 21:50:59 1997 Anthony Rossini * essl-s.el (S-syntax-table): modified . to be "_" (KH). Wed Oct 1 21:46:51 1997 Anthony Rossini * ess-inf.el: Require ess-site, not just ess, so that language specific stuff will be loaded. Wed Oct 1 21:45:47 1997 Anthony Rossini * ess-trns.el: Require ess-site, not just ess, so that language specific stuff will be loaded. Tue Sep 16 16:15:37 1997 Anthony Rossini * essl-sas.el (SAS-editing-alist): * essl-lsp.el (Lisp-editing-alist): * essl-s.el (S-editing-alist): ess-keep-dump-files NEEDS to be 'ask. Wed Sep 10 13:48:41 1997 Anthony Rossini * ess-help.el (ess-submit-bug-report): ess-program-name doesn't exist. Wed Sep 10 13:44:52 1997 Anthony Rossini * essl-sas.el: can't require sas here. Wed Sep 10 13:33:57 1997 Anthony Rossini * essl-sas.el: added Tom Cook's sas-data code. Not integrated yet. Wed Sep 10 09:42:30 1997 Anthony Rossini * Makefile (html/ess_toc.html): Use explicit file "index.html", since some servers/browsers have different defaults. (MM). Wed Sep 10 09:40:04 1997 Anthony Rossini * ess-site.el ((assoc "\\.[rR]\\'" auto-mode-alist)): change check for setting auto-mode-alist (MM). Tue Sep 9 16:35:21 1997 Anthony Rossini * ess-mode.el: removed code which generated a second "ess-mode" menu. Tue Sep 9 16:23:56 1997 Anthony Rossini * ess-mode.el (ess-mode): mode name: ess-language, not ess-dialect. Tue Sep 9 16:22:41 1997 Anthony Rossini * ess-inf.el (inferior-ess-mode): mode name: iESS [ess-dialect:proc] Tue Sep 9 10:39:35 1997 Anthony Rossini * essd-[r][s+3].el (*-customize-alist): lastvalue command renamed as ".ess.lvsave". Tue Sep 9 09:59:04 1997 Anthony Rossini * ess-inf.el: what is (fset 'run-s (fset 'run-S (symbol-function 'S))) for?? Tue Sep 9 09:15:24 1997 Anthony Rossini * ess-vars.el (ess-version): incremented * Makefile (VERSION): incremented Tue Sep 9 09:01:59 1997 Anthony Rossini * RELEASING beta 13 Tue Sep 9 09:01:02 1997 Anthony Rossini * Makefile (all): ess -> ESS Tue Sep 9 08:29:48 1997 Anthony Rossini * essd-r.el (R-customize-alist): needs syntax table for inferior processes. Mon Sep 8 15:22:18 1997 Anthony Rossini * ess-inf.el (inferior-ess-mode): need to fix syntax table. Mon Sep 8 14:28:57 1997 Anthony Rossini * essl-sas.el (sas-indent-line): renamed from indent-sas-statement. Mon Sep 8 14:08:24 1997 Anthony Rossini * ess-mode.el (ess-mode): add one more debugging statement. Mon Sep 8 13:23:20 1997 Anthony Rossini * ess-vars.el: moved syntax table code to essl-s.el. Mon Sep 8 13:07:48 1997 Anthony Rossini * ess-vars.el (ess-version): updated. * Makefile: Updated version number Mon Sep 8 12:25:09 1997 Anthony Rossini * ess-help.el (ess-find-help-file): doesn't search for completions, with SAS or XLS. Fine, since there isn't a really good way to build the list [SAS] or it isn't coded yet [XLS]. Mon Sep 8 12:24:42 1997 Anthony Rossini * ess-help.el (ess-display-help-on-object): uses process name as part of the buffer. Mon Sep 8 12:23:24 1997 Anthony Rossini * ess-vars.el: removed inferior-ess-save-lastvalue-command and inferior-ess-retr-lastvalue-command, not needed. Mon Sep 8 09:01:18 1997 Anthony Rossini * essl-sas.el: moved SAS language related autoloads and fsets from ess.el to here. Mon Sep 8 08:59:13 1997 Anthony Rossini * essl-s.el: moved S language related autoloads and fsets from ess.el to here. Mon Sep 8 08:51:01 1997 Anthony Rossini * essd-sas.el (SAS-customize-alist): use ess-local-customize-alist. Mon Sep 8 08:46:32 1997 Anthony Rossini * essd-r.el (R-customize-alist): use ess-local-customize-alist. Mon Sep 8 08:45:43 1997 Anthony Rossini * essd-s+3.el (S+3-customize-alist): use ess-local-customize-alist. Mon Sep 8 08:45:00 1997 Anthony Rossini * essd-s4.el (S4-customize-alist): use ess-local-customize-alist. Mon Sep 8 08:42:48 1997 Anthony Rossini * essd-s3.el (S3-customize-alist): use ess-local-customize-alist. Mon Sep 8 08:41:35 1997 Anthony Rossini * ess-vars.el (ess-local-customize-alist): new variable. use it. Mon Sep 8 08:35:42 1997 Anthony Rossini * ess-site.el: code to remove .[sS] from auto-mode-alist commented out. Need a version which works with Emacs. Fri Sep 5 14:20:18 1997 Anthony Rossini * ess-mode.el (ess-eval-map): define it. New keysequence: C-c C-e ... for evaluation of code. Fri Sep 5 14:19:43 1997 Anthony Rossini * ess-vars.el (ess-eval-map): new variable. use it. Wed Sep 3 12:54:46 1997 Anthony Rossini * ess-trns.el: removed log section. Wed Sep 3 12:30:57 1997 Anthony Rossini * ess-mode.el (ess-find-dump-file-other-window): changed error to message, so that dumping non-existent R objects would work. Wed Sep 3 12:29:45 1997 Anthony Rossini * ess-help.el (ess-submit-bug-report): fixed to use ess-bugs, and to include *ESS* buffer contents. Wed Sep 3 12:27:35 1997 Anthony Rossini * essd-s4.el: rolled in John Chamber's s4-modeadds.el Wed Sep 3 11:48:24 1997 Anthony Rossini * essd-s4.el (S4-customize-alist): added inferior-ess-search-list-command from the ess-xtras. Wed Sep 3 11:11:37 1997 Anthony Rossini * ess-site.el ((assoc "\\.q" auto-mode-alist)): removed '$'. (RMH). Wed Sep 3 10:42:13 1997 Anthony Rossini * ess.texi : applied Martin's updates. Wed Sep 3 10:37:39 1997 Anthony Rossini * Makefile: applied Martin's patch, ESS -> ess, for texinfo stuff. Tue Sep 2 16:36:59 1997 Anthony Rossini * essd-*.el (ess-dump-filename-template): use it, with ess-suffix. Tue Sep 2 16:19:41 1997 Anthony Rossini * ess-vars.el (ess-delete-dump-files): changed default value to nil. Better safe than sorry. Tue Sep 2 16:05:04 1997 Anthony Rossini * essd-*.el (*-customize-alist): ess-suffix. Use it. Tue Sep 2 15:44:02 1997 Anthony Rossini * essl-s.el: moved "general" variables from essd-s?.el, essd-r.el. There, should only be modifications to the standard S customizations. Avoids conflict with not loading certain customization variables. Tue Sep 2 13:23:01 1997 Anthony Rossini * Makefile (LASTVERSION): version set to 12. Tue Sep 2 10:22:11 1997 Anthony Rossini * ess-vars.el (ess-version): Version 11 released; set to 12. Mon Sep 1 17:16:42 1997 Anthony Rossini * essd-r.el (R-mode): setq-default the customize alist. Mon Sep 1 16:59:57 1997 Anthony Rossini * essd-s+3.el (S+3-mode): need to set ess-customize-alist. Mon Sep 1 16:15:10 1997 Anthony Rossini * ess-vars.el (ess-mode-font-lock-keywords): redid the assign fontlocking. Mon Sep 1 15:53:54 1997 Anthony Rossini * ess-vars.el (ess-mode-editing-alist): renamed. Use it. Mon Sep 1 15:48:43 1997 Anthony Rossini * ess-inf.el (inferior-ess): corrected doc string. Mon Sep 1 14:54:44 1997 Anthony Rossini * essl-sas.el: added sas config variables here. Mon Sep 1 14:21:08 1997 Anthony Rossini * essd-sas.el (SAS): works. Mon Sep 1 14:20:45 1997 Anthony Rossini * essd-sas.el (SAS-mode): fixed and "modernized". Mon Sep 1 14:16:16 1997 Anthony Rossini * ess.el (SAS-transcript-mode): load it. Mon Sep 1 14:16:07 1997 Anthony Rossini * ess.el (SAS-mode): load it. Mon Sep 1 14:12:33 1997 Anthony Rossini * ess-site.el (auto-mode-alist): XLS is recognized. SAS is recognized. Fri Aug 29 13:41:22 1997 Anthony Rossini * ess-inf.el (inferior-ess-make-comint): use inferior-ess-start-file, inferior-ess-start-args. Fri Aug 29 13:24:12 1997 Anthony Rossini * essd-sas.el (inferior-SAS-args): new variable. Use it. Fri Aug 29 13:11:56 1997 Anthony Rossini * ess-vars.el (ess-dribble-buffer): now defaults to *ESS*. (RMH/MM). Fri Aug 29 13:09:04 1997 Anthony Rossini * essd-sas.el (SAS-customize-alist): fixed primary prompt (RMH). Thu Aug 28 10:21:41 1997 Anthony Rossini * ess-mode.el (ess-check-modifications): reformat. Thu Aug 28 09:03:53 1997 Anthony Rossini * ess.el: moved ess-site autoloads here. Thu Aug 28 09:02:57 1997 Anthony Rossini * ess-help.el (ess-find-help-file): autoloaded ess-get-object-list at the beginning of ess-help; byte-compiler error. Wed Aug 27 14:33:56 1997 Anthony Rossini * ess-mode.el (ess-mode): needed to set buffer local variables AFTER they are killed. Whoops. Wed Aug 27 14:27:44 1997 Anthony Rossini * ess-mode.el (ess-mode): type changed to dialect. Wed Aug 27 11:55:07 1997 Anthony Rossini * ess-inf.el (ess-proc-name): changed the process name to be returned. Now is the form: ess-dialect : ess-process-number. Tue Aug 26 18:49:31 1997 Anthony Rossini * ess-version-running -> ess-dialect Tue Aug 26 18:49:18 1997 Anthony Rossini * ess-proc-prefix -> ess-language Tue Aug 26 17:58:11 1997 Anthony Rossini * ess-site.el: added SAS site init (from Cook's mode) (TC) Tue Aug 26 17:50:57 1997 Anthony Rossini * essl-sas.el: new file. SAS language editing mode (Cook's mode). Use it. (TC) Tue Aug 26 17:48:47 1997 Anthony Rossini * essl-s.el : new file. S language editing mode. Use it. S specific stuff from ess-mode. Mon Aug 25 16:53:10 1997 Anthony Rossini * ess-help.el (ess-find-help-file): added hack to complete non-S stuff. (KH) Mon Aug 25 16:42:46 1997 Anthony Rossini * essd-r.el (R-customize-alist): made the name quoted. Mon Aug 18 15:27:41 1997 Maechler * essd-r.el (R-customize-alist): sorted * essd-s4.el: * essd-s3.el (S3-customize-alist): not Splus; no 'Optional/Required Arg' * essd-s+3.el (S+3-customize-alist): switched some lower/upper case: more important things on lower case; now compatible to R Mon Aug 25 16:35:29 1997 Anthony Rossini * ess-site.el auto-mode-alist: Use \\' instead of $ [faster (?)], standard; Add ...src/library/[A-z]*/funs/.. for R source editing. (MM). Mon Aug 25 11:02:37 1997 Anthony Rossini * ess-site.el (inferior-ess-font-lock-input): added setq of this variable as a customization example (RMH). Mon Aug 25 10:35:09 1997 Anthony Rossini * ess-comp.el: removed (require 'cl). This is semi-evil, if we can only avoid it. Fri Aug 22 17:01:56 1997 Anthony Rossini * ess-vars.el (inferior-ess-font-lock-prompt-p): New variable. Need to use it. Customize in ess-site. Fri Aug 22 16:56:35 1997 Anthony Rossini * ess-inf.el (inferior-ess-mode): mode name is now "iESS", as per discussion. Fri Aug 22 16:54:19 1997 Anthony Rossini * ess-vars.el (ess-object-name-db-file-loaded): use it to determine which languages/versions have been loaded. Fri Aug 22 16:48:55 1997 Anthony Rossini * essd-r.el (R-customize-alist): added ess-object-name-db to alist. Fri Aug 22 16:47:57 1997 Anthony Rossini * essd-s+3.el (S+3-customize-alist): added ess-object-name-db to alist. Fri Aug 22 16:41:49 1997 Anthony Rossini * essd-xls.el (XLS-customize-alist): added ess-object-name-db to alist. Fri Aug 22 16:40:31 1997 Anthony Rossini * essd-xls.el (XLS-mode): moved from ess-mode.el Fri Aug 22 15:58:54 1997 Anthony Rossini * essd-s+3.el (S-mode): moved from ess-mode.el Fri Aug 22 15:58:07 1997 Anthony Rossini * essd-r.el (R-mode): moved from ess-mode.el Fri Aug 22 15:50:25 1997 Anthony Rossini * essd-s+3.el: removed commented out font-lock patterns. (RMH) Fri Aug 22 15:49:56 1997 Anthony Rossini * essd-s3.el: removed commented out font-lock patterns. (RMH) Fri Aug 22 15:48:59 1997 Anthony Rossini * ess-vars.el (essd-S-inferior-font-lock-keywords): added RMH's error patterns. Fri Aug 22 12:28:42 1997 Anthony Rossini * essd-sas.el: new file (RMH). Fri Aug 22 12:18:30 1997 Anthony Rossini * ess-vars.el (ess-function-pattern): New pattern, thanks to Stephen C. Pope . Fri Aug 22 11:59:32 1997 Anthony Rossini * Makefile (ESS.info): fixed text output (KH) Fri Aug 22 11:59:13 1997 Anthony Rossini * Makefile (html/ESS_toc.html): fixed text output (KH) Fri Aug 22 11:55:33 1997 Anthony Rossini * ess-vars.el (inferior-ess-save-lastvalue-command): new defvar for variable. (KH) Fri Aug 22 11:55:07 1997 Anthony Rossini * ess-vars.el (inferior-ess-retr-lastvalue-command): new defvar for variable. (KH) Fri Aug 22 11:54:27 1997 Anthony Rossini * ess-vars.el (S-plus): removed variable Fri Aug 22 11:51:22 1997 Anthony Rossini * essd-xls.el (XLS-customize-alist): inferior-ess-start-file ("~/.ess-R"). inferior-ess-start-args. Use it. Fri Aug 22 11:43:49 1997 Anthony Rossini * essd-s+3.el (S+3-customize-alist): inferior-ess-start-file ("~/.ess-R"). inferior-ess-start-args. Use it. Fri Aug 22 11:42:34 1997 Anthony Rossini * essd-r.el (R-customize-alist): inferior-ess-start-file ("~/.ess-R"). inferior-ess-start-args. Use it. Fri Aug 22 11:06:34 1997 Anthony Rossini * ess.texi: renamed, from ESS.texi. Changed header. Added info-directory stuff (KH). Fri Aug 22 11:04:02 1997 Anthony Rossini * ess.el: installed new, non CL versions of ess-setq-vars, ess-setq-vars-default. (KH) Fri Aug 22 10:58:05 1997 Anthony Rossini * ess-xtra.el: ESS-version -> ess-version (KH) Fri Aug 22 10:57:13 1997 Anthony Rossini * ess-vars.el (ess-version): incremented. ESS-version -> ess-version. (AJR) Fri Aug 22 10:56:11 1997 Anthony Rossini * ess-inf.el (inferior-ess-mode): ESS-version -> ess-version (KH) Fri Aug 22 10:56:11 1997 Anthony Rossini * STARTED : ESS-4.9-b11. All DOCUMENTATION NOW IN `ChangeLog'. Tue Jul 29 07:14:01 1997 Anthony Rossini * ess-vars.el: transcript fontlock vars now here. Mon Jul 28 09:57:57 1997 Anthony Rossini * ess-site.el: explanatory comments for dialect customization. Mon Jul 28 09:55:58 1997 Anthony Rossini * ess-vars.el: added defvars for ess-site things below. Still need to add to essd-*.el's! * ess-site.el: more customizations for the executable names. Need to move defvars to ess-vars. * README: edited authors again. * Makefile: S-mode -> ESS. * Makefile: updated version number. * ess-site.el: moved/uncommented essd-s?.el * essd-s3.el: provide the right package! * Makefile: S-mode -> ESS. * ess-site.el: reformat. * ess-site.el: fixed typo. * ess.el: made ess-setq-vars* clean. No ugly hacks! cleaned up authorship. * Makefile: updated version number. * ess.el (ess-setq-vars-default): made nice. * ess.el (ess-setq-vars): made nice. 1997-07-25 Anthony Rossini * ess-mode.el (ess-mode-map): newline/return mapped to 'newline-and-indent, by popular demand. * General : variable definitions in ess now moved to ess-vars. ess now only contains useful code for distinguishing between processes. 1997-07-01 Anthony Rossini * ess-inf.el (inferior-ess): removed make-local-variables which should've been handled in ess.el (ess-multi): same as above. (ess.el): fixed same. (ess-execute): removed make-local-variable 'ess-local-process-name (ess-force-buffer-current): removed make-local-variable 'ess-local-process-name (inferior-ess): let (done 0), for constructing inferior-ess-procname. * ess-site.el: added RMH's new docs, `ess-keep-dump-files'. * ess-inf.el (ess-quit): doc string edited. * ess-mode.el (ess-check-source): RMH's solution. 1997-06-16 Anthony Rossini * Makefile: trans->trns. Idea is to keep file names at the 8+3 length for archaic OSs... Sun Jun 15 04:39:09 1997 Anthony Rossini * NOTE: SEE RCS Log files for program updates. All language/dialect specific code attempted to be moved to essd files (d=dialect :-).. need more movement, though... * ess.el: Documentation update. Wed May 21 14:47:17 1997 Anthony Rossini * S-mode has now become ess-mode. (Emacs Speaks Statistics). Thu Apr 24 18:10:32 1997 Anthony Rossini * TODO: (MM) word wrap mistake. * S-help.el (S-help-mode-map): (MM) Patch to bind ^M to next-line. Whoops. (AJR) changed to \C-m. Wed Apr 23 09:29:53 1997 Anthony Rossini * S.el (S-mode-version): incremented. * S-help.el (S-display-help-on-object): (MM) S-help-sec-regex, S-help-sec-keys-alist take correct values (see yesterday's log for inferior-S-help-command). Need to do similar with inferior-S-help-command hack! * S.el : (MM) S-help-sec-regex, S-help-sec-keys-alist buffer-local. Tue Apr 22 19:19:47 1997 Anthony Rossini * S-mode-4.9-b5 : released. * S-help.el (S-display-help-on-object): Added curr-help-command (since inferior-S-help-command is buffer-local, need to get BEFORE switching buffers). * S-site.el (S,R,XLS): setq-default to setq. (R): "cat" -> inferior-S-pager. Buffer local? (XLS): cleaned up. (S-XLS-shortcut-post-run-hook): new function. (S-XLS-shortcut-pre-run-hook): new function. (R): cleaned up. (S-R-shortcut-post-run-hook): new function. (S-R-shortcut-pre-run-hook): new function. (S): cleaned up. (S-S-shortcut-post-run-hook): new function. (S-S-shortcut-pre-run-hook): new function. * S-inf.el (inferior-S): removed useless make-local-variables * S.el : declared many variables via make-variable-buffer-local. * S-site.el : removed useless make-local-variables... * S-inf.el (S-multi): setq -> setq-default, for inferior-S-prompt. * buffer-local stuff moved to S.el. Mon Apr 21 21:35:22 1997 Anthony Rossini * S-mode-4.9-b4 : released. * S-site.el (XLS): wrong help; syntax confusion :-). * S-inf.el (inferior-S): moved the setting of the history file. * S.el: inferior-S-program should be global? Sun Apr 20 12:30:36 1997 Anthony Rossini * S-inf.el: moved S-force-buffer-current here, from S-mode. * S.el: (S-version-running): buffer-local. (inferior-S-program): buffer-local. (inferior-S-secondary-prompt): buffer-local. (inferior-S-primary-prompt): buffer-local. * S-site.el (S-transcript-mode): change autoload to point at S-trans. Fri Apr 18 12:01:59 1997 Anthony Rossini * S-site.el: removed stupid comments, rearranged autoloads sensibly. * S-inf.el: Moved `eval-*' commands here from S-mode. Edited autoloads appropriately (must be a better way to deal with the bytecompiler and file/function synchronization!) * S-mode.el: Moved `eval-*' commands to S-inf. Thu Apr 17 12:58:34 1997 Anthony Rossini * S.el (S-mode-font-lock-keywords): changed ("<-" . font-lock-reference-face) to ("< * S-trans.el: removed byte-compiler errors. * S-mode.el (S-indent-exp): commented out, in "let", restart and last-sexp. * S-inf.el (S-eval-visibly): See: "Terrible Kludge". This code needs to be "done right (tm)". Last byte-compile problem... :-(. (S-get-process-variable): removed let (not needed?) (S-set-process-variable): removed let (not needed?) * S.el: run-hooks 'S-mode-load-hook before provide 'S. (S-mode-version): update the version. * S-help.el: added autoloads for bytecompile (need to find a cleaner way). Tue Apr 8 06:32:20 1997 Anthony Rossini * S-mode-4.9-b3 RELEASED. * S-site.el (R): use the previously defined variable. (S): use the previously defined variable. (XLS): use the previously defined variable. * S.el (inferior-S-program): changed definition. (inferior-S-program-name): new. (inferior-R-program-name): new. (inferior-XLS-program-name): new. (inferior-S4-program-name): new. * General: put back GNU. But need to check this! * General: removed "FSF GNU" from all files. It's not kosher. Mon Apr 7 07:52:49 1997 Anthony Rossini * S-inf.el (get-S-process): moved to prevent byte-compiler warnings. * S.el: moved user/sys vars from S-mode.el/S-inf/S-help (font-lock): added require. * S-help.el: moved user/sys vars to S.el. * S-site.el: removed (require 'font-lock). * S-mode.el: moved user/sys vars to S.el. * S-inf.el: moved requires and eval-when-compile requires. * S-site.el: moved XLS, R, S here from S-inf. Added local vars at end. Edited commented-out documentation. * S-inf.el: moved XLS, R, S to S-site (XLS, R, S): S0 -> inferior-S (inferior-S): Renamed from S0. * S.el: Documentation cleaned, modified. Old news moved to NEWS files. (S-mode-version): variable updated (wasn't, before. Whoops!) * S-mode-4.9-b2 RELEASED * S.el : removed autoloads (and duplicates) for the modes and inferior processes (which were and are in S-site). * S.el : Commentary: deferred installation instructions to README and S-site. Removed comint stuff, since present in 19.x emacsen. * S.el (S-local-process-name): variable, not a constant. * S-site.el: Added R-mode autoload. * README: query-rep'd "4.8" to "4.9". * S-mode.el (S-mode-map): S-parse-errors binding changed to C-c` Sun Apr 6 14:23:45 1997 Anthony Rossini * S-inf.el (inferior-S-make-comint): S-inf-pager -> inferior-S-pager. * S-site.el (XLS): added XLS autoload. * S-inf.el (inferior-S-make-comint): replaced with Kurt's version (I need to verify this). (inferior-S-pager): New variable. Fri Apr 4 10:38:26 1997 Anthony Rossini * S-mode-4.9-b1 RELEASED * S-site.el: added R as an autoload. * S-inf.el (inferior-S-mode): Added a switch (based on S-proc-prefix) for using inferior-S-input-sender or inferior-R-input-sender. * S-inf.el (inferior-R-input-sender): added (thanks to KH). * S-mode.el (S-eval-paragraph): added. (from S-extras). * S-extras.el: removed S-eval-paragraph * Makefile: More in line with GNU standards. Still WRONG, though. Thu Apr 3 14:38:09 1997 Anthony Rossini * S-help.el: Support for W3 viewing of R files is included. It works (but could be better). Removed until 5.0 :-). * S.el (S-proc-prefix): Moved before S-history-file definition, which now depends on it. * S-help.el (S-submit-bug-report): send to rossini@stat.sc.edu * S-inf.el (inferior-S-mode-map): C-x` should be C-c` (S-parse-errors). Major modes NEVER use C-x prefixes! (inferior-S-mode-map): C-c C-a masks a useful function in comint. Need to find a second prefix for "hotkeys". * S-inf.el (S-object-name-db-file): added variable. (S-create-object-name-db): Use S-object-name-db. * S-inf.el (inferior-S-mode): Changed comint-completion-addsuffix definition, and made buffer-local (thanks: Kurt Hornik). * All_files : S-filenames-map is final name. (-p for functions. Bozo...). * S-inf.el (inferior-S-font-lock-keywords): changed variable name from S-inf-font-lock-keywords. (inferior-S-mode): changed variable name to inferior-S-font-lock-keywords from S-inf-font-lock-keywords. * S-modeadds.el (S-mode-load-hook): changed name of S-inf-filenames-map to S-filenames-map-p * S-inf.el (S-dir-modtime): changed name of S-inf-filenames-map to S-filenames-map-p (S-object-names): changed name of S-inf-filenames-map to S-filenames-map-p * S-mode.el (S-check-modifications): changed name of S-inf-filenames-map to S-filenames-map-p * S-inf.el: removed S-inf-filenames-map defvar. * S.el: Moved S-inf-filenames-map defvar here, renamed as S-filenames-map-p. Wed Apr 2 09:38:47 1997 Anthony Rossini * TODO: updated ALL conversations and reasonings. * Makefile: removed extraneous commented-out parts. Changed Prefloads, default Emacs, compilation flags, and infodir location. * S-mode.el (S-dump-object): added indent-region (thanks: Peter Dalgaard, ). * S-mode.el : changed default for S-else-offset to 0 (thanks: Peter Dalgaard, ). Mon Mar 10 11:30:23 1997 Anthony Rossini * General : moved the rest of the easymenu startup code here * General : edited Makefile for easier XEmacs distribution * S-site.el : added example Splus call (thanks: Claudia Yastremiz ) Fri Mar 7 17:42:36 1997 Anthony Rossini * S-trans.el : For easymenu menus, moved code from S-menu here. * S-mode.el : For easymenu menus, moved code from S-menu here. * S-inf.el : For easymenu menus, moved code from S-menu here. * Added code from Kurt H. Mon Feb 10 11:14:42 1997 Anthony Rossini * S-help.el : added/checked some of Martin's older patches (most in the 4.8.6 series). * Makefile (patch): added $(GZCAT) (normally zcat, but sometimes it's gzcat, if sys admins are GNU-suspicious). * S-mode.el: XEmacs compatibility, maintaining Emacs compatibility. * S-inf.el: See above. * S-trans.el: See above. * S-menu.el: added easymenu support, XEmacs menu hooks. Mon Oct 14 16:24:14 1996 Local * S-inf.el: inferior-S-program -- only new if S <--> R Tue Jun 25 08:53:12 1996 Martin Maechler * S-inf.el: (defun R ...); renamed 'S to 'S0; S, R both call S0 after setting variables. * S.el: added autoloads for 'R and 'R-mode. defconst for S-help-S... and S-help-R used in S-inf. * S-site.el: same autoloads * S-help.el : S-help-sec-regex,etc: defconst for S- and R- versions moved to S.el, since used in S-inf * S-mode.el (R-mode): added S-force-buffer-current: optional 2nd arg. 'force' Mon Dec 4 1995 -- Wed May 29 1996 Martin Maechler * S.el: Fixed the syntax-table entry which broke 'beg.-of-function'. New variable S-proc-prefix (for using "R" and "S" simultaneously). * S-inf.el: S-synchronize-evals -> NIL (finally!). S-proc-name : Use new variable S-proc-prefix instead of hardwired "S"; the same for other places. S-execute-search: Use new variable inferior-S-search-list-command Switched binding of C-c C-k to S-force-buffer-current. Fixed LONG-STANDING bug in S-eval-region (when >= 2 S-processes) now using (get-S-process ...) instead of hardwired "S". * S-help.el: added S-eval-line-and-next-line to key bindings. Changed binding of request-a-process to C-c C-k as in other S-modes. New configurable variable S-help-sec-regex (for R help) * Makefile: texi, not texinfo; support for non-GNU tar; minor.. Mon Dec 4 1995 -- Wed May 29 1996 Martin Maechler * S.el: Fixed the syntax-table entry which broke 'beg.-of-function'. New variable S-proc-prefix (for using "R" and "S" simultaneously). * S-inf.el: S-synchronize-evals -> NIL (finally!). S-proc-name : Use new variable S-proc-prefix instead of hardwired "S"; the same for other places. S-execute-search: Use new variable inferior-S-search-list-command Switched binding of C-c C-k to S-force-buffer-current. Fixed LONG-STANDING bug in S-eval-region (when >= 2 S-processes) now using (get-S-process ...) instead of hardwired "S". * S-help.el: added S-eval-line-and-next-line to key bindings. Changed binding of request-a-process to C-c C-k as in other S-modes. New configurable variable S-help-sec-regex (for R help) * Makefile: texi, not texinfo; support for non-GNU tar; minor.. Wed Dec 13 17:27:53 1995 David M Smith * S-inf.el (S-search-list): Would return nil if S-search-list was nil and the search path had not changed (which could happen, apparently) Mon Dec 4 10:21:52 1995 David M Smith * S.el: New syntax table. * S-trans.el: New bindings. * S-mode.texi: Updates for 4.8 * S-mode.el: Autoload and bind S-list-object-completions. S-request-a-process moved to C-c C-k. S-force-buffer-current: new function * S-menu.el: Many updates. * S-inf.el: S-object-list: docstring update S-directory is now used as the default S directory. The current buffers default directory is used if it is nil. get-S-process: better error message. inferior-S-mode: Use comint-input-filter-functions instead of the deprecated comint-input-sentinel. Don't anchor paragraph regexps. S-list-object-completions: new function S-modtime-gt: bugfix S-complete-filename: don't use comint-last-inout-start * S-help.el: Make autoloads from S-inf.el. * Makefile: Deleted useless SCRATCH vbl. Use S-mode.texi, not S-mode.texinfo. Thu Nov 30 13:10:17 1995 David M Smith * Makefile: Version update Mon Nov 13 14:46:13 1995 David M Smith * S.el (S-mode-syntax-table): Made syntax table independent of c-mode-syntax-table * S-mode.el (S-check-modifications): Changed regexp to allow `w' and `_' class syntax in object names Wed Aug 23 16:37:10 1995 David M Smith * S-inf.el (S-complete-filename): Checked form the beginning of the *last* command to determine if we should complete a filename. History expansions work now. Mon Aug 21 15:35:29 1995 David M Smith * S-menu.el (S-transcript-mode-menu): New menu (S-inferior-S-mode-menu): Lotsa updates. * S-trans.el (S-transcript-copy-command): Renamed from S-transcript-copy-commmand (mmm). Also switches to the S process. (S-trans-font-lock-keywords): strings keep other highlighting Lots of autoloads for S-mode.el stuff * S-help.el: Autoloads for stuff in S-mode.el Tue Aug 8 11:06:43 1995 David M Smith * S-mode.el (S-dump-object-into-edit-buffer): Run a lambda S-source-directory in the process buffer (S-dump-object-into-edit-buffer): As for process if none attached * S-inf.el (S): Use default-directory only if S-directory is nil. * S.el (S-directory): Doc update * S-inf.el (S-modtime-gt): Fixed to give correct results (inferior-S-mode): Add S-search-path-tracker to comint-input-filter-functions, not comint-input-sentinel. Tue Aug 1 16:13:14 1995 David M Smith * S-inf.el (inferior-S-mode): Don't anchor paragraph-start and paragraph-separate with "^" (for 19.29). Tue Aug 1 14:44:32 1995 David M Smith * S-mode.el (S-eval-region): Make sure S-local-process-name is set. * S-inf.el (get-S-process): Better error message when no processes are running. * S-mode.el (S-eval-region): Make sure S-inf is loaded Thu Jul 27 16:43:01 1995 David M Smith * S-inf.el (S-list-object-completions): New function (inferior-S-mode-map): Bind it to M-? Tue Jul 25 16:07:10 1995 David Smith * Version 4.7 released. * Makefile (info): New target (install): Ignore errors in second cp in case LISPDIR==. (clean): Junk all the tex crap, too (VERSION): New variable (distrib): Use it (AUXFILES): Include ChangeLog (distrib): Make sure Makefile is writeable * S-inf.el (S-execute-screen-options): Added documentation. (S-multi): Use S-post-run-hook * S.el (S-keep-dump-files): Expanded documentation. (S-delete-dump-files): Expanded documentation. (S-post-run-hook): New variable. Mon Jul 24 11:58:22 1995 David M Smith * S.el: Default for S-keep-dump-files is 'check * S-mode.el (S-mode): Make S-keep-dump-files buffer-local. (S-load-file): Meaningful values of S-keep-dump-files are nil, check, ask and anything else. (S-dump-object): If S-keep-dump-files is 'check, don't ask for confirmation when loading. * S-mode.el (S-dump-object-into-edit-buffer): Bug-fix; you can now create the Src directory if it doesn't exist. * S-site.el (window-system): Only add turn-on-font-lock to mode hooks if window-system is non-nil. Also add to S-transcript-mode-hook. Thu Jul 20 12:21:43 1995 David M Smith * S-inf.el (S-inf-font-lock-keywords): Strings in input don't de-fontify anymore. Wed Jun 28 12:15:57 1995 David M Smith * S-mode.texinfo: Updated e-mail addresses, and used @@ instead of @. * S-mode.el (S-mode): Use S-mode-font-lock-keywords, not S-inf-font-lock-keywords Mon Jun 26 12:14:10 1995 David M Smith * Version 4.6 released * TODO, S-mode.texinfo, NEWS, Makefile: Update for 4.6 Mon Jun 26 12:09:55 1995 David M Smith * S-trans.el: Font-lock support. * README: Update for 4.6 * S.el: Version update: 4.6 S-local-process-name added. * S-site.el: Deleted hilit19 patterns (font-lock patterns are now in the individual source files). S-site should now be much more lightweight to load. Used add-to-list for the load-path. .s for S-mode files in auto-mode-alist by default. * S-mode.el: Font-lock support. Fri Jun 23 13:56:54 1995 David M Smith * S-inf.el: Doesn't call comint-output-filter-functions in S-eval-visibly any more (and so works in 19.29). Font-lock support. Bound M-RET to S-transcript-send-command-and-move. Wed Oct 26 12:37:15 1994 David M Smith * S-mode.el (S-check-modifications): Fixed a bug which occurred when the object name could not be found. Tue Oct 25 16:28:54 1994 David M Smith * S-inf.el: Moved S-local-process name to S.el. (S-eval-visibly): Bugfix involving comint-last-output-end Wed Jun 1 11:03:34 1994 David M. Smith (maa036@mathssun5) * Version 4.5 released. * Makefile: Update to distrib target * Makefile: Bugfix with info install * README: Update for 4.5 * NEWS: *** empty log message *** Wed Jun 1 10:29:30 1994 David M. Smith (maa036@mathssun5) * S-menu.el: Bugfix Mon May 30 16:34:53 1994 David M. Smith (maa036@mathssun5) * S-site.el: Major revision. * README: More detail in INSTALL section. * TODO: Initial revision * S.el: Version number update: 4.5 * Makefile: Bugfix in SOURCES * Makefile: added S-mode.texinfo to AUXFILES * Makefile, NEWS, README: Initial revision Fri May 27 17:18:50 1994 David M. Smith (maa036@mathssun5) * S-mode.el, S-trans.el: Binding changes * S-help.el: Binding change * S.el: Define S-help as an alias for S-display-help-on-object. * S-inf.el: S-view-at-bottom: deleted function and keybinding Changed bindings of S-display-help-on-object and S-execute. * S-menu.el: Many modifications to S-inferior-S-mode-menu, including incorporation of the old hotkey menu. * S.el: Autoload for S-load-file. * S-help.el: S-submit-bug-report: new function * S.el: Added autoloads for S-dump-object-into-edit-buffer and S-parse-errors. * S.el: Added an autoload for S-submit-bug-report * S-mode.el: Added a provide call. Can't imagine why it wasn't there before. * S-mode.texinfo: Initial revision Fri May 13 09:57:00 1994 David M. Smith (maa036@mathssun5) * S.el: Version number update: 4.4 * S-inf.el: bugfix * S-inf.el: S-compiled-dir: new function S-object-names: support it * S-inf.el: Support for S-object-name-db. S-object-names: modified S-get-words-from-vector: new function S-create-object-name-db: new command Wed May 11 14:18:27 1994 David M. Smith (maa036@mathssun5) * S-trans.el: Defined S-transcript-send-command-and-move * S-menu.el: Dunno. Fri Apr 29 14:30:55 1994 David M. Smith (maa036@mathssun5) * S-mode.el: S-continued-statement-p: minor bugfix. Removed the (bolp) test; I don't know why it was there but it caused top-level statements to be indented. S-insert-local-variables: removed (obsolete) * S-mode.el: S-dump-object-into-edit-buffer: rewrite. Implemented S-delete-dump-files. S-dump-object: new function S-find-dump-file-other-window: new function * S.el: New option S-delete-dump-files * S.el: Version number change (4.3) Thu Apr 28 12:58:41 1994 David M. Smith (maa036@mathssun5) * S-mode.el: Definition and implementation of S-mode-silently-save. Fri Apr 22 14:40:56 1994 David M. Smith (maa036@mathssun5) * splitup2/S-inf.el (S-get-directory): Cause an error if an invalid directory is specified. Wed Mar 16 14:19:31 1994 David M. Smith (maa036@mathssun5.lancs.ac.uk) * splitup2/S-inf.el (inferior-S-primary-prompt): prompts are optionally followed by one space. (S-complete-object-name): No longer runs indent-for-tab-command (S-after-pathname-p): deleted (S-complete-filename): New function (inferior-S-mode): Better completion support, thanks to the new comint. Wed Feb 23 15:50:28 1994 David M. Smith (maa036@mathssun5.lancs.ac.uk) * splitup2/S-inf.el (S-search-list): Bugfix where relative pathnames in search list were expanded in wrong directory Fri Feb 18 19:27:10 1994 David M. Smith (maa036@mathssun5.lancs.ac.uk) * splitup2/S-mode.el (S-check-modifications): Don't cause an error if the source file has been deleted. Tue Feb 15 12:11:42 1994 David M. Smith (maa036@mathssun5.lancs.ac.uk) * splitup2/S-inf.el (S-temp-buffer-p): Deleted. There is no longer any dependence on this variable: S-local-process-name suffices. (S-local-variables-string): Deleted. File extensions should be good enough for setting the mode. (S-cleanup): Simplified. Doesn't delete files. * splitup2/S-help.el (S-help-mode): Make S-local-process-name local. * splitup2/S-mode.el (S-mode): make S-local-process-name permanent-local. (S-insert-function-templates): deleted, S-function-template has this functionality now. (S-function-template): May be nil or a string. Point is placed after first open. (S-dump-object-into-edit-buffer): If S-keep-dump-files is nil, don't delete files, but don't make backups either. Mon Feb 14 14:53:17 1994 David M. Smith (maa036@mathssun5.lancs.ac.uk) * splitup2/S-mode.el (S-check-modifications): New function (S-load-file): Rewrite. Only ask for a filename if the current buffer is not in S-mode. Always offer to save. * splitup2/S-inf.el (S-inf-filenames-map): New variable (S-object-names): Use it (S-extract-onames-from-alist): Supply directory name (S-get-modtime-list): Supply directory name for quicker completions (S-object-modtime): New function (S-modtime-gt): New function Fri Feb 11 14:49:29 1994 David M. Smith (maa036@mathssun5.lancs.ac.uk) * splitup2/S-mode.el (S-mode): Set parse-sexp-ignore-comments to t; there are no longer any limitations with this in elisp. Wed Feb 9 13:25:12 1994 David M. Smith (maa036@mathssun5.lancs.ac.uk) * splitup2/S-trans.el (S-transcript-send-command-and-move): New function (S-transcript-send-command): Doesn't move any more. * splitup2/S-inf.el (S-eval-visibly): Call comint-output-filter-functions Wed Jan 26 11:15:46 1994 David Smith (maa507@mathssun5.lancs.ac.uk) * S.el (S-search-list): Caches result in S-search-list (S-execute-objects): Use it (S-search-list ): Now just a cache. Don't access directly Completions are now calculated on demand; as a result the first completion in a session will take a long time. The results are cached, however, so remaining completions should be fast. Sun Jan 23 17:56:46 1994 David Smith (maa507@mathssun5.lancs.ac.uk) * S.el (S): If S-ask-for-S-directory is unset, set default-directory to S-directory. Wed Jan 19 16:16:10 1994 David Smith (maa507@mathssun5.lancs.ac.uk) * S-site.el: Added (cond (window-system ...)) calls so that all users (even those without window systems) can safely require this file. Thu Jan 6 15:15:53 1994 David Smith (dsmith@spam.maths.adelaide.edu.au) Version 4.1alpha released to wingra * S.el: deleted S-set-display and associated variables. Fri Dec 24 11:56:00 1993 David Smith (dsmith@spam.maths.adelaide.edu.au) * S.el (S-command): Rewrite. Now uses a new filter to redirect output to the buffer; comint never sees the output. This filter could feasibly be accommodated to detect the prompt itself; allowing for an "in the background" implementation of S-command. (S-process-sentinel): Reports date; useful if you have run many S sessions in one transcript file. Thu Dec 16 12:47:38 1993 David Smith (dsmith@spam.maths.adelaide.edu.au) * S.el (S-multi): Ask for transcript file, maybe (S-ask-about-transfile): new variable (S-get-directory): replaces S-set-directory Wed Dec 15 12:10:11 1993 David Smith (dsmith@spam.maths.adelaide.edu.au) * S.el (S-loop-timeout): Increased Mon Dec 13 10:11:25 1993 David Smith (dsmith@spam.maths.adelaide.edu.au) * S.el (S-command): Avoids calling comint-output-filter-functions until the last minute. (S-complete-object-name): Complete rewrite of completion routines. Completion should now be accurate in every situation: the only way to make it wrong is to use assign() to assign into a dataframe not at position 1. Uses objects() to make listings, so you don't get .Data, .Help etc. Should now be able to make this work for DOS users. (S-object-list): New buffer-local vbl; cache of completions Thu Dec 9 12:08:09 1993 David Smith (dsmith@spam.maths.adelaide.edu.au) * S.el (S-process-sentinel): Can now see message after q() Tue Nov 16 09:25:41 1993 David Smith (dsmith@spam.maths.adelaide.edu.au) * S.el (S-mode): kill-all-local-variables (S-insert-local-variables): Use ### instead of # in local variables section. Mon Nov 15 10:31:02 1993 David Smith (dsmith@spam.maths.adelaide.edu.au) * S.el (inferior-S-mode): Changed comint-after-partial-pathname-command to comint-after-partial-filename-command (new comint) Sun Nov 14 17:18:55 1993 David Smith (dsmith@spam.maths.adelaide.edu.au) * S.el: Version 4.00alpha. Made available for FTP, and announced on the S-mode mailing list Fri Nov 12 12:36:06 1993 David Smith (dsmith@spam.maths.adelaide.edu.au) * S.el (S-transcript-mode): Created. (S-execute-screen-options): Added. Thu Nov 11 12:30:06 1993 David Smith (dsmith@spam.maths.adelaide.edu.au) * S.el (S-find-help-file): More intuitive defaults when requesting help generated by S-read-helpobj-name-default. (S-eval-visibly): Doesn't wait for prompt after the last line of text has been sent. (inferior-S-send-input): Big improvement in the handling of multi-line inputs. Users should use LFD (not RET) to continue incomplete commands. Should automate this. Thu Oct 7 14:45:00 1993 David Smith (dsmith@spam.maths.adelaide.edu.au) * S.el (inferior-S-mode): Few mods to make it work with the new comint. Mon Sep 27 11:21:56 1993 David Smith (dsmith@spam.maths.adelaide.edu.au) * S.el (inferior-S-get-old-input): Now separates multi-line commands by newlines instead of spaces. This produces messier output, but avoids S's 255 char line limit for commands. Sun Sep 26 17:38:59 1993 David Smith (dsmith@spam.maths.adelaide.edu.au) * S.el (S-kill-buffer-function): Added to kill-buffer-hook in the process buffer. Fri Sep 17 11:23:36 1993 David Smith (dsmith@spam.maths.adelaide.edu.au) * S.el (S-display-temp-buffer): Uses temp-buffer-show-function instead of popper. (inferior-S-mode): Fixed a typo of paragraph-separate appearing as paragraph-start. Wed Sep 15 11:47:51 1993 David Smith (dsmith@spam.maths.adelaide.edu.au) * S.el: Converted old E18 variables (buffer-flush-undo, comment-indent-hook) to E19 versions. Removed the require for comint-extra -- now contained in the new comint.el. Removed autoload for comint-isearch -- that's the user's decision. (inferior-S-prompt): Now generated from inferior-S-primary-prompt and (new variable) inferior-S-secondary-prompt Tue Sep 14 09:33:03 1993 David Smith (dsmith@spam.maths.adelaide.edu.au) * S.el (S-multi): Makes use of Simon Marshall's new comint.el. New variable S-history-file for saving histories. Calls comint-read-input-ring. Sets the sentinel. (S-process-sentinel): Created. Automatically saves the history ring if the S process dies. Sun Sep 12 18:53:40 1993 David Smith (dsmith@spam.maths.adelaide.edu.au) * S.el: (S-multi). Now always switches to the buffer associated with process N, if available. (inferior-S-make-comint): New calling procedure; bufname is the literal buffer name (no *'s are added); procname is the process name to use. Tue Sep 7 16:20:11 1993 David Smith (dsmith@spam.maths.adelaide.edu.au) * S.el (inferior-S-mode-map): Unbound comint-[mp]search input, and comint-isearch, as I haven't tested them yet. (inferior-S-mode): replaced input-ring-size with comint-input-ring-size (Vivek Khera ). * comint-extra.el: Added comint-msearch* and comint-psearch*, commented out in the E19 distribution of comint.el * comint-isearch.el: Back in the distribution Fri Sep 3 16:20:28 1993 David Smith (dsmith@spam.maths.adelaide.edu.au) * S.el (S-mode): Replaced the documentation string, and removed the code which set it explicitly. Doing this was breaking the byte compiler. Version 3.63 Wed Aug 25 17:36:57 1993 David Smith (dsmith@spam.maths.adelaide.edu.au) * S.el (inferior-S-send-input): Added a hook: S-send-input-hook, so that I could do nice things with highlighting. This will probably disappear or change. Sat Aug 14 14:48:11 1993 David Smith (dsmith@spam) * S.el (S-extract-onames-from-alist): Modified so that S-complete-object-name will work in the minibuffer (e.g. through command S-execute.) * S.el: Restructured the entire S.el file into meaningful sections. The file now uses Outline mode. * S.el: Tek mode is no longer supported. Moved all Tek-related variables and functions to S-tek.el, and commented out any code references to them. * S-tek.el: This file is no longer supported. Moved all Tek-related functions and variables in S.el to the end of this file. Wed Aug 4 16:35:24 1993 David Smith (dsmith@spam) * S.el (S-complete-object-name): Fixed regexp so that completion over lists works properly. Thu Jul 22 12:25:46 1993 David Smith (maa507@mathssun4) * S.el: Uses s-menu instead of s-simple-menus. * s-menu.el: Totally rehacked from s-simple-menus.el to use easymenu.el, to take advantage of Emacs 19 menus. * S.el: Rehacked the multiple process code so that local variables are used to store process-specific variables. I really don't know why I didn't do this in the first place. As a result multiple processes actually seem to work, now. (S-request-a-process): Now enters initial input Sun Jul 18 12:15:27 1993 David Smith (maa507@mathssun4) * S.el: Created this change log file, and moved the change log from S.el here. The following is from the original Changelog section of S.el Release 2.1 on October 14, 1991 to statlib@stat.cmu.edu, and to the elisp archives at OSU (brennan@dg-rtp.dg.com (Dave Brennan)) and announced on internet.s-news, netnews.gnu.emacs.sources, & andrew.programs.S ------------------------------------------------------- Jul 26 1991 Frank Ritter * added S-mode-load-hook & S-pre-run-hook and testing by neilc@research.att.com Jul 9 1991 Frank Ritter * Changed S-command to use a register rather than the kill ring. * Better file header, comments now at 60 col so mailers wont' eat them. * Better S-extract-word-name. * Added S-mode-version variable * Changed syntax table to read |#; appropriately Wed Nov 28 11:03:50 1990 Ed Kademan (kademan at hermes) * Make the S-mode-syntax-table a slightly modified version of the c-mode-syntax-table instead of a version of the one for lisp. Sat Nov 10 12:41:52 1990 Ed Kademan (kademan at hermes) * Made run-S and run-s commands synonymous with the function S. Fri Oct 19 12:41:52 1990 Ed Kademan (kademan at hermes) * Made S-directory a user modifiable variable. S will run from that directory. Thu Oct 18 12:41:52 1990 Ed Kademan (kademan at hermes) * Added function S-nuke-help-bs to clean up nroff style text in the S help buffer. This function is a modification of nuke-nroff-bs from man.el. ------------------------------------------------------- Unnumbered version released dated Thu Jun 14 09:56:56 CDT 1990 Fri Jan 17 1992 Dave Smith (dsmith@stats.adelaide.edu.au) * Help mode for reading files. When asking for an object to run help on, completion is over those help files that exist. * Added object name completion, and made S-get-object-list efficient enough to make it worthwile. * Error parsing for loaded files * Better customization of file-names, with sensible defaults * Sensible buffer names for object buffers * Corrected definition for `.' in syntax table * Improved (and simplified) S-read-object-name-default * Included pager='cat' to default help-command specification * Added a call to run-hook for S-pre-run-hook * Changed keymaps to conform with GNU guidelines (i.e. no \C-letter bindings) * S-command has a new third argument, visible Tue May 27 1992 Dave Smith (dsmith@stats.adelaide.edu.au) * now copes with dynamically changing prompts (reported by Doug Bates) Thu May 29 1992 Dave Smith (dsmith@stats.adelaide.edu.au) * Added S-execute, modified S-execute-* to use it. Mon Jun 22 1992 dsmith * Added S-mode editing commands written by Ken'ichi Shibayama (shiba@isac.co.jp). A big win. * Removed the redundant argument to S-switch-to-end-of-S * S-function-pattern improved * added S-eval-visibly, S-eval-visibly-p and modified S-eval-* to use them * added S-eval-line-and-next-line * eval commands can now echo in the process buffer * added S-kill-output and S-view-at-bottom * added a binding for comint-isearch and autoloaded it * added S-execute-in-tb. S-parse-errors now takes prefix arg. Thu Jun 25 1992 dsmith * Moved some doctrings to comments (Frank Ritter) * The Tek stuff now lives in a separate file (Frank Ritter) * Fiddly C-c ESC M-. bindings in S mode and Help mode moved to C-c M-. bindings (Martin Maechler) * S-execute-objects now uses variable inferior-S-objects-command whose value depends on S version. (Ken'ichi Shibayama) * Symbols given uniform prefixes: S- or inferior-S- (Frank Ritter) -- Version 3.41 released to Statlib and Emacs Archive -- Tue Jul 7 11:56:59 CST 1992 dsmith * S-execute-attach now updates the internal search list. This is a manifestation of a general bug: S-command doesn't call S-search-path-tracker Wed Jul 29 09:38:54 CST 1992 kenichi * Several fixes to indenting code. New variable S-else-offset. Indentation of code not within braces. expression() indentation. Correct handling of in-line comments. Fri Aug 7 10:52:06 CST 1992 dsmith * S-execute now uses S-mode-minibuffer-map. * Setting indentation variables in .emacs now has some effect. * Files retrieved by S-dump-object-into-scratch are now automatically placed in S-mode. Fri Jul 28 1992 R.D.Ball added multi-S to allow multiple S sessions run by ESC-x S or with numeric prefix arg e.g. ESC-2 ESC-x S The current S process is determined by S-process-name, this is modified by typing a return into a non-current S process buffer. Variables S-process-name-list, S-current-process-name and functions update-S-process-name-list, get-S-process to replace (get-process "*S*"), and checks for existence of process, buffer in inferior-S-mode made function S-eval-line-and-next-line keep to the bottom of the S process buffer so user can see results when working interactively To do this an optional arg eob was added to S-eval-visibly To go to bottom of window it was necessary to use switch-to-buffer-other-window, but this only when eob is t. Additionally, if S-eval-visibly-at-end is t the functions S-eval-region etc. also display results at the end of the current process buffer. Default directory for starting S is now the current directory for the current buffer. (Set S-use-current-directory to nil to avoid this). Sat Sep 19 18:35:10 CST 1992 dmsith * Modified Rod's multi-S code so that it works properly. S-process-name-list is now an alist whose CARs are the process names and whose CDRs is an alist of variable . value pairs specific to particular processes (so e.g. completion works properly for each buffer.) The function S-get-process-specific-vbls does the work, and any process-specific variables should be mentioned here. S-mode buffers know which process they should evaluate into. * New command S-request-a-process which should be bound to a key. Wed Nov 4 dsmith * S-load-file now informs you if S gave a warning during load. Also, the S-errors buffer is displayed using popper, if available * C-x ` is now also bound in S-mode. * Installed Frank's menus Wed Nov 18 dsmith * Bound M-TAB and M-? to comint completion functions in inf-S-mode and S-mode * In the process buffer, a paragraph is a promwpt, a command and its output, to make the paragraph functions useful * Multiple S sessions in a process buffer are delimited by ^L, to make the page functions useful * In process buffer mode line, name of process is shown in [..] (in case buffer name is changed.) In edit buffers, the name if the process the buffer belongs to is shown in []'s Wed Nov 21 dsmith * Nuked S-make-function, since it is now obsolete * Added S-clean-region * M-TAB in S-mode now completes *files*, not objects. Object completion has moved to C-c TAB. * Bound k in the help buffer to 'kill-buffer. * Local variables are added to files accessed with C-c C-d, if needed. * Fixed incorrect use of 'save-buffer in several places. * Bound C-c C-p to 'S-request-a-process * Replaced S-beginning-of-function and S-end-of-function to DMS's versions, since Frank's don't work with the new function regexp. * New variable S-synchronize-evals (Martin Maechler) * Changed default of S-eval-visibly-p to t. Wed May 12 dmith * Change definition of S-dumped-missing-re to cope with 3.1 ESS-24.01.1/Makeconf000066400000000000000000000076001455642170100137670ustar00rootroot00000000000000## To install ESS for all users on your unix system: ## 1. Check variables below, edit as necessary ## 2. make ## 3. make install ## Section 1 ## Installation variables for your Emacs variant ## ## Variable Description ## EMACS Path to GNU Emacs ## EMACSBATCH How to run Emacs as batch ## SITELISP Destination of site-lisp ## ESSDESTDIR Destination of ESS DESTDIR ?= /usr PREFIX ?= $(DESTDIR) ##__ GNU Emacs __ EMACS ?= emacs SITELISP ?= $(PREFIX)/share/emacs/site-lisp ESSDESTDIR ?= $(SITELISP)/ess EMACSBATCH ?= $(EMACS) -batch -Q # ##__ GNU Emacs __ preparing for a emacs 29.1 "ESS" release # DESTDIR = /usr/local # PREFIX = $(DESTDIR) # EMACS = $(PREFIX)/emacs/29.1/bin/emacs # SITELISP = $(PREFIX)/emacs/29.1/share/emacs/site-lisp # ESSDESTDIR = $(SITELISP)/ess # EMACSBATCH = $(EMACS) -batch -Q ##__ GNU Emacs __ for macOS # PREFIX=/Applications/Emacs.app/Contents/Resources # EMACS=/Applications/Emacs.app/Contents/MacOS/Emacs # SITELISP=$(PREFIX)/site-lisp # LISPDIR=$(SITELISP)/ess # INFODIR=/usr/local/info # ETCDIR =$(PREFIX)/etc/ess ##__ Vincent Goulet's Modified Emacs __ for macOS ## site-lisp is empty: payload is in lisp directory # PREFIX=/Applications/Emacs.app/Contents/Resources # EMACS=/Applications/Emacs.app/Contents/MacOS/Emacs # SITELISP=$(PREFIX)/lisp # LISPDIR=$(SITELISP)/ess # INFODIR=/usr/local/info # ETCDIR =$(PREFIX)/etc/ess ##__ GNU Emacs with Homebrew __ for macOS ## site-lisp is not within .app directory # PREFIX=/Applications/Emacs.app/Contents/Resources # EMACS=/Applications/Emacs.app/Contents/MacOS/Emacs # SITELISP=/opt/homebrew/share/emacs/site-lisp # LISPDIR=$(SITELISP)/ess # INFODIR=/usr/local/info # ETCDIR =$(PREFIX)/etc/ess ##__ Aquamacs __ (donated by Dan Knoepfle, Mar 26, 2011) # PREFIX=/Applications/Aquamacs.app/Contents/Resources/lisp/aquamacs/edit-modes # EMACS=/Applications/Aquamacs.app/Contents/MacOS/Aquamacs # SITELISP=/Applications/Aquamacs.app/Contents/Resources/lisp # LISPDIR=$(PREFIX)/ess-mode/lisp # INFODIR=/Applications/Aquamacs.app/Contents/Resources/info # ETCDIR=$(PREFIX)/ess-mode/etc ## COMPILE-FLAGS is set in tests COMPILE ?= $(EMACSBATCH) $(COMPILE-FLAGS) --directory . --directory ./obsolete -f batch-byte-compile COMPILE-SIMPLE ?= $(EMACSBATCH) --directory . --directory ./obsolete -f batch-byte-compile ## Section 2 ## Installation variables for your unix variant ## ## Variable Description ## MAKEINFO program to convert .texi{nfo} to .info ## MAKEHTML program to convert .texi{nfo} to .html ## MAKETXT program to convert .texi{nfo} to .txt ## INSTALLDIR to create directories, if necessary ## INSTALL to copy files, file copying commands expect 2 args: ## 1st) source-file & 2nd) target-directory ## UNINSTALL deletes all arguments ## DOCDIR Destination of other doc files ## DOWNLOAD Download internet file to stdout MAKEINFO ?= LC_ALL=C LANG=en makeinfo MAKEHTML ?= $(MAKEINFO) --html --no-split --css-include=atouchofstyle.css -o MAKETXT ?= $(MAKEINFO) --no-validate --plaintext --no-split -o - INSTALLDIR ?= mkdir -p INSTALL ?= cp -p UNINSTALL ?= rm -f TEXI2PDF ?= LANG=C texi2dvi --pdf DOWNLOAD ?= $(shell which wget > /dev/null && echo 'wget -qO -' || which curl) INSTALLINFO ?= install-info ## Section 3 ## For ESS developers only, not part of installation procedure ## ## Variable Description ## GNUTAR the name of GNU tar to support the z option ## SVN_URL SVN repository URL (repo retired) ## UPLOAD_DIR Martin's upload directory ## ESS_HOMEPAGE Martin's svn co https://svn.r-project.org/ESS-web/trunk ## GNUTAR=tar # SVN_URL = https://svn.r-project.org/ESS UPLOAD_DIR = /u/maechler/emacs/ess-WWW/downloads/ess ESS_HOMEPAGE = /u/maechler/emacs/ESS-web GPG=$(shell (gpg2 --version > /dev/null 2>&1 && echo gpg2 ) || echo gpg ) .SUFFIXES: .i3 .m3 .nw .tex .dvi .html .c .h .el .elc # Local Variables: # mode: makefile-gmake # End: ESS-24.01.1/Makefile000066400000000000000000000153451455642170100137660ustar00rootroot00000000000000## Top Level Makefile ## Before making changes here, please take a look at Makeconf include ./Makeconf ESSVERSION := $(shell cat VERSION) PKGVERSION := $(shell sed -n 's/;; Version: *\(.*\) */\1/p' lisp/ess.el) ESSDIR := ess-$(ESSVERSION) ifneq ($(ESSVERSION), $(PKGVERSION)) $(shell sed -i 's/Version: .*/Version: $(ESSVERSION)/' VERSION) ${shell sed -i 's/;; Version: .*/;; Version: $(ESSVERSION)/' lisp/ess.el} endif ESSR-VERSION := $(shell sed -n "s/;; ESSR-Version: *\(.*\) */\1/p" lisp/ess.el) .PHONY: all all: lisp doc etc autoloads .PHONY: version version: VERSION @echo "********************* VERSIONS **************************" @echo $(shell $(EMACS) --version | sed -n 1p) @echo ESS $(ESSVERSION) @echo ESSR $(ESSR-VERSION) @sed -i "s/\"VERSION\"/\"$(ESSVERSION)\"/" lisp/ess-custom.el @echo "*********************************************************" .PHONY: lisp lisp: version $(MAKE) -C lisp all .PHONY: doc doc: version $(MAKE) -C doc all .PHONY: etc etc: version $(MAKE) -C etc all .PHONY: test test: version $(MAKE) -C test all test-%: version $(MAKE) -C test $* .PHONY: julia julia: @cd lisp; $(MAKE) julia-mode.el .PHONY: autoloads autoloads: cd lisp; $(MAKE) ess-autoloads.el ## Rebuild and publish ESSR package: # 1. Update ESSR-Version in lisp/ess.el # 2. make essr .PHONY: essr essr: VERSION @echo "**********************************************************" @echo "** Making ESSRv$(ESSR-VERSION) **" @sed -i "s/^ *VERSION <- .*/ VERSION <- \"$(ESSR-VERSION)\"/" etc/ESSR/R/.load.R cd etc/ESSR/; ./BUILDESSR; cd - @git add etc/ESSR.rds lisp/ess.el etc/ESSR/R/.load.R git commit -m"ESSR Version $(ESSR-VERSION)" git tag "ESSRv"$(ESSR-VERSION) git push git push origin "ESSRv"$(ESSR-VERSION) install: all mkdir -p $(ESSDESTDIR) $(INSTALL) -R ./* $(ESSDESTDIR)/ uninstall: rm -rf $(ESSDESTDIR) ## the rest of the targets are for ESS developer's use only : .PHONY: tarballs sign-tarballs TARBALLS = ess-$(ESSVERSION).tar ess-$(ESSVERSION).tgz ess-$(ESSVERSION).zip # TODO: ess-plus-$(VERSION).tar tarballs: $(TARBALLS) SIGNED_TARBALLS = $(addsuffix .sig, $(TARBALLS)) sign-tarballs: $(SIGNED_TARBALLS) $(SIGNED_TARBALLS): $(TARBALLS) @echo "Signing $@" $(GPG) -ba -o $@ $< .PHONY: tgz tgz: ess-$(ESSVERSION).tgz ess-$(ESSVERSION).tgz: $(ESSDIR) @echo "** Creating .tgz file **" test -f $(ESSDIR).tgz && rm -rf $(ESSDIR).tgz || true $(GNUTAR) hcvofz $(ESSDIR).tgz $(ESSDIR) .PHONY: zip zip: ess-$(ESSVERSION).zip ess-$(ESSVERSION).zip: $(ESSDIR) @echo "** Creating .zip file **" test -f $(ESSDIR).zip && rm -rf $(ESSDIR).zip || true zip -r $(ESSDIR).zip $(ESSDIR) .PHONY: package package: ess-$(ESSVERSION).tar ess-$(ESSVERSION).tar: @echo "Creating $@" @rm -rf $(ESSDIR) @git archive HEAD -o ess-$(ESSVERSION).tar @mkdir ess-$(ESSVERSION) @$(GNUTAR) -C ess-$(ESSVERSION) -xf ess-$(ESSVERSION).tar @cd ess-$(ESSVERSION) && $(EMACS) -Q --script "targets/create-pkg-file.el" @$(GNUTAR) c -f ess-$(ESSVERSION).tar ess-$(ESSVERSION) @rm -rf ess-$(ESSVERSION)/ # Create the "release" directory # run in the foreground so you can accept the certificate # NB 'all', 'cleanup-dist' must not be targets: otherwise, e.g. # 'make tarball' re-builds the tarballs always! $(ESSDIR): RPM.spec autoloads $(MAKE) all # remove previous ESSDIR, etc: $(MAKE) cleanup-dist @echo "** Exporting Files **" git clone . $(ESSDIR)-git mkdir -p $(ESSDIR) (cd $(ESSDIR)-git; $(GNUTAR) cvf - --exclude=.git --exclude=.svn --no-wildcards .) | (cd $(ESSDIR); $(GNUTAR) xf - ) @echo "** Clean-up docs, Make docs, and Correct Write Permissions **" CLEANUP="user-* useR-* Why_* README.*"; ED=$(ESSDIR)/doc; \ if [ -d $$ED ] ; then CD=`pwd`; cd $$ED; chmod -R u+w $$CLEANUP; rm -rf $$CLEANUP; \ $(MAKE) all cleanaux ; cd $$CD; fi # just in case: update from VERSION: cd lisp; $(INSTALL) ess.el ../$(ESSDIR)/lisp/; cd .. cd lisp; $(MAKE) julia-mode.el; $(INSTALL) julia-mode.el ../$(ESSDIR)/lisp/; cd .. $(INSTALL) RPM.spec $(ESSDIR)/ $(INSTALL) lisp/ess-autoloads.el $(ESSDIR)/lisp/ chmod a-w $(ESSDIR)/lisp/*.el chmod u+w $(ESSDIR)/lisp/ess-site.el $(ESSDIR)/Make* $(ESSDIR)/*/Makefile touch $(ESSDIR)/etc/.IS.RELEASE # # Get (the first 12 hexdigits of) the git version into the release tarball: $(shell git-rev-parse master | cut -c 1-12 ) > $(ESSDIR)/etc/git-ref dist: VERSION tarballs @echo "** Making pdf and html documentation" @cd $(ESSDIR)/doc/ ; $(MAKE) pdf @cd $(ESSDIR)/doc/ ; $(MAKE) html grep -E 'defvar ess-(version|revision)' lisp/ess-custom.el \ $(ESSDIR)/lisp/ess-custom.el > $@ .PHONY: cleanup-dist cleanup-rel cleanup-dist: @echo "** Cleaning up **" rm -f $(ESSDIR)/etc/.IS.RELEASE $(ESSDIR)/etc/git-ref (if [ -d $(ESSDIR) ] ; then \ chmod -R u+w $(ESSDIR) $(ESSDIR)-git && rm -rf $(ESSDIR) $(ESSDIR)-git; fi) ## should only be called manually (if at all): cleanup-rel: # @rm -rf $(ESSDIR)* @rm -f tarballs dist tag homepage upload rel %.spec: %.spec.in VERSION sed 's/@@VERSION@@/$(ESSVERSION)/g' $< > $@ ## --- RELEASE section --- ChangeLog: VERSION @echo "** Adding log-entry to ChangeLog file" mv ChangeLog ChangeLog.old (echo `date "+%Y-%m-%d "` \ " ESS Maintainers " ; \ echo; echo " * Version $(ESSVERSION) released."; echo; \ cat ChangeLog.old ) > ChangeLog @rm ChangeLog.old git commit -m 'Version $(ESSVERSION)' ChangeLog tag: @echo "** Tagging the release ** 1) pull existing; 2) tag 3) push it" git fetch --tags ## git pull --tags @echo "Creating tag (no signing, as that fails for MM)" git tag -m'release tagging' v$(ESSVERSION) @echo '** Pushing the v$(ESSVERSION) upstream ...' git push origin v$(ESSVERSION) @touch $@ # signing fails for MM (gpg2 / gpg ??) --> use a non-signed tag above # @echo "Creating tag and signing using $(GPG)" # git tag -s -m'release tagging' v$(ESSVERSION) homepage: @echo "** Updating ESS Webpage **" [ x$$USER = xmaechler ] || (echo 'must be maechler'; exit 1 ) cd $(ESS_HOMEPAGE); ./update-VERSION $(ESSVERSION) @touch $@ upload: [ x$$USER = xmaechler ] || (echo 'must be maechler'; exit 1 ) @echo "** Placing .tgz and .zip files and their .sig's **" cp -p $(ESSDIR).tgz $(ESSDIR).tgz.sig $(ESSDIR).zip $(ESSDIR).zip.sig $(UPLOAD_DIR) @echo "** Creating LATEST.IS. file **" rm -f $(UPLOAD_DIR)/LATEST.IS.* touch $(UPLOAD_DIR)/LATEST.IS.$(ESSDIR) touch $@ #==== RELEASE : ==== rel: ChangeLog dist tag homepage upload @echo "If all is perfect, eventually call 'make cleanup-rel'" touch $@ ## NB: The rpm (SuSE, RH, FC) and debian packages are built *and* signed ## by the down stream maintainers: .PHONY: buildrpm buildrpm: dist rpmbuild -ta --sign $(ESSDIR).tgz builddeb: dpkg-buildpackage -uc -us -rfakeroot -tc clean distclean: cleanup-dist rm -f ess-$(ESSVERSION).tar cd etc; $(MAKE) $@ cd lisp; $(MAKE) $@ cd doc; $(MAKE) $@ ESS-24.01.1/NEWS000066400000000000000000000641451455642170100130270ustar00rootroot00000000000000Changes and New Features in 24.01.1: • Revert a bug introduced with the â€ess-request-a-process’ change Changes and New Features in 24.01.0: • fix docstring warnings in ess-custom • :package-version is now set to "VERSION" in ess-custom. By make this is replaced with "24.01.0" (or similar). • Better “collaboration” with org-mode Now â€ess-request-a-process’ obeys â€ess-gen-proc-buffer-name-function’, thanks to Ihor Radchenko. Changes and New Features in 19.04 (unreleased): • ESS[R]: When a background command is interrupted with C-g, ESS now asks the user if they want to disable background evaluations altogether. This is a resiliency measure against cases where background evals cause cascading errors or hangs. • ESS[R]: Background commands now propagate errors to Emacs. • ESS[R]: Background commands can now be disabled by process instad of globally. For instance when a process has failed to initialize properly, background evals are disabled for that particular process to avoid cascading errors. Other processes may still use background commands. • ESS[R]: ESSR commands are now more robust when ESSR is not in scope. This can happen when using â€browser()’ in an environment that doesn’t inherit from the search path. • ESS[R]: Unexpected exits are now detected during startup. In that case an error is thrown with advice about how to recover. • ESS[R]: â€options(width = )’ is now set on startup based on the width of the inferior window. • ESS[R]: Add support for R projects and start R by default in the project folder. • ESS[R]: Backticked symbols in the process buffer are no longer fontified as strings. • ESS[R]: â€ess-command’ now runs R code in a sandboxed environment. Use â€.ess.environment()’ to inspect the current environment. • ESS[R]: Added support for new syntax in R 4.0 and R 4.1. This concerns raw strings, lambda functions, and the pipe operator. • ESS[R]: Highlight error locations in rlang style backtraces • ESS[R]: Fixed issue that caused ESS-help to hang when usage blocks include R comments (#1025). Fix contributed by Bill Evans. • ESS: New â€ess-elisp-trace-mode’ minor mode. Toggle it to start or stop tracing all â€ess’-prefixed functions with â€trace-function’. Tracing is useful for debugging background ESS behaviour. • ESS[R]: â€ess-get-help-aliases-list’ now caches the aliases on the R side. This should speed up help lookup when the search path has changed and the aliases are read again. • ESS: â€ess-command’ now uses a default timeout of 30 seconds. It should normally be avoided with long-running tasks because it causes Emacs to block while the command is running. If the timeout is reached, an error is thrown. An interrupt is also sent to the process in case of early exit. This is a behaviour change: you will now have to explicitly opt in blocking the whole Emacs UI for more than 30 seconds by supplying a larger timeout (use â€most-positive-fixnum’ for infinity). • ESS: â€ess-wait-for-process’ now returns nil if a timeout is reached. • ESS: â€ess-get-words-from-vector’ gains a â€timeout’ argument. • ESS[R]: Fixed performance issue with argument completions. The help summary for the argument is no longer displayed in the echo area. This fixes delays and hangs (#1062). • ESS[R]: â€ess-command’ is now more robust and resilient to hangs and custom prompts (#1043). It also strips continuation prompts (â€+’ prompts) automatically and reliably (#1116). • ESS[R]: â€ess-command’ now handles sinked consoles correctly. • ESS[R]: â€ess-command’ no longer changes â€.Last.value’. As a result, background tasks like completions no longer affect the last value binding (#1058). • ESS[R]: Namespaced evaluation is disable in roxygen examples (#1026). Part of this change is that namespaced evaluation has become a buffer-local rather than process-local setting (#1046). This makes it possible to disable namespaced evaluation in specific buffers or contexts. • iESS: Inferior processes can now properly reuse frames (#987). Fixed issue that caused the current buffer to be incorrectly displayed in the new frame when â€display-buffer’ is set to pop up frames. • ESS[R]: Better support for tramp. Fixed package evaluation on remote servers with Tramp (#950); process reloading (#1001); and an evaluation issue (#1024). These fixes were contributed by David Pritchard. • ESS[R]: Automatic offsetting of R process output is now disabled by default because it produces undesirable output in some situations. To re-enable, set â€inferior-ess-fix-misaligned-output’ to t. • ESS[R]: Improved â€xref’ lookup (â€M-.’). Function locations are now always detected for package libraries listed in â€ess-r-package-library-paths’. • ESS[R]: Evaluated lines starting with the Roxygen prefix are now always stripped from the prefix, so they can be sent to the process easily. Previously, this was only the case inside the â€examples’ field. Since roxygen is switching to R markdown, it becomes useful to evaluate chunks of R outside examples. • stata support is now obsolete since we were unable to elicit FSF paperwork from some of the original authors: see the lisp/obsolete sub-directory on the ESS github repo • â€ess-set-working-directory’ no longer changes the active directory (as defined by the buffer-local variable â€default-directory’) of the buffer where the command is called. Instead, the active directory of the inferior buffer is updated to the new working directory. • The default of ess-eval-visibly is now â€'nowait’. With this change you should no longer experience freezes while evaluating code. • ESS[R]: There is a new menu entry for reloading the R process. It is otherwise bound to â€C-c C-e C-r’. Reloading now reuses the same process name and start arguments that were used to start the process. • iESS: Process runners now return the inferior buffer. Note that callers of inferior runners should not assume that the current buffer has been set to the inferior buffer. Instead, use â€with-current-buffer’ with the return value of the inferior. • iESS[SAS]: The SAS keymap was only set in iESS buffers called â€*SAS*â€. This is now fixed. • ESS[R]: Fixed longstanding indentation issues involving â€::’ and â€:::’ operators. • Implement a more reliable check for the process busy state. Background actions such as completion and directory synchronization should not block the process and should not cause printing of the extraneous output to the interpreter. • Activate â€goto-address-mode’ for url and email highlighting in inferior buffers. • â€smart-underscore’ and â€ess-smart-S-assign-key’ have been removed. Users who liked the previous behavior (i.e. underscore inserting “<-”) should bind â€ess-insert-assign’ to the underscore in their Emacs initialization file. For example, â€(define-key ess-r-mode-map "_" #'ess-insert-assign)’ and â€(define-key inferior-ess-r-mode-map "_" #'ess-insert-assign)’ will activate it in all ESS R buffers. • ESS major modes are now defined using ’define-derived-mode’. This makes ESS major modes respect modern conventions such as having -mode-hook and -mode-map. Users are encouraged to place customizations under the appropriate mode. • New option ess-auto-width controls setting the width option on window changes. Users can change it to ’frame, ’window, or an integer. See the documentation for details. â€ess-auto-width-visible’ controls visibility. • ESS now respects â€display-buffer-alist’. Users can now use â€display-buffer-alist’ to manage how and where windows appear. For more information and examples, see *Note (ess)Controlling buffer display::. • â€ess-roxy-mode’ can now be enabled in non-R buffers. This is primarily intended to support roxygen documentation for cpp buffers. Preview functionality is not supported outside R buffers. • ESS[R]: DESCRIPTION files now open in â€conf-colon-mode’. • â€ess-style’ now has effects when set as a file or directory local variable. • â€ess-default-style’ is now obsolete, use â€ess-style’ instead. • Options for ’ess-gen-proc-buffer-name-function’ have been renamed. ess-gen-proc-buffer-name:projectile-or-simple was renamed to ess-gen-proc-buffer-name:project-or-simple and ess-gen-proc-buffer-name:projectile-or-directory was renamed to ess-gen-proc-buffer-name:project-or-directory. As the name suggests, these now rely on project.el (included with Emacs) rather than projectile.el, which is a third-party package. • Eldoc fully honors â€eldoc-echo-area-use-multiline-p’ • ESS[R]: â€ess-r-rhub-check-package’ gained new â€RECOMMENDED’. • ESS[R]: devtools commands ask about saving modified buffers before running. Users can disable the questioning with â€ess-save-silently’. • ESS[R] help pages now provide links to other help topics. This is similar with what you would see with, for example â€options(help_type = ``html'')’ but works with the plain-text version as well. This only works with â€options(useFancyQuotes = TRUE)’ (the default). • â€ess-rdired’ buffers now derive from tabulated-list-mode. They should look better and be a bit faster overall. The size column now displays object sizes in bytes. • â€ess-rdired’ buffers now auto-update. The frequency is governed by the new option â€ess-rdired-auto-update-interval’. • ESS[R]: â€electric-layout-mode’ is now supported. This automatically inserts a newline after an opening curly brace in R buffers. To enable it, customize â€ess-r-mode-hook’. • ESS[R]: imenu now supports assignment with the equals sign. • ESS[Rd]: Rd no longer writes abbrevs to user’s abbrev file. • ESS removed support for many unused languages. This includes old versions of S+, ARC, OMG, VST, and XLS. • ess-r-runner-prefixes was modified to find R-4 and later. • ESS no longer activates eldoc if the user has disabled global-eldoc-mode. The following have been made obsolete or removed, see their documentation for more detail: • Libraries for literate data analysis are obsolete and not loaded by default. This includes â€ess-noweb’, â€ess-swv’, and related functionality like â€Rnw-mode’. Users are encouraged to switch to one of several other packages that deal with these modes. For example, polymode , , or markdown-mode with edit-indirect . • Support for â€auto-complete’ is obsolete. The â€auto-complete’ package is unmaintained and so ESS support is now obsolete. Users are encouraged to switch to â€company-mode’ instead. • User options for controlling display of buffers. This includes â€ess-show-buffer-action’, â€inferior-ess-same-window’, â€inferior-ess-own-frame’, and â€inferior-ess-frame-alist’. See above about ESS respecting â€display-buffer-alist’. • Variables â€ess-tab-always-indent’ and â€ess-tab-complete-in-script’. Use the Emacs-wide setting of â€tab-always-indent’ instead. • â€inferior-ess-*-start-file’ variables. All modes except Stata did not respect customization of this variable. In order to load a file on startup, you should put a function on â€ess-*-post-run-hook’. Bug Fixes in 18.10.3: • More â€Makefile’ fixes, notably installing â€*.el’s. Bug Fixes in 18.10.2: • ESS[R] Fix namespace evaluation in non-installed packages. Evaluation is directed into GlobalEnv as originally intended. • â€Makefile’ fixes, notably for â€make install’ and including full docs in the tarballs. Bug Fixes in 18.10.1: • New functions â€ess-eval-line-visibly-and-step’ (â€C-c C-n’ and â€ess-eval-region-or-line-visibly-and-step’ (â€C-RET’) which behave as the old versions of â€ess-eval-line-and-step’ and â€ess-eval-region-or-line-and-step’. Changes and New Features in 18.10: • This is the last release to support Emacs older than 25.1. Going forward, only GNU Emacs 25.1 and newer will be supported. Soon after this release, support for older Emacs versions will be dropped from the git master branch. Note that MELPA uses the git master branch to produce ESS snapshots, so if you are using Emacs < 25.1 from MELPA and are unable to upgrade, you should switch to MELPA-stable. • ESS now displays the language dialect in the mode-line. So, for example, R buffers will now show ESS[R] rather than ESS[S]. • The ESS manual has been updated and revised. • The ESS initialization process has been further streamlined. If you update the autoloads (which installation from â€package-install’ does), you should not need to â€(require 'ess-site)’ at all, as autoloads should automatically load ESS when it is needed (e.g. the first time an R buffer is opened). In order to defer loading your ESS config, you may want to do something like â€(with-require-after-load "ess" )’ in your Emacs init file. Users of the popular â€use-package’ Emacs package can now do â€(use-package ess :defer t)’ to take advantage of this behavior. For more information on this feature, see *Note (ess)Activating and Loading ESS::. • ESS now respects Emacs conventions for keybindings. This means that The â€C-c [letter]’ bindings have been removed. This affects â€C-c h’, which was bound to â€ess-eval-line-and-step-invisibly’ in â€sas-mode-local-map’; â€C-c f’, which was bound to â€ess-insert-function-outline’ in â€ess-add-MM-keys’; and â€C-c h’, which was bound to â€ess-handy-commands’ in â€Rd-mode-map’, â€ess-noweb-minor-mode-map’, and â€ess-help-mode-map’ • Functions â€ess-eval-line-and-step’ and â€ess-eval-region-or-line-and-step’ now behave consistently with other evaluation function inside a package. • ESS[R]: â€ess-r-package-use-dir’ now works with any mode. This sets the working directory to the root of the current package including for example C or C++ files within â€/src’). • ESS[R]: Long + + prompts in the inferior no longer offset output. • ESS[R]: New option â€strip’ for â€inferior-ess-replace-long+’. This strips the entire + + sequence. • ESS modes now inherit from â€prog-mode’. In the next release, ESS modes will use â€define-derived-mode’ so that each mode will have (for example) its own hooks and keymaps. • ESS[R]: Supports flymake in R buffers for Emacs 26 and newer. Users need to install the â€lintr’ package to use it. Customizable options include â€ess-use-flymake’, â€ess-r-flymake-linters’, and â€ess-r-flymake-lintr-cache’. • ESS[R]: Gained support for xref in Emacs 25+ *Note (emacs)Xref::. • ESS[R]: The startup screen is cleaner. It also displays the startup directory with an explicit â€setwd()’. • ESS[R]: Changing the working directory is now always reflected in the process buffer. • ESS[R]: â€Makevars’ files open with â€makefile-mode’. • New variable â€ess-write-to-dribble’. This allows users to disable the dribble (â€*ESS*’) buffer if they wish. • All of the â€*-program-name’ variables have been renamed to â€*-program’. Users who previously customized e.g. â€inferior-ess-R-program-name’ will need to update their customization to â€inferior-ess-R-program’. These variables are treated as risky variables. • â€ess-smart-S-assign’ was renamed to â€ess-insert-assign’. It provides similar functionality but for any keybinding, not just â€_â€. For instance if you bind it to â€;â€, repeated invocations cycle through between assignment and inserting â€;â€. • â€C-c C-=’ is now bound to â€ess-cycle-assign’ by default. See the documentation for details. New user customization option â€ess-assign-list’ controls which assignment operators are cycled. • ESS[R] In remote sessions, the ESSR package is now fetched from GitHub. • Commands that send the region to the inferior process now deal with rectangular regions. See the documentation of â€ess-eval-region’ for details. This only works on Emacs 25.1 and newer. • ESS[R]: Improvements to interacting with iESS in non-R files. Interaction with inferior process in non-R files within packages (for instance C or C++ files) has been improved. This is a work in progress. • ESS[R]: Changing the working directory is now always reflected in the process buffer. • ESS[JAGS]: *.jog and *.jmd files no longer automatically open in JAGS mode. Many improvements to fontification: • Improved customization for faces. ESS now provides custom faces for (nearly) all faces used and places face customization options into their own group. Users can customize these options using â€M-x customize-group RET ess-faces’. • Many new keywords were added to â€ess-R-keywords’ and â€ess-R-modifiers’. See the documentation for details. • ESS[R]: â€in’ is now only fontified when inside a â€for’ construct. This avoids spurious fontification, especially in the output buffer where â€in†is a common English word. • ESS: Font-lock keywords are now generated lazily. That means you can now add or remove keywords from variables like â€ess-R-keywords’ in your Emacs configuration file after loading ESS (i.e. in the â€:config’ section for â€use-package’ users). • ESS[R]: Fontification of roxygen â€@param’ keywords now supports comma-separated parameters. • ESS[R]: Certain keywords are only fontified if followed by a parenthesis. Function-like keywords such as â€if ()’ or â€stop()’ are no longer fontified as keyword if not followed by an opening parenthesis. The same holds for search path modifiers like â€library()’ or â€require()’. • ESS[R]: Fixed fontification toggling. Especially certain syntactic elements such as â€%op%’ operators and backquoted function definitions. • ESS[R]: â€ess-font-lock-toggle-keyword’ can be called interactively. This command asks with completion for a font-lock group to toggle. This functionality is equivalent to the font-lock menu. Notable bug fixes: • â€prettify-symbols-mode’ no longer breaks indentation. This is accomplished by having the pretty symbols occupy the same number of characters as their non-pretty cousins. You may customize the new variable â€ess-r-prettify-symbols’ to control this behavior. • ESS: Inferior process buffers are now always displayed on startup. Additionally, they don’t hang Emacs on failures. Obsolete libraries, functions, and variables: • The â€ess-r-args.el’ library has been obsoleted and will be removed in the next release. Use â€eldoc-mode’ instead, which is on by default. • Functions and options dealing with the smart assign key are obsolete. The following functions have been made obsolete and will be removed in the next release of ESS: â€ess-smart-S-assign’, â€ess-toggle-S-assign’, â€ess-toggle-S-assign-key’, â€ess-disable-smart-S-assign’. The variable â€ess-smart-S-assign-key’ is now deprecated and will be removed in the next release. If you would like to continue using â€_†for inserting assign in future releases, please bind â€ess-insert-assign’ in â€ess-mode-map’ the normal way. • ESS[S]: Variable â€ess-s-versions-list’ is obsolete and ignored. Use â€ess-s-versions’ instead. You may pass arguments by starting the inferior process with the universal argument. Changes and New Features in 17.11: • The ESS initialization process has been streamlined. You can now load the R and Stata modes independently from the rest of ESS. Just put â€(require 'ess-r-mode)’ or â€(require 'ess-stata-mode)’ in your init file. This is for experienced Emacs users as this requires setting up autoloads for â€.R’ files manually. We will keep maintaining â€ess-site’ for easy loading of all ESS features. • Reloading and quitting the process is now more robust. If no process is attached, ESS now switches automatically to one (prompting you for selection if there are several running). Reloading and quitting will now work during a debug session or when R is prompting for input (for instance after a crash). Finally, the window configuration is saved and restored after reloading to prevent the buffer of the new process from capturing the cursor. • ESS[R]: New command â€ess-r-package-use-dir’. It sets the working directory of the current process to the current package directory. • ESS[R] Lookup for references in inferior buffers has been improved. New variable â€ess-r-package-source-roots’ contains package sub-directories which are searched recursively during the file lookup point. Directories in â€ess-tracebug-search-path’ are now also searched recursively. • ESS[R] Namespaced evaluation is now automatically enabled only in the â€R/’ directory. This way ESS will not attempt to update function definitions from a package if you are working from e.g. a test file. Changes and New Features in 16.10: • ESS[R]: Syntax highlighting is now more consistent. Backquoted names are not fontified as strings (since they really are identifiers). Furthermore they are now correctly recognized when they are function definitions or function calls. • ESS[R]: Backquoted names and â€%op%’ operators are recognized as sexp. This is useful for code navigation, e.g. with â€C-M-f’ and â€C-M-b’. • ESS[R]: Integration of outline mode with roxygen examples fields. You can use outline mode’s code folding commands to fold the examples field. This is especially nice to use with well documented packages with long examples set. Set â€ess-roxy-fold-examples’ to non-nil to automatically fold the examples field when you open a buffer. • ESS[R]: New experimental feature: syntax highlighting in roxygen examples fields. This is turned off by default. Set â€ess-roxy-fontify-examples’ to non-nil to try it out. • ESS[R]: New package development command â€ess-r-devtools-ask’ bound to â€C-c C-w C-a’. It asks with completion for any devtools command that takes â€pkg’ as argument. • ESS[R]: New command â€C-c C-e C-r’ to reload the inferior process. Currently only implemented for R. The R method runs â€inferior-ess-r-reload-hook’ on reloading. • ESS[R]: â€ess-r-package-mode’ is now activated in non-file buffers as well. Bug fixes in 16.10: • ESS[R]: Fix broken (un)flagging for debugging inside packages • ESS[R]: Fixes (and improvements) in Package development • ESS[R]: Completion no longer produces â€...=’ inside â€list( )’. • ESS[R]: Better debugging and tracing in packages. • ESS[R]: Better detection of symbols at point. • ESS[R]: No more spurious warnings on deletion of temporary files. • ESS[julia]: help and completion work (better) • ESS[julia]: available via â€ess-remote’ Changes and New Features in 16.04: • ESS[R]: â€developer’ functionality has been refactored. The new user interface consists of a single command â€ess-r-set-evaluation-env’ bound by default to â€C-c C-t C-s’. Once an evaluation environment has been set with, all subsequent ESS evaluation will source the code into that environment. By default, for file within R packages the evaluation environment is set to the package environment. Set â€ess-r-package-auto-set-evaluation-env’ to â€nil’ to disable this. • ESS[R]: New â€ess-r-package-mode’ This development mode provides features to make package development easier. Currently, most of the commands are based on the â€devtools’ packages and are accessible with â€C-c C-w’ prefix. See the documentation of â€ess-r-package-mode’ function for all available commands. With â€C-u’ prefix each command asks for extra arguments to the underlying devtools function. This mode is automatically enabled in all files within R packages and is indicated with â€[pkg:NAME]’ in the mode-line. • ESS[R]: Help lookup has been improved. It is now possible to get help for namespaced objects such as pkg::foobar. Furthermore, ESS recognizes more reliably when you change â€options('html_type')’. • ESS[R]: New specialized breakpoints for debugging magrittr pipes • ESS: ESS now implements a simple message passing interface to communicate between ESS and inferior process. Bug fixes in 16.04: • ESS[R]: Roxygen blocks with backtics are now correctly filled • ESS[R]: Don’t skip breakpoints in magrittr’s â€debug_pipe’ • ESS[R]: Error highlighting now understands â€testthat†type errors • ESS[Julia]: Added getwd and setwd generic commands ESS-24.01.1/ONEWS000066400000000000000000002273711455642170100131500ustar00rootroot00000000000000Changes and New Features in 15.09: * ESS[R]: The indentation logic has been refactored. It should be faster, more consistent and more flexible. There are three types of indentation settings, those starting with 'ess-offset-' give the actual offsets, those starting with 'ess-indent-' are control (commonly Boolean) variables, and those starting with 'ess-align-' are vertical alignment overrides which inhibit default offsets in specific situations. See 'ess-style-alist' for detailed description of the new indentation system and provided default indentation styles. * ESS[R]: Deprecation of old indentation settings. As a consequence of the indentation re-factoring 'ess-brace-imaginary-offset', 'ess-expression-offset' and all delimiter-specific offsets are deprecated. The settings for indentation of continued statements have been replaced by 'ess-offset-continuations'. It can be set to either 'cascade' or 'straight' (the default). 'ess-arg-function-offset' has been replaced by 'ess-indent-from-lhs' and has been generalised to assignments. This setting now works with both statement blocks and expressions and only takes effect for offsets set to 'prev-call' and 'open-delim' in order to produce a consistent indentation. * ESS: A test framework has been set up. * ESS[R]: A new RStudio style is provided to mimic as closely as possible R files indented via RStudio. To reproduce the setup of some of the RStudio users, the RStudio- style with 'ess-offset-arguments' set to 'prev-line' is also provided. In addition, the new RRR+ style is equivalent to RRR except it indents blocks in function calls relatively to the opening delimiter. This style does not try to save horizontal space and produces more indentation. * ESS[R]: Roxygen fields will now be indented on paragraph refilling in order to make the documentation more readable. You can also refill commented lines in the 'examples' field without squashing the surrounding code in the comments. * ESS[R]: ESS can now format your code! This is controlled through the settings 'ess-fill-calls' and 'ess-fill-continuations'. When activated, '(fill-paragraph)' formats your calls and your formulas/continuations while making sure they don't go past 'fill-column'. Repeated refills cycle through different styles (see the docstrings for more details). By default, the refilled region blinks. Set 'ess-blink-filling' to nil to prevent this. * ESS[R]: Fix occasional missing error location fontification in inferior buffers. * ESS[R]: ess-developer now correctly assigned the environment of new functions to the package namespace. * ESS[Julia]: ?[topic] now works in the *julia* buffer. Note that support for editing Julia code now depends on 'julia-mode.el' from the Julia project. If you install ESS from the official tarball/zip file, 'julia-mode.el' is already included. Otherwise, if you install ESS by running 'make', then the latest version of 'julia-mode.el' is downloaded (and so you need an active internet connection to install) during the installation process. Alternatively, if you run ESS without running 'make', then ensure that you have the 'julia-mode.el', which you can get easily from MELPA for example. * iESS: For naming inferior processes, ESS can use 'projectile''s project root and it does so when 'ess-gen-proc-buffer-name-function' is set to 'ess-gen-proc-buffer-name:projectile-or-simple' as by default, or to another value beginning with 'ess-gen-proc-buffer-name:projectile-*'. Changes and New Features in 15.03-1: * ESS[R]: An indentation bug has been fixed (github issue 163) * ESS[R]: On windows, if 'ess-prefer-higher-bit' is non-nil (the default), then R-newest will try to run a 64 bit (rather than 32 bit) version of R. Changes and New Features in 15.03: * ESS[R]: Full native support for 'company-mode'. * ESS[R]: More efficient caching algorithm for R completion. * ESS: New offset variable 'ess-close-paren-offset' to control the indentation of the closing parentheses. * ESS[R]: Ask for CRAN mirror only once per emacs session. * ESS[R]: Detect 'library' and 'require' calls for better completion caching. * Buffer display is now customizable ('ess-show-buffer-action'). * Use 'y-or-n-p' instead of 'yes-or-no-p' throughout. * More support for ODS in ess-sas-graph-view. * Makefiles are now both UNIX and GNU friendly. * ESS[R]: Simplify directory lookup in 'ess-developer' (#137). * Make closed paren indentation consistent Bug Fixes in 15.03: * Fix open brace indentation bug (#27 in ess/R-ESS-bugs.R). * Fix git version lookup * Don't check directory modtime in R dialect. * Declare all ess macros for edebug. * Add 'ess-smart-comma' to eldoc message functions. * Inform users when retrieving RDA aliases. * Line ending in '~' is also a continuation line. * Filing roxy paragraphs works as expected now. * In 'ess-developer-add-package', remove incorrect 'wait' argument from 'ess-get-words-from-vector' call. * Fix #96, #117, #120, #125, #134, #137. * Fix ess-quit-r. Call base::q() even if it is masked. * Fix 'ess-show-buffer' to always display the buffer in another window. * Makefile: Fix cd bug for directories with spaces in them * 'ess-kill-buffer-and-go' modified to not restart R Changes / Selected Bug Fixes in 14.09: * ESS[Julia]: Executable is changed to 'julia'. * ESS[Julia]: Completion and help system was adjusted to Julia v.0.3.0. Julia v.0.2.x is no more supported. * ESS[R]: Running R with 'gdb' debugger now works as expected * iESS: Inferior ESS buffers are now derived from 'comint-mode' * ESS[R]: 'ess-execute-screen-options' uses correct screen width in terminal sessions * ESS: 'ess-build-tags-for-directory' works when no TAGS file name was provided * ESS: 'ess-offset-statement-continued' is now respected everywhere except inside of the 'if' test condition. * ESS: New variable 'ess-offset-statement-first-continued' for indentation of the first line in multiline statements. * ESSR: Starting ',' in multiline statements indentation is now ignored to achieve a more pleasant alignment. * ESSR: Improved behavior of 'RET' in roxygen blocks. * ESS[R]: command cleaning with 'C-u C-u C-y' was broken with lines containing " + " * ESS[R]: fixed "empty watch window bug" * ESS[R]: don't ask for help location on ac-quick-help (request of github #81) * ESS[R]: "importClassesFrom" and "importMethodsFrom" were added to the list of two-parameter roxygen commands * ESS[R]: fix vignetes display and hyperlinks (were broken in 13.09-1) * ESS[Julia]: recognize function names ending with ! * ESS[Julia]: fix indentation of "for" comprehension syntax within brackets. Changes / Selected Bug Fixes in 13.09-1: * ess-remote and TRAMP: R support code is now downloaded in binary form instead of being injected from local machine. The R code is stored in '~/.config/ESSR/' directory on the remote machine * TRAMP: PAGER environment variable is now correctly set to 'inferior-ess-pager' * retrieval of help topics on remote machines is fixed * org-babel: source references of R code executed from org files correctly point to source references in original org files (version 8.2.1 or higher of org-mode is required for this feature) * 'ess-execute' is now bound to 'C-c C-e C-e' in 'ess-extra-map'. * completion works again in 'ess-execute' * ESS[R]: 'head' and 'tail' methods were replaced by '.ess_htsummary' in 'ess-R-describe-object-at-point-commands' * ESS[roxygen]: evaluation commands now work in roxygen blocks. Leading comments are automatically removed before the evaluation * ESS[transcript]: 'Clean Region' now works with multiline statements; 'ess-transcript-clean-region' etc. correctly treat multiline statements, i.e., no longer forgets the lines typically preceded by '+' * ESS[SAS]: Three features/fixes with special thanks to Matthew Fidler https://github.com/emacs-ess/ESS/pulls/mlf176f2 (https://github.com/emacs-ess/ESS/pulls/mlf176f2). Turn on SAS log mode when appropriate. Indent comments and CARDS statement more appropriately. * ESS[SAS]: 'ess-sas-edit-keys-toggle' default returns to 'nil' * ESS[R]: support for 'prettify-symbols-mode': contribution from Rudiger Sonderfeld * ESS[SWV]: knitr now evaluates in the current frame * ESS[developer]: ess-developer doesn't kill open DESCRIPTION files anymore * ESS[roxygen]: 'ess-roxy-preview-HTML' is now on 'C-c C-o C-w' and 'ess-roxy-preview-text' is now on 'C-c C-o C-t' * ESS: installation with 'make install' was simplified and should work out of the box on most *nix systems * ESS installation instructions simplified * fixed font-lock bug introduced in 13.09 that was causing very slow process output Changes/New Features in 13.09: * font-lock in process buffers doesn't "spill" over prompts. Missing closing string delimiters should not cause wrong fontification of the following command input. * ESS[julia]: full features M-TAB completion and auto-complete support, which now works for modules, structures and data types. * ESS[julia]: a much better eldoc showing arguments of methods and data type constructors * ESS-developer: - ESS-developer work-flow pattern has been streamlined: ESS-developer is now automatically activated on per-file basis if the file is part of a developed package 'ess-developer-packages'. The old behavior (activation on per-process basis) is still available on 'M-x ess-developer' in a process buffer. - integration with 'devtools' package. New command 'ess-developer-load-package' calls 'load_all' on the package containing current file. 'ess-developer-add-package' now offers IDO menu completions with available loading methods, currently 'library', and 'load_all'. Loading command can be customized with 'ess-developer-load-on-add-commands'. * 'TAB' now indents region if region is active (a contribution of Matthew Fidler in pull #41) * 'M-x ess-version' now reports full loading path and recognizes git and ELPA versions. * warning and error keyword are now highlighted with 'font-lock-warning-face' as they should be, (for quite some time these keywords have been hijacked by compilation mode fontification). * eldoc: Eldoc now recognizes multiple processes. If current process is busy, or current buffer is not associated with a process, eldoc picks its completions from the first available free process. * org-babel: evaluation is now org-friendly * help: new help buffers now try to reuse ess-help buffers. This behavior is controlled by 'ess-help-reuse-window' custom variable. * help: ?foo pops IDO menu on multiple help files (so far it worked only for 'C-c C-v') * remote evaluation is considerably faster now on slow connections * ESS[R] tracebug R source references regular expressions are (mostly) language agnostic. * 'ess-function-call-face' inherits from 'font-lock-function-name-face' rather than 'font-lock-builtin-face'. * 'ess-inject-source' now accepts 'function-and-buffer' option. * Documentation: The "New Features" section (and 'NEWS') now represent recent changes: within the last year or so. All changes can be found in the new news.html (news.html) (or 'NEWS' and 'ONEWS'). * ESS[R] 'ess-rep-regexp' should no longer inf.loop (rarely!), and hence 'M-x ess-fix-miscellaneous' should neither. Changes/New Features in 13.05: * ESS[gretl]: Support for 'gretl' (both editing and sub-process interaction). A contribution of Ahmadou Dicko. * ESS: process output display is 4-10 times faster due to new caching and only occasional emacs re-display (for the moment this functionality is available only when 'ess-tracebug' is active). * ESS: 'C-c `' is now bound to 'ess-show-traceback' and 'C-c ~' is bound to 'ess-show-call-stack'. * ESS[R]: ESS stores function in 'ESSR' environment to avoid kludging users' global environment and accidental deletion. * ESS[R]: new variable 'ess-swv-processing-command' to control weaving and tangling. * ESS[R]: 'ess-default-style' has been changed (from 'DEFAULT') to 'RRR'. Use something like '(setq ess-default-style 'DEFAULT)' or '(setq ess-indent-level 2)' in your '~/.emacs' equivalent _before_ loading ESS, if you do not like this new "incompatible" default style. * ESS[julia]: ESS stores its functions in 'ESS' module. * ESS[julia]: Eldoc is now supported in julia modes * ESS[julia]: Adjusted error reference detection and interactive help to julia internal changes * ESS[R]: 'ess-use-tracebug''s default has been changed to 't'. Set it to nil if you want to keep the previous behavior. * ESS[tracebug]: Electric debug keys have been removed [breaking change] The functionality was replaced with 'ess-debug-minor-mode' and 'ess-debug-minor-mode-map'. * ESS[tracebug]: 'ess-tracebug-map' is an alias to 'ess-dev-map' 'C-c C-t'. * ESS[tracebug]: 'ess-bp-toggle-state' ('C-c C-t o') can now be used during the debug session to toggle breakpoints on the fly (suggestion by Ross Boylan). * ESS[tracebug]: 'ess-debug-flag-for-debugging' and 'ess-debug-unflag-for-debugging' work correctly from the debugging contexts. These commands also recognize non-exported functions for the packages listed in 'ess-developer-packages' ('C-c C-t C-a'). * ESS[R]: Eldoc (activated by 'ess-use-eldoc') has become more sophisticated, and hence also more intruding in the interface between the Statistics software, e.g., R, and the user. Note that you can turn off ElDoc, by placing '(setq ess-use-eldoc nil)' in your '~/.emacs' file, prior to loading ESS, * ESS[SAS]: long over-looked 'SAS-mode-hook' appears! * ESS[SAS]: 'ess-sas-edit-keys-toggle' now defaults to 't' since 'sas-indent-line' is still broken, i.e. 'TAB' is now bound to 'ess-sas-tab-to-tab-stop' by default Changes/Bug Fixes in 12.09-2: * ESS: new 'ess-switch-to-end-of-proc-buffer' variable that controls whether 'C-c C-z' switches to the end of process buffer. The default is 't'. You can use prefix argument to 'C-c C-z' to toggle this variable. * ESS: fix in 'ess-eval-linewise' that was causing emacs to hang during R debugging with 'ess-eval-visibly' equal to 't'. * ESS: fix in 'ess-eval-linewise' that was causing emacs to recenter the prompt in visible window * ESS[tracebug]: A better handling of "Selection" prompts and debug related singlekey commands. * ESS: fix a bug in 'ess-switch-process' that was causing '*new*' selection to fail. * ESS[R]: Solve missing 'ess-local-process-name' bug in R-dired. * ESS[SWV]: 'ess-swv-PDF' doesn't ask for a command to run if there is only one command in 'ess-swv-pdflatex-commands'. * ESS[SWV]: 'ess-swv-weave' gained an universal argument to allow for an interactive choice between available weavers (sweave, knitr). * ESS: 'ess-eval-*-and-step' functions go to next empty line at eob, instead of staying at the last line. Changes/New Features in 12.09-1: * ESS _Breaking Changes in Keys_: - New keymaps: 'ess-doc-map' bound to 'C-c C-d'; 'ess-extra-map' bound to 'C-c C-e'; 'ess-dump-object-into-edit-buffer' was moved on 'C-c C-e C-d' - roxygen map was moved on 'C-c C-o' and 'ess-roxy-update-entry' now resides on 'C-c C-o C-o' - ess-handy-commands is not bound anymore - 'ess-dev-map' (including 'ess-tracebug' and 'ess-developer') moved on 'C-c C-t' - 'C-c C-y' is deprecated in favor of 'C-c C-z C-z' * ESS[R] new command 'ess-describe-object-at-point' bound to 'C-c C-d C-e' (repeat 'C-e' or 'e' to cycle). It was inspired by Erik Iverson's 'ess-R-object-tooltip'. Customize 'ess-describe-at-point-method' to use tooltip instead of an electric buffer. * ESS: New command 'ess-build-tags-for-directory' bound to 'C-c C-e C-t' for building dialect specific tag tables. After building tags use 'M-.' to navigate to function and objects definitions. By default 'C-c C-e C-t' builds tags based on imenu regular expressions and also include other common languages '.c, .o, .cpp' etc. But it relies on external 'find' and 'etags' commands. If 'ess-build-tags-command' is defined (for 'R'), the inferior process is asked to build tags instead. * ESS: 'ess-switch-process' offers '*new*' alternative to start a new process instead of switching to one of the currently running processes. * ESS: Switching between processes ('C-c C-s') uses buffer names instead of the internal process names. Use 'M-x rename-buffer' command to conveniently rename your process buffers. * ESS: Process buffers can be automatically named on process creation according to user specified scheme. Default schemes are *proc*, *proc:dir* and *proc:abbr-long-dir* where 'proc' stands for the internal process name and 'dir' stands for the directory where the process was started in. The default is *proc*. For customization see 'ess-gen-proc-buffer-name-function'. * ESS: 'ess-eval-visibly-p' is deprecated in favor of 'ess-eval-visibly'. * ESS: New evaluation pattern 'nowait'. In addition to old 'nil' and 't' values, 'ess-eval-visibly' accepts 'nowait' for a visible evaluation with no waiting for the process. See 'ess-eval-visibly' for details on evaluation patterns. * ESS: New "Process" menu entry with process related commands and configuration * iESS: Process buffer is now automatically shown on errors * ESS: New 'ess-switch-to-inferior-or-script-buffer' command bound to 'C-c C-z' in both script and process buffers. If invoked form process buffer it switches to the most recent buffer of the same dialect. It is a single key command. * ESSR-help: On multiple help pages with the same name, 'C-c C-v' now asks for user resolution directly in emacs. * ESS[R] ess-roxy: new variable 'ess-roxy-re' for fontification of cases where the number of leading '#' differs from 'ess-roxy-str'. * ESS[R] Eldoc was considerably enhanced. It now finds hidden default S3 methods and displays non-default methods' arguments after trailing ||. * ESS[R]: New 'ess-display-demos' command bound to 'C-c C-d o' and 'C-c C-d C-o' * ESS: New 'ess-help-web-search' command bound to 'C-c C-d w' and 'C-c C-d C-w' to facilitate interactive search of web resources. Implemented for 'R', 'Stata' and 'Julia'. See also 'ess-help-web-search-command'. * ESS: ess-pdf-viewer-pref accepts now command line arguments * ESS[Rnw]: Add knitr support. Customize 'ess-swv-processor' for the default processor. * ESS[Rnw]: More thorough renaming of remaining 'noweb-*' to 'ess-noweb-*'. * ESS[Rnw] new commands 'ess-eval-chunk-and-step' and 'ess-eval-chunk' bound to 'M-n C-c' and 'M-n C-M-x' to mirror standard ess commands in C-c map. * ESS[R] Auto-completion: new variable 'ess-ac-R-argument-suffix' to customize the insertion of trailing "=". Defaults to " = ". * ESS[Julia]: Added index, apropos and web-search to julia. * ESS help: More evaluation commands were added to ess-help mode ('C-c C-c', 'C-M-x' etc) Bug Fixes in 12.09-1: * iESShelp: Multiple help pages with the same name are properly handled on 'C-c C-v' * iESSremote: Evaluation with ESS remote no longer freezes emacs. * iESS: 'comint-previous-prompt' 'C-c C-p' no longer stops on secondary prompt "+". * iESS[R], iESS(Sqpe) [S] on Windows: The 'options("editor")' is now initialized to 'emacsclient' instead of the previous 'gnuclient'. The user may need to add the line '(server-start)' to the emacs initialization file. 'emacsclient' has been included with emacs since GNU Emacs 22.1. * ESS[Rnw] Fixed "connection to R" bug (in 12.09 only). * ESS[Rnw] Explicit 'ess-swv-stangle' and 'ess-swv-sweave' functions. * ESS[Rnw] Fixed completion and smart underscore problems cause by unmatched "\"' * ESS[R] is more careful with the 'R' code injection. It now happens only once at the start of the session. * ESS[R]: Fixed auto-scrolling the comint buffer on evaluation. * ESS[Julia]: Solve several indentation and word navigation problems. * ESS[Julia]: Help system works again. Changes/New Features in 12.09: * Due to XEmacs lacking some features that ESS requires, ESS support of XEmacs ends with ESS 12.04-4. This decision will be re-visited in the future as XEmacs continues to sync with GNU Emacs. * ESS[R]: On Windows, there is now a new customizable variable (currently called 'ess-directory-containing-R') to tell ESS where to look for the 'Rterm.exe' executables. The name of the variable and the values it can take are both in beta and subject to change. Prior to this variable, ESS searched only in the default installation directory. Setting this variable now tells ESS how to find 'Rterm.exe' executables when they are installed somewhere else. * ESS[julia]: _new_ mode for editing julia code ('*.jl'). Start with 'M-x julia'. Full interaction interface, imenu and basic error referencing are available. * ESS[R] noweb: 'noweb-mode' and 'noweb-font-lock-mode' have been renamed to 'ess-noweb-mode' and 'ess-noweb-font-lock-mode' to avoid conflicts with the "real" 'noweb-mode'. * ESS[R] noweb: The long standing font-lock bug has been solved in 'ess-noweb' interface. * ESS: Basic evaluation keys are now bound to 'ess-eval-region-*-' functions: - 'C-M-x' is bound to 'ess-eval-region-or-function-or-paragraph' - 'C-c C-c' is bound to 'ess-eval-region-or-function-or-paragraph-and-step' - 'C-RET' is bound to 'ess-eval-region-or-line-and-step' Each of these functions first evaluates the region whenever the region is active. * ESS: 'C-M-a'/'C-M-e' now step to beginning/end of paragraph if no function has been detected. * ESS: 'ess-eval-*-and-step' family of functions are now smarter, and don't step to end of buffer or end of chunk code ('@') when at the end of the code. * ESS: 'ess-handy-commands' function is bound to 'C-c h' * ESS: ESS is now _blinking_ the evaluated region. Set 'ess-blink-region' to nil to deactivate; 'ess-blink-delay' gives the duration of the blink. Evaluated region is "blinked" in 'highlight' face. * ESS[R-help] New key 'a' for "apropos()" in help buffers. Also available through 'C-c h'. * ESS[R-help] All R commands of type foo?bar and foo??bar are recognized and redirected into appropriate *ESS-help* buffers. * ESS[R]: New customization interface for _font-lock_. ESS font-lock operates with predefined keywords. Default keywords are listed in 'ess-R-font-lock-keywords' and 'inferior-R-font-lock-keywords', which see. The user can easily customize those by adding new keywords. These variables can also be interactively accessed and saved through 'ESS/Font-lock' submenu. Several new fontification keywords have been added. Most notably the keywords for highlighting of function calls, numbers and operators. * ESS[R]: auto-complete is now activated by default whenever auto-complete package is detected. Set 'ess-use-auto-complete' to nil to deactivate. * ESS[R]: R AC sources are no longer auto-starting at 0 characters but at the default 'ac-auto-start' characters. * ESS no longer redefines default ac-sources, but only appends 'ac-source-filename' to it. * ESS: 'ac-source-R' now concatenates " = " to function arguments. * ESS: Menus for ESS and iESS have been reorganized and enriched with _Tracebug_ and _Developer_ submenus. * ESS[R]: 'ess-developer' and 'ess-tracebug' commands are available by default in 'ess-dev-map' which is bound to 'C-c d' in ESS and iESS maps. * ESS[R]: 'eldoc' truncates long lines whenever 'eldoc-echo-area-use-multiline-p' is non-nil (the default). Set this variable to t if you insist on multiline eldoc. See also 'ess-eldoc-abbreviation-style'. * ESS[R]: completion code pre-caches arguments of heavy generics such as 'plot' and 'print' to eliminated the undesirable delay on first request. * iESS: Prompts in inferior buffers are now highlighted uniformly with 'comint-highlight-prompt' face. * ESS[R]: R process no longer wait for the completion of input in inferior buffer. Thus, long running commands like 'Sys.sleep(5)' no longer stall emacs. * ESS: [R, S, Stata, Julia] have specialized 'ess-X-post-run-hook's, which are run at the end of subprocess initialization. * ESS[Stata]: All interactive evaluation commands work as expected. On-line comments are removed before the evaluation and multiline comments are skipped on 'C-c C-c' and other interactive commands. * ESS no longer auto-connects to a subprocess with a different dialect than the current buffer's one. * ESS: 'ess-arg-function-offset-new-line' is now a list for all the ESS indentation styles, which results in the following indentation after an open "(": a <- some.function(other.function( arg1, arg2) * ESS[SAS]: Improved MS RTF support for GNU Emacs; try 'ess-sas-rtf-portrait' and 'ess-sas-rtf-landscape'. Changes/Bug Fixes in 12.04-3: * ESS: basic support for package.el compatibility * ESS[R]: correct indentation of & and | continuation lines * 'M-x ess-version' shows the svn revision even after 'make install' * ESS[SAS]: improved XEmacs support * iESS[R]: better finding of previous prompt * ESS[Stata]: adjusted prompt for mata mode * ESS[R]: resolved name clashes with cl.el * ESS[R]: removed dependence on obsolete package assoc * New 'make' target 'lisp', to build the Lisp-only part, i.e., not building the docs. Changes/New Features in 12.04-1: * iESS[Stata]: New interactive help invocation. * iESS[Stata]: New custom variable 'inferior-STA-start-file'. * iESS[Stata]: 'inferior-STA-program-name' is now "stata" and can be customized. * ESS[Stata] New sections in stata help files Syntax('s-S'), Remarks('r'), Title('t'). Bug Fixes in 12.04-1: * ESS[R]: Better 'ess-tracebug' error handling. * ESS[R]: Corrected 'ess-eldoc' help string filtering and improved argument caching. * ESS[R]: Indentation of non-block if/else/for/while lines fixed. * 'M-x ess-version' should work better. * ESS: Filename completion now again works inside strings. * iESS[Stata]: Fixed prompt detection issue. * ESS[Rd]: R is autostarted also from here, when needed. Changes/New Features in 12.04: * ESS: Reverting new behavior of 12.03, 'TAB' in 'ess-mode' no longer completes by default. If you want smart 'TAB' completion in R and S scripts, similarly to iESS behavior, set the variable 'ess-tab-complete-in-script' to 't'. Also see 'ess-first-tab-never-complete' for how to customize where first 'TAB' is allowed to complete. * ESS: completion is consistently bound to 'M-TAB' (aka 'M-C-i') in both Emacs23 and Emacs24. * ESS: The variable 'ess-arg-function-offset-new-line' introduced in ESS(12.03) now accepts a list with the first element a number to indicate that the offset should be computed from the indent of the previous line. For example setting it to '(2) results in: a <- some.function( arg1, arg2) Changes/New Features in 12.03: * ESS indentation: new offset variable 'ess-arg-function-offset-new-line' controlling for the indentation of lines immediately following open '('. This is useful to shift backwards function arguments after a long function call expression: a <- some.function( arg1, arg2) instead of the old a <- some.function( arg1, arg2) If '(' is not followed by new line the behavior is unchanged: a <- some.function(arg1, arg2) This variable should be set as part of indentation style lists, or in ess-mode hook. * ESS[R]: 'C-c .' sets (indentation) style. * ESS: In ESS buffers 'yank'('C-y') command accepts double argument 'C-u C-u' to paste commands only. It deletes any lines not beginning with a prompt, and then removes the prompt from those lines that remain. Useful to paste code from emails, documentation, inferior ESS buffers or transcript files. * Documentation: ESS user manual has been rearranged and completed with several new chapters and sections to reflect newly added features ("Completion", "Developing with ESS", "ESS tracebug", "ESS developer", "ESS ElDoc", "IDO Completion" and "Evaluating Code") * RefCard: Reference card was updated to include new features. * Eldoc: Eldoc was rewritten and is activated by default. See 'ess-use-eldoc', 'ess-eldoc-show-on-symbol', 'ess-eldoc-abbreviation-style' variables for how to change the default behavior. _Note:_ 'skeleton-pair-insert-maybe' prohibits eldoc display, on '(' insertion. * ESS[R]: Eldoc shows arguments of a generic function whenever found. * ESS: 'TAB' in 'ess-mode' now indents and completes, if there is nothing to indent. Set 'ess-first-tab-never-completes-p' to 't' to make 'TAB' never complete on first invocation. Completion mechanism is similar to the completion in the 'inferior-ess-mode' - a filename expansion is tried, if not found ESS completes the symbol by querying the process. * ESS for emacs version 24 or higher: ESS is fully compatible with the emacs 24 completion scheme, i.e. all the completion is done by 'completion-at-point'. Also in accordance with emacs conventions, ESS doesn't bind 'M-TAB' for emacs 24 or higher. 'M-TAB' calls the default 'complete-symbol'. * ESS[R]: Out of the box integration with 'Auto Completion' mode http://cx4a.org/software/auto-complete (http://cx4a.org/software/auto-complete) . Three AC sources 'ac-source-R-args', 'ac-source-R-objects' and 'ac-source-R' are provided. The last one combines the previous two and makes them play nicely together. Set 'ess-use-auto-complete' to 't' to start using it. Refer to documentation string of 'ac-use-auto-complete' for further information. * ESS[R]: New unified and fast argument completion system, comprised of 'ess-funname.start', 'ess-function-arguments', 'ess-get-object-at-point'. Eldoc and auto-completion integration are using this system. * ESS: 'ess-switch-to-end-of-ESS'('C-c C-z'), and 'ess-switch-to-ESS'('C-c C-y'): Automatically start the process whenever needed. * ESS[R]: 'roxy' knows about previewing text version of the documentation. Bound to 'C-c C-e t'. * ESS[R]: Solved the "nil filename" bug in roxygen support. * ESS[R]: 'ess-tracebug' is now part of ESS: New Features: - Source injection: Tracebug now can inject source references on the fly during code evaluation, i.e. you don't have to source your file, but just evaluate your code in normal fashion. Variable 'ess-tracebug-inject-source-p' controls this behavior - if t, always inject source reference, if ''function', inject only for functions (this is the default), if 'nil', never inject. During the source injection the value of 'ess-eval-visibly' is ignored. - Org-mode support: Visual debugger is now aware of the temporary org source editing buffer ('C-c '') and jumps through this buffers if still alive, or in original org buffer otherwise. - New keys in watch mode: '?' and 'd' - Two new hooks: ess-tracebug-enter-hook and ess-tracebug-exit-hook * ESS[R]: New package 'ess-developer' to evaluate 'R' code directly in the package environment and namespace. It can be toggled on and off with 'C-c d t'. When 'ess-developer' is on all ESS evaluation commands are redefined to evaluate code in appropriate environments. Add package names to the list of your development packages with 'C-d a', and remove with 'C-d r'. Source the current file with 'C-d s'.Evaluation function which depend on '`ess-eval-region'' ask for the package to source the code into, 'ess-eval-function' and alternatives search for the function name in the development packages' environment and namespace and insert the definition accordingly. See the documentation section "Developing with ESS/ESS developer" for more details. * ESS[R] help system: New Features: - 'q' quits window instead of calling 'ess-switch-to-end-of-ESS'. This is consistent with emacs behavior help and other special buffers (_breaking change_). - 'k' kills window without asking for the name (pointed by Sam Steingold) - Help map inherits from 'special-mode-map' as suggested by Sam Steingold. - Package index: new function 'ess-display-index' bound to 'i' in help mode map. - Package vignettes: new function 'ess-display-vignettes' bound to 'v' in help mode map. - Display help in HTML browser: new function 'ess-display-help-in-browser' bound to 'w' in help mode map. It depends on 'R''s 'browser' option. - New custom variable 'ess-help-pop-to-buffer': if non-nil ESS help buffers are given focus on display. The default is 't' (_breaking change_). - New menu entries for the above functions. - Bogus help buffers are no longer generated by default, i.e. buffers of the form "No documentation for 'foo' in specified packages and libraries: you could try '??foo' ". 'ess-help-kill-bogus-buffers' now defaults to 't'. Beware, there may be instances where the default is unsatisfactory such as debugging and/or during R development. Thanks to Ross Boylan for making the suggestion, Sam Steingold for reminding us of this variable and Martin Maechler for the warning. * ESS now uses 'IDO' completing read functionality for all the interactive requests. It uses ido completion mechanism whenever available, and falls back on classical completing-read otherwise. You can set 'ess-use-ido' to nil if you don't want the IDO completion. See the documentation string of 'ess-use-ido' for more information about 'IDO' and ESS configuration. * ESS[S]: "','" is bound to ess-smart-comma: If comma is invoked at the process marker of an ESS inferior buffer, request and execute a command from '`ess-handy-commands'' list. If 'ess-R-smart-operators' is t '`ess-smart-comma' also inserts " " after comma. * ESS[S], notably 'R': Variable '`ess-handy-commands'' stores an alist of useful commands which are called by 'ess-smart-comma' in the inferior buffer. Currently containing: change-directory 'ess-change-directory' help-index 'ess-display-index' help-object 'ess-display-help-on-object' vignettes 'ess-display-vignettes' objects[ls] 'ess-execute-objects' search 'ess-execute-search' set-width 'ess-execute-screen-options' install.packages 'ess-install.packages' library 'ess-library' setRepos 'ess-setRepositories' sos 'ess-sos' Handy commands: 'ess-library', 'ess-install.packages', etc - ask for item with completion and execute the correspond command. 'ess-sos' is a interface to 'findFn' function in package 'sos'. If package 'sos' is not found, ask user for interactive install. * ESS: New dynamic mode line indicator: Process status is automatically reflected in all mode-lines of associated with the process buffers. Particularly useful for displaying debug status of 'ess-tracebug' and developer status of 'ess-developer' in all associated buffers. * ESS: New 'ess-completing-read' mechanism: ESS uses 'ido' completions whenever possible. Variable 'ess-use-ido' controls whether to use ido completion or not. Active by default. * ESS now supports comint fields for output and input detection. This feature is not used by default, but might be useful in the future. * ESS[S]: New custom variable 'inferior-ess-S-prompt' to customize prompt detection regular expression in the inferior ESS buffers. You can customize this variable to enhance comint navigation ('comint-previous-prompt' and 'comint-next-prompt') the inferior buffers. * ESS[R]: Internal 'R' completion retrieval ('ess-R-complete-object-name') was rewritten and is faster now. * ESS is using process plist to store process specific variables, as opposed to buffer local variables as it was using before. The use of buffer local variables to store process variables is discouraged. * ESS: new functions to manipulate process plists: 'ess-process-get' and 'ess-process-set'. * ESS: Internal process waiting mechanism was completely rewritten. ESS no more relies on prompt regular expressions for the prompt detection. The only requirement on the primary process prompt is to end in '> '. This could be overwritten by setting 'inferior-ess-primary-prompt'. * ESS[S], notably 'R': Saved command history: ESS-HISTORY-FILE now accepts 't' (default), 'nil', or a file name. By setting it to 'nil' no command line history is saved anymore. ESS-HISTORY-DIRECTORY now allows to have the history all saved in one "central" file. * ESS[R]: more Roxygen improvements. * ESS[R]: 'C-c .' to set (indentation) style. * ESS[R]: Functions with non-standard names (for example 'aaa-bbb:cc') are properly handled by font-lock and evaluation routines. * ESS[R]:Several regexp bugs (described in etc/R-ESS-bugs.el) were fixed in 'ess-get-words-from-vector' and 'ess-command'. Changes/New Features in 5.14: * ESS[BUGS/JAGS]: Batch BUGS is back! For recent OpenBUGS versions, 3.0.8+, a batch BUGS script is once again available, but for Linux only. Therefore, since it seems that BUGS and JAGS must co-exist (rather than a transition from BUGS to JAGS), .bug files are now in ESS[BUGS] mode and .jag files are in ESS[JAGS] mode. ESS[BUGS] now works like ESS[JAGS] rather than the original mode ESS[BUGS] mode which was difficult to maintain. Although, ESS[BUGS] appears to work, there still may be some features missing as well as bugs. * ESS[R]: New customizable variable 'ess-swv-plug-into-AUCTeX-p' Commands to Sweave current file and LaTeX the result are now available to AUCTeX users, if this variable is set to 't'. * ESS[S]: 'C-c C-c' ('ess-eval-function-or-paragraph-and-step') is now skipping over comments as the other paragraph functions do. It (and similar functions) should no longer wrongly find 'function()' beginnings inside comments or strings. * ESS[SAS]: improved by better support for GNU Emacs Changes/New Features in 5.13: * ESS[R]: On Windows, for R 2.12.0 and later, the Rterm executables (in subdirectories i386 / x64) now are found as well as for earlier R versions. * ESS[S+]: on Windows, both 32- and 64-bit versions of S+ ("S-PLUS") are found now and made available on the menu. * ESS[R]: When prompting for a starting directory, the R version is (always?) correct now. * ESS[R]: on non-Windows platforms, the 'use-dialog-box' variable is no longer temporarily changed (to 'nil' for R-x.y.z version functions and to 't' for 'R' itself), but rather the user customization is obeyed. * ESS[R]: more Roxygen improvements. * 'Rd-preview-help' now generates preview buffers with navigation facilities the same as regular help buffers. * ESS: New functions and keys C-c [up] / [down] for evaluating the buffer "from beginning till here". Changes/New Features in 5.12: * ESS[SAS] Font-locking: update of PROCs keywords (up to SAS 9.22); error/warnings. * ESS[R]: Roxygen improvements: S4 classes; also optionally keep spaces when filling arguments * ESS[Rd]: support new keywords: section-name \subsection plus a dozen "new" keywords; should match R 2.12.x now. * 'ess-display-help-on-object' ('C-c C-v') now _caches_ the list of topics, thus speeding up the improvement feature introduced in 5.9. Changes/New Features in 5.11: * Filename completion within buffers now adds only trailing characters to complete the filename, rather than expanding to an absolute file path. This filename completion is bound to the TAB key. * 'M-n P' in Sweave buffers now prompts for the command to run instead of using 'pdflatex' unconditionally, offering completion from customizable collection 'ess-swv-pdflatex-commands', the first of which is taken as default and that defaults to 'texi2pdf'. * 'M-RET' is now also bound in S language (R and S+) buffers to 'ess-use-this-dir'. It sends 'setwd(..)' to the S process to set the working directory to the one of the source file. Changes/New Features in 5.10: * 'M-RET' in *S* buffers is now bound to 'ess-dirs'. This function will set Emacs's current directory to be the same as the *S* process. This is useful if you use 'setwd()' within a *S* process. Changes/New Features in 5.9: * Toolbar: The toolbar now has an icon for starting Splus. * Indentation: New documentation and code has been added to make it easier to change how ESS indents code. In particular, see 'ess-default-style', 'ess-own-style-list' and the documentation subsection "Changing indentation styles". * 'ess-display-help-on-object' ('C-c C-v') now offers completion candidates for help file aliases, in addition to object names. * Font locking: is now turned on even without 'window-system' is 'nil', whenever ESS-FONT-LOCK-MODE is non-nil, i.e., by default. * ESS script editing: ess-eval-deactivate-mark default is now t, as suggested by Leo Alekseyev and subsequent "unanimous" ESS-help discussion. * ESS[R]: Editing support for "#!" (Rscript / littler) editing, thanks to Jeffrey Arnold. * ESS[R]: Now finds all R versions, both 64-bit and 32-bit, on some 64-bit Windows machines. Please report back to ess-core success or failure on your 64-bit Windows machine. * ESS Manual now more visually pleasing; * ESS[R]: Roxygen on XEmacs no longer font locks for now (as it required missing features and hence broke ESS startup, there). * ESS[R]: Roxygen has a sub-menu on the [ESS] menu. * ESS[R]: Function 'ess-rutils-htmldocs' in 'ess-rutils.el' offers an alternative to 'help.start()' for navigating R documentation, using the 'browse-url' Emacs function. Changes/New Features in 5.8: * ESS[R]: New 'ess-rutils.el' with utilities for listing, loading, installing, and updating packages, as well as object manipulation (listing, viewing, and deleting). It also provides an alternative to 'RSiteSearch()' that uses the 'browse-url' function, so results can be viewed in an Emacs web browser. * ESS[R]: much more extensive Roxygen interface, via ess-roxy.el from Henning Redestig. Ess-roxy supports filling of roxygen fields, generation and updating roxygen templates, completion of roxygen tags, basic navigation (marking and moving between entries), folding using hs-minor-mode and preview of the Rd file. * Emacs Lisp files have got better names (partly, for now). Changes/New Features in 5.7: * ESS[R]: loading a source file ('C-c C-l') now works in Windows, similarly to other platforms; (further; it had accidentally been broken in ESS 5.6 on all platforms) Changes/New Features in 5.6: * ESS[R]: help() calls have to differ from old default, with newer versions of R; currently via .help.ESS <- function(...) hack. Changes/New Features in 5.4: * ESS[SAS]: The long overdue change from 'make-regexp' to 'regexp-opt' for font-locking is complete. The new 'regexp-opt' is now the default since it is better than the old code in many ways (and especially more maintainable). However, there are certainly some special cases missed (bug reports and patches welcome!). Setting 'ess-sas-run-regexp-opt' to 'nil' will result in the old code being used. * ESS[BUGS] and ESS[JAGS]: typing '=' now results in '<-'. * ESS[R] function arguments "show" '(ess-r-args-show)' now uses the new '(tooltip-show-at-point)' contributed by Erik Iverson. * Toolbar icons now also work in (beta) Emacs 23. * ESS[S]: New function 'ess-change-directory' for setting both emacs' current directory and the directory of an *R* or *S* buffer. * ESS[S] when transient-mark-mode is true, the mark is now kept, rather than deactivated, thanks to a patch from David Reitter. Changes/New Features in 5.3.11: * ESS[SAS]: work around bug in Emacs 22.2 & 22.3 which fails to set case-fold fontification automatically. * Rd mode: support new keyword 'Rdversion' * ESS[R]: now again works with Emacs 21.x Changes/New Features in 5.3.10: * Fixed noweb-mode bug accidentally introduced into 5.3.9 * In noweb-mode, e.g., Rnw-mode, electric "<" also inserts closing "@". Further, the code chunk boundaries are better kept up-to-date, such that code[R] <-> text[LaTeX] minor mode switching should happen more reliably. * In noweb-mode, fix a buglet in rare [Enter] or [Tab] behavior; further, by default disable the former '[[' .. ']]' code-protection-when-filling behavior which has been found to be buggy. Changes/New Features in 5.3.9: * ESS[SAS]: evince PDF viewer now supported as well; search order: evince, Xpdf, Adobe/Acrobat Reader * ESS[R]: added support for Roxygen, potentially to be extended. * ESS[S] (and R): inferior ('*R*') and transcript modes no longer fontify language keywords (such as 'for', 'in', etc). * iESS[Stata]: Customize the 'ess-sta-delimiter-friendly' setting to 't' to convert embedded semi-colons to newlines for Stata processing. * Sweave fix for embedded blanks in PDF reader and PDF files * Several fixes for Major Mode Convention violations in 'ess-mode' and 'noweb-mode'. * ESS[JAGS]: 'M-x comment-region' now available! * ESS[S] The 'ess-swv-*' commands (and keybindings) are now in a submenu of the "Noweb" menu, when editing Sweave files. Changes/New Features in 5.3.8: * ESS[JAGS]: more separation from ESS[BUGS] (as much as is currently planned); now 'C-c C-c' on an empty '.jmd' creates a template as it should; symbolic links are created for CODA output so BOA is happy: from 'index.txt' to '.ind' and 'chain#.txt' to '#.out' * ESS[SAS]: buffer-local 'ess-sas-submit-command' and 'ess-sas-submit-command-options' now recognized by 'ess-sas-submit-region' * ESS[S]: When trying to evaluate code in an S language buffer and there is no associated process, now start R automatically instead of signalling an error. Also, restart R if there is an associated process which is not running. However, do not start R just via the "electric" '(' ('ess-r-args-auto-show'). * ESS[S]: For (one-line) functions withOUT '{ .. }' bodys, the end of function is now correctly found more often. This notably improves 'C-c C-c' ('ess-eval-function-or-paragraph-and-step'). * ESS[JAGS]: cleanup/re-organization of Elisp code; symbolic links for CODA output are now only created by the new JAGS 'system' command in version 1.0.3; specify whether this command is available via 'ess-jags-system'; if not present, then no links are created so that the '*shell*' buffer does not become unresponsive during the batch run Changes/New Features in 5.3.7: * ESS: 'ess-default-style' now *is* customizable, i.e., changing its value in '~/.emacs' now does have the desired effect. * ESS: 'ess-font-lock-mode' is a new variable (default: t) which controls whether font-locking is enabled in ESS buffers. * ESS[R]: for XEmacs on Windows; another tweak to find R versions * ESS[SAS]: font-locking updated for ODS and SAS Bayesian Procedures; a more consistent handling of SAS options by 'ess-sas-submit-command-options' which is buffer-local; portable snooze for MS Windows via customize-able 'ess-sleep-for' (floats welcome); Xpdf now supported as a PDF viewer * ESS[Rnw]: now also works with "emacs -nw" and Emacs 22. * ESS[JAGS]: now requires JAGS 1.0 (see the new ESS for JAGS help section for more information): both need work; suggestions welcome * ESS[R]: [TAB] completion now uses the R-internal completion mechanism (for R >= 2.5.0). * ESS[R] ([S]): interpretation of "_" as assignment has been removed in 'ess-continued-statement-p' for R and S. * several internal code cleanups. * ESS[R]: An experimental version of a new command 'Rgui' on MS Windows to send lines directly from emacs to 'Rgui' is available in file 'lisp/essd-rgui.el'. Preliminary documentation is in file 'doc/rgui-doc.txt'. Changes/New Features in 5.3.6: * ESS: for XEmacs, using "gnuclient" (without a "-q") works for things like fix() after M-x gnuserv-start has been done. * ESS[R]: M-x R-newest should now work in more situations on MS Windows, e.g., when R has been installed in a non-default "ProgramFiles" directory tree. In these cases, there's no need to specify the name (and full path) of the R program anymore. * ESS[R]: For XEmacs, startup (with new tooltip code) works again. Changes/New Features in 5.3.5: * ESS[R] a new defun is available, 'M-x R-newest', which will start the newest version of R that it can find on your system. * ESS[R] add Sven Hartenstein's "R function arguments tips" functionality, via new file '../lisp/essd-r-args.el'. Note that this includes an "electric "("" behavior inside 'R-mode' which is _active by default_ and can be customized via 'ess-r-args-electric-paren'; i.e., use '(setq ess-r-args-electric-paren nil)' to turn it off. Further, 'ess-r-args-show-as' allows to switch to the "tooltip" mode. * ESS: functions 'ess-get-pdf-viewer' and *-ps-viewer; built on new customizable variables 'ess-pdf-viewer-pref' and 'ess-ps-viewer-pref'; currently used in 'ess-swv-PDF' and '*-PS'. * ESS[R] Improved 'ess-swv-PDF' to run pdf viewer only if pdflatex was ok * ESS[R] Improved 'ess-swv-weave' to start R automatically if none is running. * ESS: Do no longer ask _which_ ESS process to use if there is only one. Changes/New Features in 5.3.4: * ESS[R] now better work with options(error=recover); and the new default of CHM help files on windows. * ESS[R] some more cleanup in the "sweave" functions * miscellaneous fixes Changes/New Features in 5.3.3: * ESS[S] fix buglet (5.3.2 only) which left command prompt in "execute buffer" and hence help files. * new customizable variable 'ess-display-buffer-reuse-frames' set to true (which changes default behavior) such that execution or help *frames* are reused. Changes/New Features in 5.3.2: * Classic BUGS now supported by '(require 'essd-bugs)' with ESS[BUGS] and JAGS by '(require 'essd-jags)' with ESS[JAGS]. But, only one of them can be used at a time since they don't play nice together. Also, 'C-c C-c' is now bound to the function 'ess-bugs-next-action' ('F12' has been retired). And finally, note that 'essl-bug.el' is deprecated and the replacement is 'essl-bugs.el'. * ESS[R] Improved some of the "Sweave-make" functions (yet scarcely documented) in 'ess-swv.el'. * ESS[S] No longer mess with .Last.value (nor in other "languages"). Changes/New Features in 5.3.1: * See the docs for 2 ways to install ESS for XEmacs 1. by uncommenting the XEmacs part of Section 1 of 'Makeconf' and performing 'make install' 2. by unpacking either 'ess-5.3.1.tgz' or 'ess-5.3.1.zip' into 'PREFIX/lib/xemacs/site-packages' on unix or 'PREFIX\XEmacs\site-packages' on windows * ESS[R]: fixed bugs so that Rterm.exe can be found by XEmacs * ESS[S]: 'ess-toggle-S-assign-key' is slightly changed; in particular, the default 'ess-assign-key' is now 'C-x ='. * ESS[R]: 'M-x R-site-search' is a new (slightly experimental) utility similar to R's 'RSiteSearch(..)' but with the advantage of using Emacs' preferred browser, see 'browse-url-browser-function' Changes/New Features in 5.3.0: * ESS[BUGS]: sanely re-format statistical output, '.bog', from scientific notation to numbers rounded with 4 decimal places with 'M-x ess-bugs-sci-round-to-4-dp'. * The keys for navigating among section headings in help buffers worked, but only for one language per session; they should now work for multiple languages. (They were also broken on Windows machines.) * ESS[S] long standing buglets in the internal logic for loading Lisp code on Windows. Particularly fixed behavior in help mode with S-plus GUI. * New variable, 'ess-use-inferior-program-name-in-buffer-name', which enables using the executable name instead of the dialect name for R. Feature request. * ESS[S] 'ess-execute-screen-options' now also works correctly when there is more than one window *side-by-side* in the same frame and runs in the correct buffer also when there is more than one S buffer. * iESS[S] new functions 'ess-eval-paragraph-and-step' and 'ess-eval-function-or-paragraph-and-step' are bound to keys 'C-c C-p' and 'C-c C-c' respectively and to the menu in ESS-mode; also bound in the help mode (for evaluating examples). * ESS[S] new function 'ess-toggle-S-assign-key' allows to assign the " <- " insertion to an arbitrary key. Changes/New Features in 5.2.12: * ESS[SAS]: 'M-;' fixed, but the XEmacs function 'comment-dwim' may be broken, if so, use 'M-x comment-region' and 'M-x uncomment-region' instead; only valid PROCs are fontified which is very helpful finding syntax errors (currently supported: BASE, ETS, FSP, GRAPH, IML, INSIGHT and STAT); the "feature" where 'F'-keys take you to an empty buffer when the requested destination is a file that does not exist has been fixed, now the request results in a no-op. Further, sas-mode now also works in simple terminals. * Rterm/Cygwin combination works under Microsoft Windows. * ESS[R]: internal calls use baseenv() instead of NULL and define 'baseenv' where needed. * New experimental support for installing ESS. See the file 'lisp/ess-install.el'. Changes/New Features in 5.2.11: * ESS Info entry and 'dir' handled more effectively for GNU Emacs users * ESS[SAS]: temporary files created for batch submission of a region are now named based on the current file; see 'ess-sas-file-root' for details; all 'lag' and 'dif' functions now fontified correctly * iESS[SAS]: fixed a few nagging bugs, however, still does not appear to work at this time; please let us know if you have any ideas. * ESS[S]: Support for running other versions of Splus has been added for unix. Two new variables, 'ess-s-versions' and 'ess-s-versions-list', are used to tell ESS what other versions of Splus you would like to run. Changes/New Features in 5.2.10: * ESS[R]: ess-r-versions can no longer be customized (since the customization was not taking effect unless customizations were loaded before ESS). Its value has been changed so that it will also find R executables beginning "R-devel" and "R-patched". If you wish to change this variable, it must be set in your '.emacs' before ESS is loaded. * Installation with GNU Make enhanced: unix and unix-like operating systems will now be able to install ESS for all users in either a GNU Emacs site-lisp or an XEmacs package configuration by editing 'lisp/ess-site.el' and 'Makeconf' accordingly, then issuing 'make install' * ESS[S]: Filename completion (inside strings) now also works in XEmacs for R and S-plus. Changes/New Features in 5.2.9: * ESS[R] for Windows: the \ directory character bug with respect to ess-load-file has been eradicated. * iESS[SAS]: 'C-c C-r' and 'C-c C-b' once again work as intended and documented. * ESS[S]: M-x ess-fix-EQ-assign is a bit more aggressive. * ESS[S]: Imenu now also shows setAs(), etc. * ESS[R]: R function pattern enhanced with underlying code such that 'M-C-a' ('ess-beginning-of-function') etc now work for many more cases, including S4 method definitions. * iESS[R]: myOwnhelp(1) no longer wrongly triggers help(1). * ESS[R]: Improved detection of bogus help buffers: valid help buffers containing with the string "no documentation"(e.g. contour) were being treated as bogus. * ESS[R]: In R help buffers, if 'options("help.try.all.packages" = TRUE)' then '?rlm' will list which packages rlm is defined in. This help buffer is not bogus, but instead is now relabelled "*help[R](rlm in packages)*". * ESS[STA]: add "//" as comment starting character to syntax-table. Changes/New Features in 5.2.8: * iESS: [Tab] completes *file* names "inside string" as in earlier (<= 5.2.3) ESS versions. Changes/New Features in 5.2.7: * If you use Custom to change the variable ess-toolbar-items, the new toolbar is used in all subsequent ESS buffers. * ESS[SAS]: new feature: if ess-sas-log-max >0 and your .log grows to more than ess-sas-log-max bytes, just the first ess-sas-log-max bytes are refreshed; this is helpful when your .sas program generates lots of error messages and gets too big for emacs to display * ESS[R/S]: 'M-;' in R/S editing modes will now indent with either one or two hashes depending on context. * ESS[R]: David Whiting's Sweave extensions (to 'noweb') are now available (from ess-swv.el loaded by default). Changes/New Features in 5.2.6: * Removed non-ASCII characters in a few files. * ESS[R]: now works better when UTF-8 locale is active; in particular, you get correct directional quotes in R's startup message for R-devel (unstable development version of R 2.1.0) when using environment variables LANGUAGE=en@quot LC_ALL=en_US.UTF-8 * ESS[SAS]: toggling of .log mode improved ('F10'); toggling of .lst mode now also available ('C-F10'); killing all buffers associated with .sas program no longer bound to 'C-F10' since its a bit overzealous. * S-Plus 7 for Windows is now recognized. * ESS[S] (incl. R): in auto-fill mode, strings are not wrapped anymore. * ESS[S] (incl. R): font-lock now correctly differs between R and S, e.g., for "_"; both now fontify warning(.) and S does terminate() additionally. * Support for 'bell' aka 'beep' aka 'ding' aka 'alarm' in all inferior modes: When \a is output "to the the console" at the beginning of a line, the bell is rung. Changes/New Features in 5.2.5: * ESS[R]: 'C-c C-q' or 'Quit S' from the menu now should work (again and less klunkily) and do not append '-exited' to the buffer name. Further, the behavior of '(ess-cleanup)', called from ess-quit, now depends on the new customizable variable 'ess-S-quit-kill-buffers-p' which defaults to 'nil'. Consequently, the question _"Delete all buffers associated with ..?"_ will not be asked anymore by default. * ESS[SAS] - ess-ebcdic-to-ascii-search-and-replace will now work with the 'recode' application as well which is available on many platforms * ESS[S] (incl. R): Name completion for slots of S4 objects now works! Changes/New Features in 5.2.4: * The documentation now includes an overview of how to use the emacs TAGS facility for S functions. (The distribution also used to contain a directory 'etc/other/Tags' where a ~1990 version of 'etags.c' was distributed; this is no longer relevant and so has been deleted.) * ESS[SAS] - When you are working with EBCDIC files on an ASCII platform, .log NOTEs may display as gibberish since the EBCDIC characters are not converted to ASCII prior to their display. So, the function ess-ebcdic-to-ascii-search-and-replace is provided for convenience and is bound to 'C-F11'. This function requires the 'dd' command (only available on unix or unix-like platforms). * ESS: Completion of object names is now always done dynamically rather than allowing the option of using a pre-computed database (by 'ess-create-object-name-db') since modern computers seem fast enough for dynamic completion. (We expect few users, if any, have been using the pre-computed database method.) * ESS: object completion in iESS buffers running on Windows was very slow (for GNU Emacs, but not XEmacs) and has now been fixed. Further, it was more or less broken for all versions of S-plus 6.x, and has been fixed to work everywhere but with the Windows' GUI of S-plus. The list of objects now shows unique names also when an object appears more than once in the search path. * ESS[R]: Completion of object names now also includes those starting with ".". Changes/New Features in 5.2.3: * ESS: When new inferior ESS processes are created, by default they will replace the current buffer (this restores behavior from pre 5.2.0). If you wish new ESS processes to start in another window of the current frame, set inferior-ess-same-window to nil. * New variables inferior-Splus-args and inferior-R-args provide a way to pass command line arguments to starting S and R processes. Changes/New Features in 5.2.2: * bug-fixes for 5.2.1 (require 'executable), html docs, etc. * ess-lisp-directory/../doc/info added to Info-directory-list if ess-info not found by info * ESS[R]: If you have other versions of R on your exec-path, such as "R-1.8.1" with Unix or "rw1081" with Windows, ESS will find them and create appropriate functions, such as 'M-x R-1.8.1' or 'M-x rw1081', for calling them. By default only Unix programs beginning "R-1" and "R-2" and Windows programs parallel to the version of R in your exec-path will be found, but see ess-r-versions and ess-rterm-versions for ways to find other versions of R. * ESS[R]: Other versions of R, such as "R-1.8.1" on Unix and "rw1081" on Windows, are added to the "ESS / Start Process / Other" menu. * ESS[S]: If you have other versions of S-Plus on your Windows computer, such as S-Plus 6.1 or S-Plus 4.5, ESS will find them and create appropriate functions, such as 'M-x splus61', for calling the console version (Sqpe) inside an emacs buffer. By default only programs installed in the default location will be found, but see ess-SHOME-versions for ways to find other versions of S-Plus. * ESS[S]: Other versions of Sqpe on Windows, such as "splus61", are added to the "ESS / Start Process / Other" menu. * ESS[R]: (bug fix) ess-quit (bound to 'C-c C-q') should now quit the inferior R process, when issued from either the inferior buffer, or from a .R buffer. Changes/New Features in 5.2.1: * ESS[S] (R and S-plus): now have toolbar support with icons to evaluate code in the inferior process or to switch there. This code is experimental and likely to change as XEmacs/Emacs issues get resolved. The toolbar should be enabled if your Emacs displays images, but can be disabled with the variable ess-use-toolbar. Thanks to David Smith from Insightful for the S-plus logo. * ESS[SAS]: ess-sas-graph-view ('F12') enhanced; you can specify external file viewers for each graphics file type via the alist ess-sas-graph-view-viewer-alist; also .jpg/.gif are now handled by image-mode on XEmacs, if available, otherwise by graphics primitives as before Changes/New Features in 5.2.0: * ESS[BUGS]: new info documentation! now supports interactive processing thanks to Aki Vehtari (mailto:Aki.Vehtari@hut.fi); new architecture-independent unix support as well as support for BUGS v. 0.5 * ESS[SAS]: convert .log to .sas with ess-sas-transcript; info documentation improved; Local Variable bug fixes; SAS/IML statements/functions now highlighted; files edited remotely by ange-ftp/EFS/tramp are recognized and pressing SUBMIT opens a buffer on the remote host via the local variable ess-sas-shell-buffer-remote-init which defaults to "ssh"; changed the definition of the variable ess-sas-edit-keys-toggle to boolean rather than 0/1; added the function ess-electric-run-semicolon which automatically reverse indents lines containing only "run;"; 'C-F1' creates MS RTF portrait from the current buffer; 'C-F2' creates MS RTF landscape from the current buffer; 'C-F9' opens a SAS DATASET with PROC INSIGHT rather than PROC FSVIEW; "inferior" aliases for SAS batch: 'C-c C-r' for submit region, 'C-c C-b' for submit buffer, 'C-c C-x' for goto .log; 'C-c C-y' for goto .lst * ESS[S]: Pressing underscore ("_") once inserts " <- " (as before); pressing underscore twice inserts a literal underscore. To stop this smart behaviour, add "(ess-toggle-underscore nil)" to your .emacs after ess-site has been loaded; ess-dump-filename-template-proto (new name!) now can be customized successfully (for S language dialects); Support for Imenu has been improved; set ess-imenu-use-S to non-nil to get an "Imenu-S" item on your menubar; ess-help: Now using nice underlines (instead of 'nuke-* ^H_') * ESS[R]: After (require 'essa-r), 'M-x ess-r-var' allows to load numbers from any Emacs buffer into an existing *R* process; 'M-x ess-rdired' gives a "directory editor" of R objects; fixed ess-retr-lastvalue-command, i.e. .Last.value bug (thanks to David Brahm) * ESS: Support for creating new window frames has been added to ESS. Inferior ESS processes can be created in dedicated frames by setting inferior-ess-own-frame to t. ESS help buffers can also open in new frames; see the documentation for ess-help-own-frame for details. (Thanks to Kevin Rodgers for contributing code.) Changes/New Features in 5.1.24: * The version number is now correct even inside ESS/Emacs Changes/New Features in 5.1.23: * Minor more Makefile clean up. Changes/New Features in 5.1.22: * Besides info documentation, PDF and HTML documentation are also provided (instead of built using "make") and available on the web as well; see ESS web page (https://ess.r-project.org/) and StatLib (http://lib.stat.cmu.edu/general/ESS/doc) * Now that info documentation is available, the README.* files are no longer supported. However, they are still distributed for what it's worth. * ESS is now an XEmacs package! See XEmacs Installation HOWTO (https://www.xemacs.org/Install/index.html) for details (specifically, items 10-15). * ESS[SAS]: more user-friendly enhancements for remote SAS batch jobs with Kermit file transfers (LOG and OUTPUT function key features now supported). Multiple shells now supported so you can run SAS on different computers from different buffers by setting the buffer-local variable ess-sas-shell-buffer to unique buffer names. * Major re-vamping of Makefile/Makeconf. Changes/New Features in 5.1.21: * ESS[SAS]: info documentation now available!, see ESS->Help for SAS; 'F12' opens GSASFILE nearest point for viewing either within emacs, when available, or via an external viewer; more syntax highlighting keywords; more enhancements for remote SAS batch jobs with Kermit; new framework for remote SAS interactive jobs, see ess-remote * ESS[S]: info documentation now available!, see ESS->Help for the S family * Makefile: tag now independent of rel; info files made by doc/Makefile and installed in new info sub-directory Changes/New Features in 5.1.20: * New 'options()$STERM' in the S dialects (S, S-Plus, R). The S program can determine the environment in which it is currently running. ESS sets the option to 'iESS' or 'ddeESS' when it starts an S language process. We recommend other specific values for S language processes that ESS does not start. * New 'ess-mouse-me' function, assigned to S-mouse-3 by default. User may click on a word or region and then choose from the menu to display the item, or a summary, or a plot, etc. This feature is still under development. * GNU Emacs 21.1 is now supported (fixed for S dialects, SAS & BUGS), (some from Stephen Eglen). * XEmacs 21.x is now supported (fixed w32-using-nt bug) * XEmacs on Win (NT) is better supported. * Workaround for bug in Sqpe+6 (S-PLUS 6 for Win). * should now work even when imenu is not available (for old XEmacsen). * ESS[SAS]: XEmacs-Imenu fix; 'C-TAB' is globalized along with your function-key definitions, if specified; you can specify your SAS library definitions outside of autoexec.sas for ess-sas-data-view with SAS code placed in the variable ess-sas-data-view-libname, also the dataset name is defaulted to the nearest permanent dataset to point; Speedbar support now works for permanent datasets, please ignore first./last.; new font-locking is now the default with more improvements for font-locking PROCs, macro statements, * ; and %* ; comments; you can toggle sas-log-mode with 'F10' which will font-lock your .log (if it isn't too big); submit remote .sas files accessed with ange-ftp, EFS or Tramp (Kermit is experimental) by setting ess-sas-submit-method to 'sh; ess-sas-submit-command and ess-sas-submit-command-options are buffer-local so you can have local file variable sections at the end of your .sas files to request different executables or specify special options and the local file variables are re-read at submit instead of only at file open so that if you make a change it is picked up immediately; * ESS[BUGS]: font-lock with 'in' fixed. * for STATA: font-lock bug fixed. * for Rd mode: 'C-c C-v' and 'switch-process' in menu. further, 'C-c C-f' prefix (Rd-font) for inserting or surrounding a word by things such as \code{.}, \code{\link{.}}, \emph{.} etc. * new functions (ess-directory-function) and (ess-narrow-to-defun) ess-directory <-> default-directory logic (Jeff Mincy). * Re-organized Makefile and fixed a few bugs. Changes/New Features in 5.1.19: * S+6 now supported (Tony Rossini (Unix) and Rich Heiberger (Windows)) * New BUGS support through ESS[BUGS] mode (Rodney Sparapani) Templates assist you in writing .bug and .cmd code (.cmd and .log are replaced by .bmd and .bog to avoid emacs extension collisions). Substitution" parameters facilitate "automagic" generation of data...in" and "init...in" filenames, "const N=" from your data file and "monitor()/stats()" commands. Activated by pressing 'F12'. * Fixes for 'ess-smart-underscore' SAS breakage (Rich Heiberger) * You can change between PC and Unix, local and global SAS function-key definitions interactively (Rich Heiberger) * 'C-Submit' a highlighted region to SAS batch (Rodney Sparapani) * New and improved SAS syntax highlighting (Rodney Sparapani) To get the new functionality, set ess-sas-run-make-regexp to nil. Also available in .log files via 'F10'. * Open a permanent SAS dataset for viewing via 'F9' (Rodney Sparapani) You must have the library defined in autoexec.sas for it to work. * User-friendly defaults for 'sas-program', 'ess-sas-batch-pre-command' and 'ess-sas-batch-post-command' as well Customize support for these and other ESS[SAS] variables (Rodney Sparapani) * 'ess-sas-suffix-2' now defaults to .dat via 'F11' (Rodney Sparapani) * Emacs/XEmacs, Unix/Windows issues collectively handled in ess-emcs.el * defadvice solves problem of missing *ESS* (thanks to Jeff Mincy) * Improved manual a bit by including things that were only in 'README'. Changes/New Features in 5.1.18: * New 'ess-smart-underscore' function, now assigned to "_" by default. Inserts 'ess-S-assign' (customizable " <- "), unless inside string and comments where plain "_" is used instead. (MM) * Fixes for longstanding interactive SAS breakage (RMH) Changes/New Features in 5.1.17: * Documentation for Windows Installation (Rich Heiberger) * removal of ess-vars, finalization of customize support (in the sense that there is no more use of ess-vars, but that we need to fix ess-cust) (AJ Rossini) * Many small (and large) fixes/contributions (MMaechler) * addition of the "S-equal" variable and provide 'M-x ess-add-MM-keys' a way to remap "_" to 'ess-S-assign', typically " <- ", but customizable. (MMaechler) Changes/New Features in 5.1.16: * BUG FIXES * Better SAS support Changes/New Features in 5.1.15: * BUG FIXES Changes/New Features in 5.1.14: * Yet more fixes to SAS mode, (Rich Heiberger and Rodney Sparapani) * Customize support (for most Emacsen which support it) (AJRossini) * ARC and ViSta support out of the box, and fixes for XLispStat (AJRossini) Changes/New Features in 5.1.13: * Version numbering finally all depending on the ./VERSION file, thanks to Martin Maechler. * Yet more fixes to SAS mode, thanks to Rich Heiberger. Changes/New Features in 5.1.12: * Splus 5.1 stabilized, thanks to Martin Maechler, Bill Venables, Chuck Taylor, and others. * More fixes to SAS mode, thanks to Rodney Sparapani and Rich Heiberger. Changes/New Features in 5.1.11: * More fixes to Stata mode, thanks to Brendan Halpin (mailto:brendan@essex.ac.uk). * fixed bugs in ESS-elsewhere, thanks to many testers * README.SPLUS4WIN has DETAILED instructions for S-PLUS 2000, thanks to David Brahm (mailto:brahm@alum.mit.edu). * Fixes to SAS mode, thanks to Rodney Sparapani Changes/New Features in 5.1.10: * More fixes to Stata mode * primitive generic version of ESS-elsewhere * Small fixes to SAS/Stata. Changes/New Features in 5.1.9: * Stata mode works * Literate Data Analysis using Noweb works Changes/New Features in 5.1.8: * Bug fixes * R documentation mode defaults changed Changes/New Features in 5.1.2: * able to use inferior iESS mode to communicate directly with a running S-Plus 4.x process using the Microsoft DDE protocol. We use the familiar (from Unix ESS) 'C-c C-n' and related key sequences to send lines from the S-mode file to the inferior S process. We continue to edit S input files in ESS[S] mode and transcripts of previous S sessions in ESS Transcript mode. All three modes know the S language, syntax, and indentation patterns and provide the syntactic highlighting that eases the programming tasks. ESS-24.01.1/README.md000066400000000000000000000006341455642170100136000ustar00rootroot00000000000000[![Build Status](https://travis-ci.org/emacs-ess/ESS.svg?branch=master)](https://travis-ci.org/emacs-ess/ESS) [![MELPA Stable](http://stable.melpa.org/packages/ess-badge.svg)](https://stable.melpa.org/#/ess) [![MELPA](http://melpa.org/packages/ess-badge.svg)](https://melpa.org/#/ess) # ESS Git development branch of Emacs Speaks Statistics: ESS. For more info, see our web page at https://ess.r-project.org/ ESS-24.01.1/RPM.spec.in000066400000000000000000000075171455642170100142470ustar00rootroot00000000000000# This is an RPM spec file that specifies how to package # ESS for Fedora Core Linux and, possibly, similar systems. %define name emacs-ess %define version @@VERSION@@ %define release 1.tgm Summary: Emacs Speaks Statistics add-on package for Emacs Name: %{name} Version: %{version} Release: %{release} Copyright: GPL Group: Applications/Editors Source: https://ESS.R-project.org/downloads/ess/ess-%{version}.tgz URL: https://ESS.R-project.org/ Packager: Detlef Steuer <.........de> BuildRoot: %{_tmppath}/%{name}-root Prefix: %{_prefix} BuildArchitectures: noarch BuildRequires: emacs Requires: emacs %description This package provides Emacs Speaks Statistics (ESS), which provides Emacs-based front ends for popular statistics packages. ESS provides an intelligent, consistent interface between the user and the software. ESS interfaces with S-PLUS, R, SAS, BUGS and other statistical analysis packages under the Unix, Microsoft Windows, and Apple Mac OS operating systems. ESS is a package for the GNU Emacs text editors whose features ESS uses to streamline the creation and use of statistical software. ESS knows the syntax and grammar of statistical analysis packages and provides consistent display and editing features based on that knowledge. ESS assists in interactive and batch execution of statements written in these statistical analysis languages. %prep %setup -n ess-%{version} ( cd doc && chmod u+w html info ) # fix perms to ensure builddir can be deleted %build make # create an init file that is loaded when a user starts up emacs to # tell emacs to autoload our package's Emacs code when needed cat > %{name}-init.el <<"EOF" ;;; Set up %{name} for Emacs. ;;; ;;; This file is automatically loaded by emacs's site-start.el ;;; when you start a new emacs session. (require 'ess-site) EOF # create a README.RPM file to document any quirks of this package cat > README.RPM < EOF %install %{__rm} -rf ${RPM_BUILD_ROOT} INITDIR=${RPM_BUILD_ROOT}%{_datadir}/emacs/site-lisp/site-start.d PKGLISP=${RPM_BUILD_ROOT}%{_datadir}/emacs/site-lisp/%{name}-%{version} INFODIR=${RPM_BUILD_ROOT}%{_infodir} %{__install} -D %{name}-init.el $INITDIR/%{name}-init.el %{__install} -d $PKGLISP %{__install} -d $INFODIR %{__make} install \ PREFIX=${RPM_BUILD_ROOT}%{_prefix} \ LISPDIR=$PKGLISP \ INFODIR=$INFODIR %{__rm} -f $INFODIR/dir # don't package but instead update in pre and post %{__cp} -a etc $PKGLISP # tuck ess's /etc into lisp dir for easy transport # Uncomment to print the README file after install. # # %post # echo # cat %{_defaultdocdir}/%{name}-%{version}/README.RPM # echo %clean %{__rm} -rf ${RPM_BUILD_ROOT} %files %defattr(-,root,root) %doc README README.RPM ANNOUNCE COPYING VERSION ChangeLog doc %dir %{_datadir}/emacs/site-lisp/%{name}-%{version} %{_datadir}/emacs/site-lisp/%{name}-%{version}/* %{_datadir}/emacs/site-lisp/site-start.d/* %{_infodir}/*.gz %post [ -f /usr/share/info/ess.info.gz ] && \ /sbin/install-info /usr/share/info/ess.info.gz /usr/share/info/dir || : %preun if [ $1 = 0 ]; then [ -f /usr/share/info/ess.info.gz ] && \ /sbin/install-info --delete /usr/share/info/ess.info.gz \ /usr/share/info/dir || : fi %changelog * Fri Oct 15 2004 Tom Moertel 5.2.3-1.tgm - Updated to ESS 5.2.3. * Fri Aug 27 2004 Tom Moertel 5.2.2-3.tgm - Updated ESS URL. - Fixed Summary. * Fri Aug 27 2004 Tom Moertel 5.2.2-2.tgm - Fixed bug: Forgot to include ESS's etc/ directory. * Thu Aug 26 2004 Tom Moertel 5.2.2-1.tgm - Initial build. ESS-24.01.1/VERSION000066400000000000000000000000101455642170100133550ustar00rootroot0000000000000024.01.1 ESS-24.01.1/doc/000077500000000000000000000000001455642170100130635ustar00rootroot00000000000000ESS-24.01.1/doc/CONTRIBUTING.org000066400000000000000000000021321455642170100155010ustar00rootroot00000000000000* Contributing code Please make sure your contribution: - Does not introduce any byte compilation warnings or cause existing tests to fail (=make test=) - Satisfies M-x checkdoc We follow standard Elisp coding conventions with the following exceptions: - =indent-tabs-mode= should be =nil= - =sentence-end-double-space= should be =nil= Both of these are taken care of by the .dir-locals.el file. We do not require internal functions to be documented if their name is descriptive enough. If you have contributed to ESS in the past but changed your git username or email, please add the proper alias to .mailmap (see git-shortlog(1) for the format). ** FSF copyright assignment Unless your change is less than about 15 lines of code, you must assign copyright to the FSF. This is the same process that Emacs itself and all packages in GNU ELPA use (the paperwork can cover both). Instructions for this process can be found [[https://git.savannah.gnu.org/cgit/gnulib.git/tree/doc/Copyright/request-assign.future][here]]. If you have already signed the paperwork for GNU Emacs, nothing else needs to be done. ESS-24.01.1/doc/Makefile000066400000000000000000000051131455642170100145230ustar00rootroot00000000000000include ../Makeconf TEXISRC = announc.texi authors.texi bugrept.texi bugs.texi \ credits.texi currfeat.texi ess.texi ess-defs.texi \ help-s.texi help-sas.texi installation.texi \ license.texi mailing.texi onewfeat.texi news.texi onews.texi \ newfeat.texi requires.texi help-bugs.texi \ help-jags.texi allnews.texi Makefile ../Makeconf ../VERSION PDFs = ess.pdf readme.pdf refcard/refcard.pdf TXTs = ../README ../ANNOUNCE ../NEWS ../ONEWS # Don't build pdf/html by default all : info text info : info/ess.info text : $(TXTs) html : html/ess.html html/readme.html html/news.html pdf : $(PDFs) ess.pdf : $(TEXISRC) $(TEXI2PDF) ess.texi readme.pdf : $(TEXISRC); $(TEXI2PDF) readme.texi distclean clean: @rm -f *.aux *.cp *.cps *.fn *.fns *.ky *.kys *.log *.out \ *.pg *.pgs *.tmp *.toc *.tp *.vr *.vrs @rm -f refcard/*.aux refcard/*.log @rm -f $(TXTs) $(PDFs) info/*.info* \ html/* *.info dir ../README: $(TEXISRC) -$(MAKETXT) readme.texi \ | perl -pe 'last if /^Concept Index/;' > $@ ../ANNOUNCE: $(TEXISRC) -$(MAKETXT) announc.texi \ | perl -pe 'last if /^Concept Index/;' > $@ ../NEWS: Makefile ess-defs.texi newfeat.texi news.texi -$(MAKETXT) news.texi > $@ ../ONEWS: Makefile ess-defs.texi onewfeat.texi onews.texi -$(MAKETXT) onews.texi > $@ ### File Dependencies info/ess.info: $(TEXISRC) ../VERSION @echo "making Info documentation..." -$(MAKEINFO) ess.texi mv -f ess.info info/ install: install-info install-other-docs install-info : info/ess.info -$(INSTALLDIR) $(INFODIR) $(INSTALL) info/ess.info $(INFODIR) $(INSTALL) info/dir $(INFODIR) grep $(ESSINFONODE1) $(INFODIR)/dir || \ (echo >> $(INFODIR)/dir; echo 'Emacs' >> $(INFODIR)/dir; \ echo $(ESSINFONODE1) $(ESSINFONODE2) >> $(INFODIR)/dir; \ echo $(ESSINFONODE3) >> $(INFODIR)/dir) install-other-docs: pdf html -$(INSTALLDIR) $(DOCDIR) $(INSTALL) ess.pdf readme.pdf $(DOCDIR) $(INSTALL) html/ess.html html/readme.html html/news.html $(DOCDIR) $(INSTALL) refcard/refcard.pdf $(DOCDIR) uninstall : -cd $(DOCDIR) && $(UNINSTALL) ess.pdf readme.pdf README ANNOUNCE -cd $(DOCDIR) && $(UNINSTALL) ess.html readme.html news.html -cd $(DOCDIR) && $(UNINSTALL) refcard.pdf ## TO DO: ess_toc.html & readme_toc.html should be merged into index.html html/ess.html: $(TEXISRC) @echo "making HTML documentation..." mkdir -p html -$(MAKEHTML) html/ess.html ess.texi html/readme.html: $(TEXISRC) -$(MAKEHTML) html/readme.html --no-validate readme.texi html/news.html: $(TEXISRC) mkdir -p html -$(MAKEHTML) html/news.html allnews.texi refcard/refcard.pdf: refcard/refcard.tex (cd refcard ; pdflatex refcard) ESS-24.01.1/doc/allnews.texi000066400000000000000000000001561455642170100154250ustar00rootroot00000000000000@settitle ESS -- Emacs Speaks Statistics @include ess-defs.texi @include newfeat.texi @include onewfeat.texi ESS-24.01.1/doc/announc.texi000066400000000000000000000050231455642170100154170ustar00rootroot00000000000000\input texinfo @c -*-texinfo-*- @comment %**start of header @setfilename announc.info @settitle ESS - Emacs Speaks Statistics @comment %**end of header @include ess-defs.texi @node Announce @chapter ANNOUNCING ESS @cindex ANNOUNCE The ESS Developers proudly announce the release of ESS @include ../VERSION @c -------------------------------------------------------------------- Emacs Speaks Statistics (ESS) provides an intelligent, consistent interface between the user and the software. ESS interfaces with R/S-PLUS, SAS, BUGS/JAGS, Stata and other statistical analysis packages under the UNIX, GNU Linux, Microsoft Windows, macOS and other operating systems. ESS is a package for the GNU Emacs text editor whose features ESS uses to streamline the creation and use of statistical software. ESS knows the syntax and grammar of statistical analysis packages and provides consistent display and editing features based on that knowledge. ESS assists in interactive and batch execution of statements written in these statistical analysis languages. ESS is freely available under the GNU General Public License (GPL). Please read the file COPYING which comes with the distribution, for more information about the license. For more detailed information, please read the README files that come with ESS. @c And to clear up any possible confusion; the name is ESS, NOT ESS-mode. @c Thank you :-). @menu * Latest Version:: * Current Features:: * Requirements:: * Mailing List:: * Reporting Bugs:: * Authors:: * License:: * New Features:: @end menu @node Latest Version, Current Features, Announce, Announce @section Getting the Latest Version @include installation.texi @node Current Features, Requirements, Latest Version, Announce @section Current Features @include currfeat.texi @node Requirements, Mailing List, Current Features, Announce @section Requirements @include requires.texi @node Mailing List, Reporting Bugs, Requirements, Announce @section Mailing List @include mailing.texi @node Reporting Bugs, Authors, Mailing List, Announce @section Reporting Bugs @include bugrept.texi @node Authors, License, Reporting Bugs, Announce @section Authors @include authors.texi @node License, New Features, Authors, Announce @section License @include license.texi @node New Features, , License, Announce @section New Features @include newfeat.texi @bye @c Remember to delete these lines before creating the info file. @iftex @lucidbook @bindingoffset = 0.5in @parindent = 0pt @end iftex @comment Local Variables: @comment TeX-master: "announc.texi" @comment End: ESS-24.01.1/doc/atouchofstyle.css000066400000000000000000000167211455642170100164750ustar00rootroot00000000000000/* 6 January 2007: - minor cleanup - add CSS3 selectors */ html { margin: 0px; padding: 0px; border-top: 1.4em #000033 solid; font-size: 12px; background-repeat: no-repeat; background-attachment: fixed; background-position: top left; background-color: white; } body { margin: 0px; padding: 0px; font-family: "Trebuchet MS", Arial, sans-serif; color: #171717; line-height: 1.45; /* something smart Eric Meyer said: no unit here */ text-align: justify; width: 40em; padding-left: 15em; padding-right: 2em; border-right: 1px #000033 dotted; } h1 { padding: 2em 1em 2em 1em; font-size: 2em; color: white; text-align: right; margin-left: -10em; margin-top: 0em; margin-right: -1em; background-image: url(../images/logoESS.gif); background-position: left 25%; -o-background-size: 100% auto; background-size: 100% auto; background-origin: content; border-bottom: 0.4em #000033 solid; border-left: 0.1em #000033 solid; text-transform: uppercase; text-shadow: white 0px 0px 10px, black 3px 3px 5px; } h2 { font-size: 1.4em; border-left: 0.6em black solid; padding-left: 0.3em; border-bottom: 1px black solid; padding-bottom: 0.1em; margin-top: 1.5em; letter-spacing: 0.1em; } h3 { margin-bottom: 0em; } h2,h3 { clear: both; } h1 span { font-size: 0.7em; color: #EFEFEF; } h2 span { font-size: 0.7em; color: gray; } h2[id]:hover::after, h3[id]:hover::after { content: "#" attr(id); float:right; font-size:0.7em; /*line-height:2em;*/ color: maroon; padding-left: 1em;} p { margin-top: 0px; margin-bottom: 0.5em;} dt { font-weight: bold; margin: 10px 0px 2px 0px; padding: 2px 0px; border-top: 1px black solid; border-bottom: 1px black solid; text-indent: 1em; letter-spacing: 0.1em; position: relative; } dd + dd { margin-top: 0.7em; } table { font-size: inherit; } /* so that the font-size is inherited into table */ small { margin-top: 2em; display:block; clear: both; } pre { padding: 0.5em; border: 1px gray solid; overflow:auto; background-color: #EFEFEF; } kbd { border: 2px gray outset; padding: 0em 0.1em; background-color: white; } kbd:active { border: 2px gray inset;} img.left { float: left; clear: both; margin-right: 1em; margin-bottom: 0.5em; margin-top: 0.3em; max-width: 45%; } img.right { float: right; clear: both; margin-left: 1em; margin-bottom: 0.5em; margin-top: 0.3em; max-width: 45%; } /* link styles */ a:link, a:visited {color: navy; text-decoration: none; font-weight: bold;} p:hover a, p:hover + p a, ul:hover a, dl:hover a, table:hover a { text-decoration: underline; } a:hover { text-decoration: none !important; border-width: 1px 0px; border-style: none; color: green; background-color: #efefef;} /* navigation menu */ #navmenu { width: 150px; position: fixed; /* f*ck, Opera 8 'loses' abs positioned content within fixed */ position: absolute; top: 0px; right: 0px; padding: 0px; margin: 0px; display: none; /* the TOC script will make it appear */ text-align: left; } #navmenu > li:first-child { font-weight: bold; color: white; background-color: #000033; } #navmenu li { line-height: 1.4em; padding-left: 3px; list-style-type: none; background-color: #2E2E58; color: white; margin: 0px 0px 1px 0px; position: relative; } #navmenu li:hover { background-color: maroon; color: white; } #navmenu > li:first-child:hover { width: auto; right: 0px; } #navmenu > li:hover { width: 298px; position: relative; right: 151px; font-weight: bold; } #navmenu li:hover > ul { display: block; } #navmenu li ul { margin: 0px; padding: 0px; position: absolute; top: 1.4em; right: 141px; width: 150px; margin-top: -9px; /* 1px between list, but with 10px padding */ padding-top: 10px; padding-right: 10px; /* so that the box still overlap; helps with hovering */ font-weight: normal; display:none; } #navmenu li ul li { padding-left: 0px; } /*the links should fill to full size of list item */ #navmenu li a { display: block; text-decoration:none !important; color:white; padding-left: 3px; } #navmenu li a:hover { border-style: none !important; background-color: inherit !important;} #navmenu #toc li.h2 a { padding-left: 0.3em; font-size: 0.9em; font-weight:bold;} #navmenu #toc li.h3 a { padding-left: 0.8em; font-size: 0.8em;} #navmenu #toc li.h4 a { padding-left: 1.2em; font-size: 0.8em; font-style: italic; } /* for IE: with some scripting and these styles the menus also work in IE */ /* Do not put complex selectors IE does not understand in same style declaration!! */ #navmenu li.first { color: white; background-color: #000033; } #navmenu li.expand ul { display: block; } #navmenu li.expand { width: 299px; position: relative; margin-left: -152px; font-weight: bold; background-color: maroon; color: white; } #navmenu li.expand a:hover { background-color: maroon; } #navmenu ul.ulhover { display:block; background-color: #CDD5DD; /* background-color so there's a background so hovering works... */ padding-top: 1px; margin-top: 0px; margin-right: 0em;} /* -------- Requires CSS3 Selectors (O9, IE7, FF, SF) -------- */ /* well implemented by http://www.askthecssguy.com/2006/12/showing_hyperlink_cues_with_cs_1.html */ a[href$='.pdf'], a[rel='pdf'], a[rel*='pdf'], a[rel~='pdf'] { padding-right: 18px; background: transparent url(../images/icons/icon_pdf.png) no-repeat center right; } a[href^="mailto:"] { padding-right: 18px; background: transparent url(../images/icons/icon_mailto.png) no-repeat center right; } a[class ="popup"] { padding-right: 18px; background: transparent url(../images/icons/icon_popup.png) no-repeat center right; } a[href$='.doc'] { padding-right: 18px; background: transparent url(../images/icons/icon_doc.png) no-repeat center right; } a[href$='.xls'] { padding-right: 18px; background: transparent url(../images/icons/icon_xls.png) no-repeat center right; } a[href$='.ppt'] { padding-right: 18px; background: transparent url(../images/icons/icon_ppt.png) no-repeat center right; } a[rel ~='external'] { padding-right: 18px; background: transparent url(../images/icons/icon_external.png) no-repeat center right; } /* faviconize script needs some styling */ img.faviconimg { max-width: 1.1em; margin: 0; padding: 0; margin-left: 2px; border-width: 0px; vertical-align: top; opacity: 0.5; } a:hover img.faviconimg { opacity:1; } p:hover a img, p:hover + p a img, ul:hover a img, dl:hover a img, table:hover a img{ opacity:1; } /* -------- page specific stuff -------- */ /* Sortable tables */ table.sortable span.sortarrow { color: black; padding-left: 0.5em; font-family: sans-serif; } table.sortable th { vertical-align: middle; cursor: pointer; } /* CSS Exp style */ dt span.expdate { font-size: 0.7em; line-height: 2em; color:gray; position:absolute;right:0em;} /* -------- various media styles -------- */ @media print { html, body { border-style:none; margin: 0px; padding: 0px; font-size: 10pt; width: 100%; background-color: transparent;} h1 { border-style: none; } h1:first-letter { margin: 0px; border-style: none; } #navmenu { display:none !important; } h1, h2, h3 { page-break-after: avoid; } img { width: auto; max-width: 100%; } } @media projection { html { font-size: 1.2em; } body { width: auto; padding-left: 3em; } } /* voice styles */ @media speech { title { display:block; speak:normal; } h1, h2, h3 { voice-family: female; } p, dl, ul, ol { voice-family: male; } acronym { speak:spell-out; voice-family: female; } abbr[title]::after { content: "This abbreviation means" attr(title); speak:normal; } acronym[title]::after { content: "This acronym means" attr(title); speak:normal; } } ESS-24.01.1/doc/authors.texi000066400000000000000000000027751455642170100154560ustar00rootroot00000000000000@c ---- KEEP this synchronized with the @author entries in @c ./ess.texi @c ~~~~~~~~~~ @itemize @bullet @item @c @uref{https://www.google.com/,A.J. Rossini} @uref{mailto:blindglobe@@gmail.com, A.J. Rossini} @c -------- @item @c @uref{https://www.sbm.temple.edu/departments/statistics/,Richard M. Heiberger} @uref{mailto:rmh@@temple.edu, Richard M. Heiberger} @c -------- @item @c @uref{https://www.ci.tuwien.ac.at/~hornik,Kurt Hornik} @uref{mailto:Kurt.Hornik@@R-project.org, Kurt Hornik} @c -------- @item @c @uref{https://stat.ethz.ch/people/maechler/,Martin Maechler} @uref{mailto:maechler@@stat.math.ethz.ch, Martin Maechler} @c -------- @item @c @uref{https://www.mcw.edu/pcor/rsparapa,Rodney A. Sparapani} @uref{mailto:rsparapa@@mcw.edu, Rodney A. Sparapani} @c -------- @item @c @uref{https://www.damtp.cam.ac.uk/user/eglen,Stephen Eglen} @uref{mailto:stephen@@gnu.org, Stephen Eglen} @c -------- @item @c @uref{https://www.ucs.mun.ca/~sluque,Sebastian P. Luque} @uref{mailto:spluque@@gmail.com, Sebastian P. Luque} @c -------- @item @c @uref{https://www.google.com,Henning Redestig} @uref{mailto:henning.red@@googlemail.com, Henning Redestig} @c -------- @item @c @uref{http://github.com/vspinu, Vitalie Spinu} @uref{mailto:spinuvit@@gmail.com, Vitalie Spinu} @c -------- @item @c @uref{https://github.com/lionel-, Lionel Henry} @uref{mailto:lionel.hry@@gmail.com, Lionel Henry} @c -------- @item @c @uref{https://jabranham.com/, J. Alexander Branham} @uref{mailto:alex.branham@@gmail.com, J. Alexander Branham} @end itemize ESS-24.01.1/doc/bugrept.texi000066400000000000000000000013511455642170100154260ustar00rootroot00000000000000Please send bug reports, suggestions etc. to @email{ESS-bugs@@r-project.org}, or post them on our @uref{https://github.com/emacs-ess/ESS/issues, github issue tracker} The easiest way to do this is within Emacs by typing @kbd{M-x ess-submit-bug-report} This also gives the maintainers valuable information about your installation which may help us to identify or even fix the bug. If Emacs reports an error, backtraces can help us debug the problem. Type "M-x set-variable RET debug-on-error RET t RET". Then run the command that causes the error and you should see a *Backtrace* buffer containing debug information; send us that buffer. Note that comments, suggestions, words of praise and large cash donations are also more than welcome. ESS-24.01.1/doc/bugs.texi000066400000000000000000000027611455642170100147240ustar00rootroot00000000000000@itemize @bullet @item Commands like @code{ess-display-help-on-object} and list completion cannot be used while the user is entering a multi-line command. The only real fix in this situation is to use another ESS process. @item The @code{ess-eval-} commands can leave point in the ESS process buffer in the wrong place when point is at the same position as the last process output. This proves difficult to fix, in general, as we need to consider all @emph{windows} with @code{window-point} at the right place. @item It's possible to clear the modification flag (say, by saving the buffer) with the edit buffer not having been loaded into S. @item Backup files can sometimes be left behind, even when @code{ess-keep-dump-files} is @code{nil}. @item Passing an incomplete @Sl{} expression to @code{ess-execute} causes ESS to hang. @item The function-based commands don't always work as expected on functions whose body is not a parenthesized or compound expression, and don't even recognize anonymous functions (i.e. functions not assigned to any variable). @item Multi-line commands could be handled better by the command history mechanism. @item Changes to the continuation prompt in R (e.g. @code{options(continue = " ")}) are not automatically detected by ESS. Hence, for now, the best thing is not to change the continuation prompt. If you do change the continuation prompt, you will need to change accordingly the value of @code{inferior-ess-secondary-prompt} in @code{R-customize-alist}. @end itemize ESS-24.01.1/doc/credits.texi000066400000000000000000000056211455642170100154170ustar00rootroot00000000000000@cindex comint @cindex authors @cindex credits The ESS environment is built on the open-source projects of many contributors, dating back to 1989 where Doug Bates and Ed Kademan wrote S-mode to edit S and Splus files in GNU Emacs. Frank Ritter and Mike Meyer added features, creating version 2. Meyer and David Smith made further contributions, creating version 3. For version 4, David Smith provided significant enhancements to allow for powerful process interaction. John Sall wrote GNU Emacs macros for SAS source code around 1990. Tom Cook added functions to submit jobs, review listing and log files, and produce basic views of a dataset, thus creating a SAS-mode which was distributed in 1994. In 1994, A.J. Rossini extended S-mode to support XEmacs. Together with extensions written by Martin Maechler, this became version 4.7 and supported S, Splus, and R. In 1995, Rossini extended SAS-mode to work with XEmacs. In 1997, Rossini merged S-mode and SAS-mode into a single Emacs package for statistical programming; the product of this marriage was called ESS version 5. Richard M. Heiberger designed the inferior mode for interactive SAS and SAS-mode was further integrated into ESS. Thomas Lumley's Stata mode, written around 1996, was also folded into ESS. More changes were made to support additional statistical languages, particularly XLispStat. ESS initially worked only with Unix statistics packages that used standard-input and standard-output for both the command-line interface and batch processing. ESS could not communicate with statistical packages that did not use this protocol. This changed in 1998 when Brian Ripley demonstrated use of the Windows Dynamic Data Exchange (DDE) protocol with ESS. Heiberger then used DDE to provide interactive interfaces for Windows versions of Splus. In 1999, Rodney A. Sparapani and Heiberger implemented SAS batch for ESS relying on files, rather than standard-input/standard-output, for Unix, Windows and Mac. In 2001, Sparapani added BUGS batch file processing to ESS for Unix and Windows. @itemize @bullet @item The multiple process code, and the idea for @code{ess-eval-line-and-next-line} are by Rod Ball. @item Thanks to Doug Bates for many useful suggestions. @item Thanks to Martin Maechler for reporting and fixing bugs, providing many useful comments and suggestions, and for maintaining the ESS mailing lists. @item Thanks to Frank Ritter for updates, particularly the menu code, and invaluable comments on the manual. @item Thanks to Ken'ichi Shibayama for his excellent indenting code, and many comments and suggestions. @item Thanks to Aki Vehtari for adding interactive BUGS support. @item Thanks to Brendan Halpin for bug-fixes and updates to Stata-mode. @item Last, but definitely not least, thanks to the many ESS users and contributors to the ESS mailing lists. @end itemize @emph{ESS} is being developed and currently maintained by @include authors.texi ESS-24.01.1/doc/currfeat.texi000066400000000000000000000030441455642170100155720ustar00rootroot00000000000000@itemize @bullet @item Languages Supported: @itemize @bullet @item S family (R, S, and S+ AKA S-PLUS) @item SAS @item BUGS/JAGS @item Stata @item Julia @end itemize @item Editing source code (S family, SAS, BUGS/JAGS, Stata, Julia) @itemize @bullet @item Syntactic indentation and highlighting of source code @item Partial evaluation of code @item Loading and error-checking of code @item Source code revision maintenance @item Batch execution (SAS, BUGS/JAGS) @item Use of imenu to provide links to appropriate functions @end itemize @item Interacting with the process (S family, SAS, Stata, Julia) @itemize @bullet @item Command-line editing @item Searchable Command history @item Command-line completion of S family object names and file names @item Quick access to object lists and search lists @item Transcript recording @item Interface to the help system @end itemize @item Transcript manipulation (S family, Stata) @itemize @bullet @item Recording and saving transcript files @item Manipulating and editing saved transcripts @item Re-evaluating commands from transcript files @end itemize @item Interaction with Help Pages and other Documentation (R) @itemize @bullet @item Fast Navigation @item Sending Examples to running ESS process. @item Fast Transfer to Further Help Pages @end itemize @item Help File Editing (R) @itemize @bullet @item Syntactic indentation and highlighting of source code. @item Sending Examples to running ESS process. @item Previewing @end itemize @end itemize ESS-24.01.1/doc/ess-defs.texi000066400000000000000000000011711455642170100154670ustar00rootroot00000000000000@c keep all doc macros here @macro wkbd{ARG} @w{@kbd{\ARG\}} @end macro @macro wcode{ARG} @w{@code{\ARG\}} @end macro @macro wsamp{ARG} @w{@samp{\ARG\}} @end macro @macro ESS{ARG} @acronym{ESS\ARG\} @end macro @macro iESS{ARG} @w{i@ESS{\ARG\}} @end macro @macro ESSVER @include ../VERSION @end macro @macro R{} R @end macro @macro Sl{} S @end macro @macro SPLUS{} @sc{S-Plus} @end macro @macro SAS{ARG} @w{@acronym{SAS\ARG\}} @end macro @macro UNIX{} @acronym{UNIX} @end macro @macro PC @acronym{PC} @end macro @macro MS @acronym{MS} @end macro @macro initfile{} @file{~/.emacs} or @file{~/.emacs.d/init.el} @end macro ESS-24.01.1/doc/ess.texi000066400000000000000000003723211455642170100145600ustar00rootroot00000000000000\input texinfo @c -*-texinfo-*- @comment %**start of header @setfilename ess.info @settitle ESS -- Emacs Speaks Statistics @comment %**end of header @synindex pg fn @include ess-defs.texi @titlepage @title ESS -- Emacs Speaks Statistics ESS version @ESSVER @c --- KEEP this synchronized with ./authors.texi : @c ~~~~~~~~~~~~~~ @author The ESS Developers (A.J. Rossini, R.M. Heiberger, K. Hornik, @author M. Maechler, R.A. Sparapani, S.J. Eglen, @author S.P. Luque, H. Redestig, V. Spinu, L. Henry, and J.A. Branham) @c @author (Formerly by: Doug Bates, Ed Kademan, Frank Ritter @c @author and David Smith) @c @ifhtml @c


@c @end ifhtml @c @author Current Documentation by The ESS Developers @author Copyright @copyright{} 2002--2022 The ESS Developers @author Copyright @copyright{} 1996--2001 A.J. Rossini @author Original Documentation by David M. Smith @author Copyright @copyright{} 1992--1995 David M. Smith @c (@email{D.M.Smith@@lancaster.ac.uk}) @c @author Department of Mathematics and Statistics @c @author Lancaster University, UK @c @page @c @vskip 0pt plus 1filll @c @sp 2 @author Permission is granted to make and distribute verbatim copies of this @author manual provided the copyright notice and this permission notice are @author preserved on all copies. @author Permission is granted to copy and distribute modified versions of this @author manual under the conditions for verbatim copying, provided that the @author entire resulting derived work is distributed under the terms of a @author permission notice identical to this one. @end titlepage @contents @ifnottex @majorheading ESS --- Emacs Speaks Statistics @dircategory Emacs @direntry * ESS: (ess). Emacs Speaks Statistics (R/S/S+, SAS, BUGS/JAGS and Stata). @end direntry @node Top @top ESS: Emacs Speaks Statistics ESS version @ESSVER @display by A.J. Rossini, R.M. Heiberger, K. Hornik, M. Maechler, R.A. Sparapani, S.J. Eglen, S.P. Luque, H. Redestig, V. Spinu, L. Henry, and J.A. Branham. @end display @c (Formerly: Doug @c Bates, Ed Kademan, Frank Ritter and David Smith). @quotation Emacs Speaks Statistics (ESS) provides an intelligent, consistent interface between the user and the software. ESS interfaces with R, SAS, S-PLUS, BUGS/JAGS and other statistical analysis packages on GNU/Linux, other Unix-like systems such as macOS, and Microsoft Windows. ESS is itself a package within the Emacs text editor and uses Emacs features to streamline the creation and use of statistical software. ESS knows the syntax and grammar of statistical analysis packages and provides consistent display and editing features based on that knowledge. ESS assists in interactive and batch execution of statements written in these statistical analysis languages. @end quotation @include license.texi @end ifnottex @menu * Introduction:: Overview of features provided by this package * Installation:: Installing ESS on your system * Interactive ESS:: Interacting with statistical programs * Entering commands:: Interacting with the ESS process * Evaluating code:: Sending code to the ESS process * Transcript Mode:: Manipulating saved transcript files * Editing objects:: How to create/edit objects and functions * Help:: Reading help files * Completion:: Various completion mechanisms * Developing with ESS:: Tools for package development and debugging * Extras:: Other ESS features for the S family * ESS for R:: Overview of ESS features for the S family * ESS for SAS:: * ESS for BUGS:: * ESS for JAGS:: * Mailing lists/bug reports:: How to get assistance with ESS * Customization:: Customizing ESS * Indices:: @end menu @node Introduction @chapter Introduction to ESS @cindex introduction ESS provides a generic interface, through Emacs, to statistical packages. It currently supports R (and the rest of the S family), SAS, BUGS/JAGS, Stata, and Julia with the level of support roughly in that order. Throughout this manual, @emph{Emacs} refers to @emph{GNU Emacs} by the Free Software Foundation. Although previous versions of ESS supported other Emacsen, current versions only support GNU Emacs. There are two main ways of interacting with ESS: through ``regular'' modes or ``inferior'' modes. Regular modes act like normal Emacs major modes. ESS major modes are displayed in the mode-line in the format @code{ESS[dialect]}, where @code{dialect} can take values such as @code{R}, @code{SAS}, or @code{S}. ESS also provides easy access to an ``inferior process,'' which is an Emacs buffer associated with a running process. This can be an R session, for example. These inferior processes are referred to as inferior ESS (@code{iESS}), and are shown in the modeline by @code{iESS [dialect]}. Currently, the documentation contains many references to @cite{`R'} where actually any supported (statistics) language is meant, i.e., `R' could also mean `S' or `SAS.' @cindex interactive use of R @cindex using R interactively @cindex interactive use of S @cindex using S interactively @cindex using ESS interactively For exclusively interactive users of R, ESS provides a number of features to make life easier. There is an easy to use command history mechanism, including a quick prefix-search history. To reduce typing, command-line completion is provided for all R objects and ``hot keys'' are provided for common R function calls. Help files are easily accessible, and a paging mechanism is provided to view them. Finally, an incidental (but very useful) side-effect of ESS is that a transcript of your session is kept for later saving or editing. @cindex transcripts of R sessions @cindex transcripts of S sessions No special knowledge of Emacs is necessary when using R interactively under ESS. @cindex programming in R @cindex programming in S For those that use R in the typical edit--test--revise cycle when writing R functions, ESS provides for editing of R functions in Emacs buffers. Unlike the typical use of R where the editor is restarted every time an object is edited, ESS uses the current Emacs session for editing. In practical terms, this means that you can edit more than one function at once, and that the ESS process is still available for use while editing. Error checking is performed on functions loaded back into R, and a mechanism to jump directly to the error is provided. ESS also provides for maintaining text versions of your R functions in specified source directories. @menu * Features:: Why should I use ESS? * New features:: * Credits:: Authors of and contributors to ESS * Manual:: How to read this manual @end menu @node Features @section Why should I use ESS? Statistical packages are powerful software systems for manipulating and analyzing data, but their user interfaces often leave something to be desired: they offer weak editor functionality and they differ among themselves so markedly that you have to re-learn how to do those things for each package. ESS is a package which is designed to make editing and interacting with statistical packages more uniform, user-friendly and give you the power of Emacs as well. Additionally, both Emacs and ESS (and R) are free software designed to give users full control over their computer. For more on what this means, visit @uref{https://www.gnu.org/philosophy/free-sw.html}. @menu * Current Features:: @end menu @node Current Features @subsection Features Overview @include currfeat.texi For source code buffers, ESS offers several features: @itemize @bullet @item @b{Support for multiple indentation styles} R code @xref{Indenting}. @item @b{Facilities for loading and error-checking source files}, including a keystroke to jump straight to the position of an error in a source file. @xref{Error Checking}. @item @b{Source code revision maintenance}, which allows you to keep historic versions of R source files. @xref{Source Files}. @item @b{Facilities for evaluating R code} such as portions of source files, or line-by-line evaluation of files (useful for debugging). @xref{Evaluating code}. @end itemize ESS also provides features that make it easier to interact with inferior ESS (iESS) process (a connection between your buffer and the statistical package which is waiting for you to input commands). These include: @itemize @bullet @item @b{Command-line editing} for fixing mistakes in commands before they are entered. @xref{Command-line editing}. @item @b{Searchable command history} for recalling previously-submitted commands. @xref{Command History}. @item @b{Command-line completion} of both object and file names for quick entry. @xref{Completion}. @item @b{Hot-keys} for quick entry of commonly-used commands in `R' such as @code{objects()}, and @code{search()}. @xref{Hot keys}. @item @b{Transcript recording} for a complete record of all the actions in an R session. @xref{Transcript}. @item @b{Interface to the help system}, with a specialized mode for viewing R help files. @xref{Help}. @item @b{Object editing}. ESS allows you to edit more than one function simultaneously in dedicated Emacs buffers. The ESS process may continue to be used while functions are being edited. @xref{Edit buffer}. @end itemize Finally, ESS provides features for re-submitting commands from saved transcript files, including: @itemize @bullet @item @b{Evaluation of previously entered commands}, stripping away unnecessary prompts. @xref{Transcript resubmit}. @end itemize @node New features @section New features in ESS @include newfeat.texi @comment @include onewfeat.texi @node Credits @section Authors of and contributors to ESS @include credits.texi @node Manual @section How to read this manual If you need to install ESS, read @ref{Installation} for details on what needs to be done before proceeding to the next chapter. This section describes some of the basics of using Emacs. If you are already familiar with basic Emacs functionality, skip this section. You may also want to use the Emacs tutorial, accessible via @kbd{C-h t}. In this manual we use the standard notation used by Emacs for describing the keystrokes used to invoke certain commands. @kbd{C-} means hold the CONTROL key while typing the character . @kbd{M-} means hold the META key (usually ALT) down while typing . If there is no META, EDIT or ALT key, instead press and release the ESC key and then type . All ESS commands can be invoked by typing @kbd{M-x command}. Most of the useful commands are bound to keystrokes for ease of use. Also, the most popular commands are also available through the Emacs menubar, and a small subset are provided on the toolbar. Where possible, keybindings are similar to other modes in Emacs to strive for a consistent user interface within Emacs, regardless of the details of which programming language is being edited, or process being run. Some commands, such as @kbd{M-x R} can accept an optional `prefix' argument. To specify the prefix argument, you would type @kbd{C-u} before giving the command. For example, if you type @kbd{C-u M-x R}, you will be asked for command line options that you wish to invoke the R process with. Emacs is a `self-documenting' text editor. This applies to ESS in two ways. First, some documentation about each ESS command can be obtained by typing @kbd{C-h f}. For example, if you type @kbd{C-h f ess-eval-region}, documentation for that command will appear in a separate *Help* buffer. Second, @kbd{C-h m} pops up a complete list of keybindings available in each ESS mode and brief description of that mode. Emacs is a versatile editor written in both C and a dialect of Lisp known as Elisp. ESS is written in Elisp and benefits from the flexible nature of lisp. In particular, many aspects of ESS behaviour can be changed by suitable customization of Lisp variables. This manual mentions some of the most frequent variables. A full list of them however is available by using the Custom facility within Emacs. Type @kbd{M-x customize-group RET ess RET} to get started. @ref{Customization} provides details of common user variables you can change to customize ESS to your taste, but it is recommended that you defer this section until you are more familiar with ESS. @node Installation @chapter Installing ESS on your system @cindex installation @include installation.texi @node Interactive ESS @chapter Interacting with statistical programs As well as using ESS to edit your source files for statistical programs, you can use ESS to run these statistical programs. In this chapter, we mostly will refer by example to running R from within Emacs. The Emacs convention is to name such processes running under its control as `inferior processes'. Some users find this terminology confusing; you may prefer to think of these as `interactive processes.' Either way, we use the term `iESS' to refer to the Emacs mode used to interact with statistical programs. @menu * Starting up:: * Multiple ESS processes:: * ESS processes on Remote Computers:: * Customizing startup:: * Controlling buffer display:: @end menu @node Starting up @section Starting an ESS process @cindex starting ESS @cindex running S @cindex running R To start an inferior R session on GNU/Linux, macOS, or Windows using the Cygwin bash shell, simply type @kbd{M-x R RET}. To start an R session on Windows when you use the MSDOS/powershell shell, simply type @kbd{M-x S+6-msdos RET}. R will then (by default) ask the question @pindex S @pindex R @cindex ESS process directory @cindex starting directory @cindex working directory @cindex directories @example R starting data directory? @end example @noindent Enter the name of the directory you wish to have as the working directory (that is, the directory you wish to have @code{getwd()} return if using R). You will then be popped into a buffer @cindex ESS process buffer @cindex process buffer named @samp{*R*} which will be used for interacting with the ESS process, and you can start entering commands. @node Multiple ESS processes @section Running more than one ESS process @cindex multiple ESS processes @cindex changing ESS processes @cindex multiple inferior processes @cindex multiple interactive processes ESS allows you to run more than one iESS process simultaneously in the same session. Each process has a name and a number; the initial process @cindex process names (process 1) is simply named @samp{R}. If you call @kbd{M-x R} again without killing the first R process, ESS will start a second R process with the name @samp{R:2}. To have the first buffer named @samp{R:1}, customize the option @code{ess-plain-first-buffername}. With a prefix argument, @kbd{C-u M-x R} allows for the specification of command line options. @defvr {User Option} ess-plain-first-buffername If non-@code{nil}, name the first iESS process [R]. Otherwise, name it [R:1]. @end defvr @findex ess-request-a-process You can switch to any active ESS process with the command @samp{M-x ess-request-a-process}. Just enter the name of the process you require; completion is provided over the names of all running processes. This is a good command to consider binding to a global key. @node ESS processes on Remote Computers @section ESS processes on Remote Computers @subsection ESS and TRAMP @findex ess-remote @cindex remote Computers @cindex ESS-elsewhere @cindex S+elsewhere @cindex tramp support ESS works with processes on remote computers as easily as with processes on the local machine. The recommended way to access a statistical program on remote computer is to start it with @xref{Top,,, tramp, TRAMP User Manual}. Start an ssh session using TRAMP with @samp{C-x C-f /ssh:user@@host: RET}. Tramp should open a dired buffer in your remote home directory. Now call your favorite ESS process (@code{R}, @code{Julia}, @code{stata} etc) as you would usually do on local machine: @code{M-x R}. Alternatively you can start your process normally (@code{M-x R}). When asked for starting directory, simply type @samp{/ssh:user@@host: RET}. The R process will be started on the remote machine. To simplify the process even further create a "config" file in your @code{.ssh/} folder and add an account. For example if you use amazon EC2, it might look like following: @verbatim Host amazon Hostname ec2-54-215-203-181.us-west-1.compute.amazonaws.com User ubuntu IdentityFile ~/.ssh/my_amazon_key.pem ForwardX11 yes @end verbatim With this configuration @code{/ssh:amazon:} is enough to start a connection. The ForwardX11 is needed if you want to see the R graphic device showing on the current machine @subsection ESS-remote TRAMP is the recommended way of starting a remote session. The other way to start a remote ESS connection is through @code{ess-remote}. @enumerate @item Start a new shell, telnet or ssh buffer and connect to the remote computer (e.g. use, @samp{M-x shell}, @samp{M-x telnet} or @samp{M-x ssh}; ssh.el is available at @uref{https://www.splode.com/~friedman/software/emacs-lisp/src/ssh.el}). @item Start the ESS process on the remote machine, for example with one of the commands @samp{R}, @samp{Splus}, or @samp{sas -stdio}. @item Start @samp{M-x ess-remote}. You will be prompted for a program name with completion. Choose one. Your process is now known to ESS. All the usual ESS commands (@samp{C-c C-n} and its relatives) now work with the R language processes. For SAS you need to use a different command @samp{C-c i} (that is a regular @samp{i}, not a @samp{C-i}) to send lines from your @file{myfile.sas} to the remote SAS process. @samp{C-c i} sends lines over invisibly. @c and lets SAS display them formatted correctly as in a SAS log file. With ess-remote you get teletype behavior---the data input, the log, and the listing all appear in the same buffer. To make this work, you need to end every PROC and DATA step with a "RUN;" statement. The "RUN;" statement is what tells SAS that it should process the preceding input statements. @item Graphics (interactive) on the remote machine. If you run X11 (@xref{X11}, X Windows) on both the local and remote machines then you should be able to display the graphs locally by setting the @samp{DISPLAY} environment variable appropriately. Windows users can download @samp{xfree86} from cygwin. @item Graphics (static) on the remote machine. If you don't run the X window system on the local machine, then you can write graphics to a file on the remote machine, and display the file in a graphics viewer on the local machine. Most statistical software can write one or more of postscript, GIF, or JPEG files. Depending on the versions of Emacs and the operating system that you are running, Emacs itself may display @samp{.gif} and @samp{.jpg} files. Otherwise, a graphics file viewer will be needed. Ghostscript/ghostview may be downloaded to display @samp{.ps} and @samp{.eps} files. Viewers for GIF and JPEG are usually included with operating systems. @xref{ESS(SAS)--Function keys for batch processing}, for more information on using the F12 key for displaying graphics files with SAS. @end enumerate Should you or a colleague inadvertently start a statistical process in an ordinary @samp{*shell*} buffer, the @samp{ess-remote} command can be used to convert it to an ESS buffer and allow you to use the ESS commands with it. @node Customizing startup @section Changing the startup actions If you do not wish ESS to prompt for a starting directory when starting a new process, set the variable @code{ess-ask-for-ess-directory} to @vindex ess-ask-for-ess-directory @code{nil}. In this case, the starting directory will be set using one of the following methods: @enumerate @item If the variable @code{ess-directory-function} stores the name of a function, the value returned by this function is used. The default for this variable is nil. @item Otherwise, if the variable @code{ess-directory} stores the name of a directory (ending in a slash), this value is used. The default for this variable is nil. @item Otherwise, the working directory of the current buffer is used. @end enumerate @vindex ess-ask-for-ess-directory @vindex ess-pre-run-hook If @code{ess-ask-for-ess-directory} has a non-@code{nil} value (as it does by default) then the value determined by the above rules provides the default when prompting for the starting directory. Incidentally, @code{ess-directory} is an ideal variable to set in @code{ess-pre-run-hook}. @vindex ess-post-run-hook You may also customize @code{ess-post-run-hook} and the dialect-specific @code{ess-*-post-run-hook} variables. For example, you may want to use @code{ess-load-file} to load a file when ESS starts R: @example (add-hook 'ess-r-post-run-hook (lambda () (ess-load-file "foo.R"))) @end example If you like to keep a record of your R actions, set the variable @code{ess-ask-about-transfile} to @code{t}, and you will be asked for a filename for the transcript before the ESS process starts. @defvr {User Option} ess-ask-about-transfile If non-@code{nil}, ask for a file name in which to save the session transcript. @end defvr @cindex transcript file Enter the name of a file in which to save the transcript at the prompt. If the file doesn't exist it will be created (for R, you likely want it to end in @samp{.Rout}). If the file already exists the transcript will be appended to the file. (Note: if you don't set this variable but you still want to save the transcript, you can still do it later --- @pxref{Saving transcripts}.) Once these questions are answered (if they are asked at all) the inferior process itself is started. @vindex inferior-ess-program @vindex iESS program arguments If you need to pass any arguments to this program, they may be specified in the variable @code{inferior-@var{S_program_name}-args}. For example, if @code{inferior-ess-program} is @code{"R"} then the variable to set is @code{inferior-R-args}. @cindex arguments to S program @cindex arguments to R program It is not normally necessary to pass arguments to the iESS program; in particular do not pass the @samp{-e} option to @code{Splus}, since ESS provides its own command history mechanism. @vindex ess-auto-width @vindex ess-auto-width-visible ESS can set the width option of inferior processes automatically when the window configuration changes. To do so, set @code{ess-auto-width} to a non-nil value. By default, the change will not be shown in the inferior buffer. If you want it to be shown, set @code{ess-auto-width-visible} to a non-nil value. @node Controlling buffer display @section Controlling buffer display Users can control how buffers are displayed by customizing @code{display-buffer-alist}, @xref{Window Choice,,, emacs}. This section provides examples of how to achieve certain setups. Users coming from RStudio may want the R process to appear at the bottom left of the frame, help buffers to appear at the bottom right, and ess-rdired buffers at the top right. To achieve that, you could this. Note that the order matters; @code{*R Dired*} would match @code{*R} if it came before in the alist. @example (setq display-buffer-alist `(("^\\*R Dired" (display-buffer-reuse-window display-buffer-in-side-window) (side . right) (slot . -1) (window-width . 0.33) (reusable-frames . nil)) ("^\\*R" (display-buffer-reuse-window display-buffer-at-bottom) (window-width . 0.5) (reusable-frames . nil)) ("^\\*Help" (display-buffer-reuse-window display-buffer-in-side-window) (side . right) (slot . 1) (window-width . 0.33) (reusable-frames . nil)))) @end example Some users prefer working with multiple frames where one frame has the source code and the other frame has the inferior process. To achieve this, use this example. For a detailed description of @code{reusable-frames}, see @xref{Buffer Display Action Alists,,, elisp}. @example (setq display-buffer-alist '(("^\\*R" (display-buffer-reuse-window display-buffer-pop-up-frame) (reusable-frames . 0)))) @end example Some users may want the process window to be dedicated to the process so that other buffers are not shown on top of that window. @xref{Dedicated Windows,,, elisp}. For example, this prevents help buffers from being displayed in the window showing the inferior R process. @example (setq display-buffer-alist '(("^\\*R" nil (dedicated . t)))) @end example By default, ESS usually prefers splitting the frame into multiple windows so that you can work with both the R script and the R REPL visible at once. If you want to override this behavior so that the script buffer and the process buffer share the same window, you can do so like this: @example (setq display-buffer-alist '(("^\\*R" . ((display-buffer-same-window) (inhibit-same-window . nil))) ("\\.R$" . ((display-buffer-same-window) (inhibit-same-window . nil))))) @end example @node Entering commands @chapter Interacting with the ESS process @cindex entering commands @cindex commands @cindex sending input The primary function of the ESS package is to provide an easy-to-use front end to the R interpreter. This is achieved by running the R process from within an Emacs buffer, called hereafter @emph{inferior} buffer, which has an active @code{inferior-ess-mode}. The features of inferior R mode are similar to those provided by the standard Emacs shell mode (@pxref{Shell Mode,,, emacs, The Gnu Emacs Reference Manual}). Command-line completion of R objects and a number of `hot keys' for commonly-used R commands are also provided for ease of typing. @menu * Command-line editing:: Entering commands and fixing mistakes * Transcript:: Manipulating the transcript * Command History:: Command History * History expansion:: References to historical commands * Hot keys:: Hot keys for common commands * Statistical Process running in ESS?:: * Emacsclient:: Using emacsclient * Other:: Other commands provided by inferior-ESS @end menu @node Command-line editing @section Entering commands and fixing mistakes @cindex command-line editing Sending a command to the ESS process is as simple as typing it in and pressing the @key{RETURN} key: @deffn Command inferior-ess-send-input @kindex RET @kbd{RET} Send the command on the current line to the ESS process. @end deffn If you make a typing error before pressing @kbd{RET} all the usual Emacs editing commands are available to correct it (@pxref{Basic, Basic, Basic editing commands, emacs, The GNU Emacs Reference Manual}). Once the command has been corrected you can press @key{RETURN} (even if the cursor is not at the end of the line) to send the corrected command to the ESS process. Emacs provides some other commands which are useful for fixing mistakes: @table @kbd @item C-c C-w @findex backward-kill-word @code{backward-kill-word} Deletes the previous word (such as an object name) on the command line. @item C-c C-u @findex comint-kill-input @code{comint-kill-input} Deletes everything from the prompt to point. Use this to abandon a command you have not yet sent to the ESS process. @item C-a @findex comint-bol @code{comint-bol} Move to the beginning of the line, and then skip forwards past the prompt, if any. @end table @xref{Shell Mode,,, emacs, The Gnu Emacs Reference Manual}, for other commands relevant to entering input. @node Transcript @section Manipulating the transcript Most of the time, the cursor spends its time at the bottom of the ESS process buffer, entering commands. However all the input and output from the current (and previous) ESS sessions is stored in the process buffer (we call this the transcript) and often we want to @cindex transcript move back up through the buffer, to look at the output from previous commands for example. Within the process buffer, a paragraph @cindex paragraphs in the process buffer is defined as the prompt, the command after the prompt, and the output from the command. Thus @kbd{M-@{} and @kbd{M-@}} move you backwards and forwards, respectively, through commands in the transcript. A particularly useful command is @kbd{M-h} (@code{mark-paragraph}) which will allow you to mark a command and its entire output (for deletion, perhaps). For more information about paragraph commands, @pxref{Paragraphs, Paragraphs, Paragraphs, emacs, The GNU Emacs Reference Manual}. If an ESS process finishes and you restart it in the same process buffer, the output from the new ESS process appears after the output from the first ESS process separated by a form-feed (@samp{^L}) character. Thus pages in the ESS @cindex pages in the process buffer process buffer correspond to ESS sessions. Thus, for example, you may use @kbd{C-x [} and @kbd{C-x ]} to move backward and forwards through ESS sessions in a single ESS process buffer. For more information about page commands, @pxref{Pages, Pages, Pages, emacs, The GNU Emacs Reference Manual}. @menu * Last command:: Manipulating the output from the last command * Process buffer motion:: Viewing older commands * Transcript resubmit:: Re-submitting commands from the transcript * Saving transcripts:: Keeping a record of your R session @end menu @node Last command @subsection Manipulating the output from the last command Viewing the output of the command you have just entered is a common occurrence and ESS provides a number of facilities for doing this. Whenever a command produces output, it is possible that the window will scroll, leaving the next prompt near the middle of the window. The first part of the command output may have scrolled off the top of the window, even though the entire output would fit in the window if the prompt were near the bottom of the window. If this happens, you can use the following comint commands: @code{comint-show-maximum-output} to move to the end of the buffer, and place cursor on bottom line of window to make more of the last output visible. To make this happen automatically for all inputs, set the variable @code{comint-scroll-to-bottom-on-input} to @code{t} or @code{'this}. If the first part of the output is still not visible, use @cindex reading long command outputs @kbd{C-c C-r} (@code{comint-show-output}), @findex comint-show-output which moves cursor to the previous command line and places it at the top of the window. Finally, if you want to discard the last command output altogether, use @cindex deleting output @kbd{C-c C-o} (@code{comint-delete-output}), @findex comint-delete-output which deletes everything from the last command to the current prompt. Use this command judiciously to keep your transcript to a more manageable size. @node Process buffer motion @subsection Viewing older commands If you want to view the output from more historic commands than the previous command, commands are also provided to move backwards and forwards through previously entered commands in the process buffer: @table @kbd @item C-c C-p @findex comint-previous-prompt @code{comint-previous-prompt} Moves point to the preceding prompt in the process buffer. @item C-c C-n @findex comint-next-prompt @code{comint-next-prompt} Moves point to the next prompt in the process buffer. @end table @noindent Note that these two commands are analogous to @kbd{C-p} and @kbd{C-n} but apply to command lines rather than text lines. And just like @kbd{C-p} and @kbd{C-n}, passing a prefix argument to these commands means to move to the @var{ARG}'th next (or previous) command. (These commands are also discussed in @ref{Shell History Copying,,Shell History Copying,emacs, The GNU Emacs Reference Manual}.) There are also two similar commands (not bound to any keys by default) which move to preceding or succeeding commands, but which first prompt for a regular expression (@pxref{Regexps,,Syntax of Regular Expression,emacs, The GNU Emacs Reference Manual}), and then moves to the next (previous) command matching the pattern. @table @code @item comint-backward-matching-input regexp arg @findex comint-backward-matching-input @itemx comint-forward-matching-input regexp arg @findex comint-forward-matching-input Search backward (forward) through the transcript buffer for the @var{arg}'th previous (next) command matching @var{regexp}. @var{arg} is the prefix argument; @var{regexp} is prompted for in the minibuffer. @end table @node Transcript resubmit @subsection Re-submitting commands from the transcript When moving through the transcript, you may wish to re-execute some of the commands you find there. ESS provides commands to do this; these commands may be used whenever the cursor is within a command line in the transcript (if the cursor is within some command @emph{output}, an error is signaled). Note all commands involve the @key{RETURN} key. @table @kbd @item RET @code{inferior-ess-send-input} @xref{Command-line editing}. @item C-c RET @findex comint-copy-old-input @code{comint-copy-old-input} Copy the command under the cursor to the current command line, but don't execute it. Leaves the cursor on the command line so that the copied command may be edited. @end table When the cursor is not after the current prompt, the @key{RETURN} key has a slightly different behavior than usual. Pressing @kbd{RET} on any line containing a command that you entered (i.e. a line beginning with a prompt) sends that command to the ESS process once again. If you wish to edit the command before executing it, use @kbd{C-c RET} instead; it copies the command to the current prompt but does not execute it, allowing you to edit it before (re)submitting it. These commands work even if the current line is a continuation line (i.e. the prompt is @samp{+} instead of @samp{>}) --- in this case all the lines that form the multi-line command are concatenated together and the resulting command is sent to the ESS process (currently this is the only way to resubmit a multi-line command to the ESS process in one go). If the current line does @cindex multi-line commands, resubmitting not begin with a prompt, an error is signalled. This feature, coupled with the command-based motion commands described above, could be used as a primitive history mechanism. ESS provides a more sophisticated mechanism, however, which is described in @ref{Command History}. @node Saving transcripts @subsection Keeping a record of your R session To keep a record of your R session in a disk file, use the Emacs command @kbd{C-x C-w} (@code{write-file}) to attach a file to the ESS process buffer. The name of the process buffer will (probably) change to the name of the file, but this is not a problem. You can still use R as usual; just remember to save the file before you quit Emacs with @kbd{C-x C-s}. You can make ESS prompt you for a filename in which to save the transcript every time you start R by setting the variable @vindex ess-ask-about-transfile @code{ess-ask-about-transfile} to @code{t}; @xref{Customizing startup}. @cindex transcript file names For R files, naming transcript files @samp{*.Rout} puts them in a special mode (ESS transcript mode --- @pxref{Transcript Mode}) for editing transcript files which is automatically selected for files with this suffix. @cindex editing transcripts R transcripts can get very large, so some judicious editing is appropriate if you are saving it in a file. Use @kbd{C-c C-o} whenever a command produces excessively long output (printing large arrays, for example). Delete erroneous commands (and the resulting error messages or other output) by moving to the command (or its output) and typing @kbd{M-h C-w}. Also, remember that @kbd{C-c C-x} (and other hot keys) may be used for commands whose output you do not wish to appear in the transcript. These suggestions are appropriate even if you are not saving your transcript to disk, since the larger the transcript, the more memory your Emacs process will use on the host machine. You can use @code{ess-transcript-clean-region} to strip output from a transcript, leaving only source code suitable for inclusion in files @code{source()}-able from R. @pxref{Clean, Transcript Mode} @node Command History @section Command History @cindex command history @cindex editing commands @cindex re-executing commands ESS provides easy-to-use facilities for re-executing or editing previous commands. An input history of the last few commands is maintained (by default the last 500 commands are stored, although this can be changed by setting the variable @code{comint-input-ring-size} in @vindex comint-input-ring-size @code{inferior-ess-mode-hook}.) The simplest history commands simply select the next and previous commands in the input history: @table @kbd @item M-p @findex comint-previous-input @code{comint-previous-input} Select the previous command in the input history. @item M-n @findex comint-next-input @code{comint-next-input} Select the next command in the input history. @end table @noindent For example, pressing @kbd{M-p} once will re-enter the last command into the process buffer after the prompt but does not send it to the ESS process, thus allowing editing or correction of the command before the ESS process sees it. Once corrections have been made, press @kbd{RET} to send the edited command to the ESS process. If you want to select a particular command from the history by matching it against a regular expression (@pxref{Regexps,,Syntax of Regular Expression,emacs, The GNU Emacs Reference Manual}), to search for a particular variable name for example, these commands are also available: @table @kbd @item M-r @findex comint-history-isearch-backward-regexp @code{comint-history-isearch-backward-regexp} Prompt for a regular expression, and search backwards through the input history for a command matching the expression. @c @item M-s @c @findex comint-next-matching-input @c @code{comint-next-matching-input} Prompt for a regular expression, and @c search backwards through the input history for a command matching the @c expression. @end table @noindent A common type of search is to find the last command that began with a particular sequence of characters; the following two commands provide an easy way to do this: @table @kbd @item C-c M-r @findex comint-previous-matching-input-from-input @code{comint-previous-matching-input-from-input} Select the previous command in the history which matches the string typed so far. @item C-c M-s @findex comint-next-matching-input-from-input @code{comint-next-matching-input-from-input} Select the next command in the history which matches the string typed so far. @end table @noindent Instead of prompting for a regular expression to match against, as they instead select commands starting with those characters already entered. For instance, if you wanted to re-execute the last @code{attach()} command, you may only need to type @kbd{att} and then @kbd{C-c M-r} and @kbd{RET}. @xref{Shell Ring,,Shell History Ring,emacs, The GNU Emacs Reference Manual}, for a more detailed discussion of the history mechanism, and do experiment with the @code{In/Out} menu to explore the possibilities. Many ESS users like to have even easier access to these, and recommend adding something like @example (eval-after-load "comint" '(progn (define-key comint-mode-map [up] 'comint-previous-matching-input-from-input) (define-key comint-mode-map [down] 'comint-next-matching-input-from-input) ;; also recommended for ESS use -- (setq comint-move-point-for-output 'others) ;; somewhat extreme, almost disabling writing in *R*, *shell* buffers above prompt: (setq comint-scroll-to-bottom-on-input 'this) )) @end example to your Emacs configuration file, where the last two settings are typically desirable for the situation where you work with a script (for example, @file{code.R}) and send code chunks to the process buffer (e.g. @code{*R*}). Note however that these settings influence all @code{comint}-using Emacs modes, not just the ESS ones, and for that reason, these customization cannot be part of @code{ESS} itself. @menu * Saving History:: @end menu @node Saving History @subsection Saving the command history The @code{ess-history-file} variable, which is @code{t} by default, together with @code{ess-history-directory}, governs if and where the command history is saved and restored between sessions. By default, @code{ess-history-directory} is @code{nil}, and the command history will be stored (as a file) in the same directory as the iESS process. ESS users may work exclusively with script files rather than in a iESS session, and may not want to save any history files. To do so: @smallexample (setq ess-history-file nil) @end smallexample @noindent or if you prefer only one global command history file: @smallexample (setq ess-history-directory "~/.R/") @end smallexample @noindent in your Emacs configuration file. @node History expansion @section References to historical commands Instead of searching through the command history using the command described in the previous section, you can alternatively refer to a historical command directly using a notation very similar to that used in @code{csh}. History references are introduced by a @samp{!} or @samp{^} character and have meanings as follows: @table @samp @item !! The immediately previous command @item !-@var{N} The @var{N}th previous command @item !text The last command beginning with the string @samp{text} @item !?text The last command containing the string @samp{text} @end table In addition, you may follow the reference with a @dfn{word designator} to select particular @dfn{words} of the input. A word is defined as a sequence of characters separated by whitespace. (You can modify this definition by setting the value of @code{comint-delimiter-argument-list} to a list of characters that are allowed to separate words and @vindex comint-delimiter-argument-list themselves form words.) Words are numbered beginning with zero. The word designator usually begins with a @samp{:} (colon) character; however it may be omitted if the word reference begins with a @samp{^}, @samp{$}, @samp{*} or @samp{-}. If the word is to be selected from the previous command, the second @samp{!} character can be omitted from the event specification. For instance, @samp{!!:1} and @samp{!:1} both refer to the first word of the previous command, while @samp{!!$} and @samp{!$} both refer to the last word in the previous command. The format of word designators is as follows: @table @samp @item 0 The zeroth word (i.e. the first one on the command line) @item @var{n} The @var{n}th word, where @var{n} is a number @item ^ The first word (i.e. the second one on the command line) @item $ The last word @item @var{x}-@var{y} A range of words; @samp{-@var{y}} abbreviates @samp{0-@var{y}} @item * All the words except the zeroth word, or nothing if the command had just one word (the zeroth) @item @var{x}* Abbreviates @var{x}-$ @item @var{x}- Like @samp{@var{x}*}, but omitting the last word @end table In addition, you may surround the entire reference except for the first @samp{!} by braces to allow it to be followed by other (non-whitespace) characters (which will be appended to the expanded reference). Finally, ESS also provides quick substitution; a reference like @samp{^old^new^} means ``the last command, but with the first occurrence of the string @samp{old} replaced with the string @samp{new}'' (the last @samp{^} is optional). Similarly, @samp{^old^} means ``the last command, with the first occurrence of the string @samp{old} deleted'' (again, the last @samp{^} is optional). To convert a history reference as described above to an input suitable for R, you need to @dfn{expand} the history reference, using the @key{TAB} key. For this to work, the cursor must be preceded by a space (otherwise it would try to complete an object name) and not be within a string (otherwise it would try to complete a filename). So to expand the history reference, type @kbd{SPC TAB}. This will convert the history reference into an R command from the history, which you can then edit or press @key{RET} to execute. For example, to execute the last command that referenced the variable @code{data}, type @kbd{!?data SPC TAB RET}. @node Hot keys @section Hot keys for common commands ESS provides a number of commands for executing the commonly used functions. These commands below are basically information-gaining commands (such as @code{objects()} or @code{search()}) which tend to clutter up your transcript and for this reason some of the hot keys display their output in a temporary buffer instead of the process buffer by default. This behavior is controlled by the following option: @defvr {User Option} ess-execute-in-process-buffer If non-@code{nil}, means that these commands will produce their output in the process buffer instead. @end defvr In any case, passing a prefix argument to the commands (with @kbd{C-u}) will reverse the meaning of @code{ess-execute-in-process-buffer} for that command. In other words, the output will be displayed in the process buffer if it usually goes to a temporary buffer, and vice-versa. These are the hot keys that behave in this way: @deffn Command ess-execute-objects @var{posn} @kindex C-c C-x @pindex objects() @cindex objects @kbd{C-c C-x} Sends the @code{objects()} command to the ESS process. A prefix argument specifies the position on the search list (use a negative argument to toggle @code{ess-execute-in-process-buffer} as well). This is a quick way to see what objects are in your working directory. A prefix argument of 2 or more means get objects for that position. A negative prefix argument @var{posn} gets the objects for that position, as well as toggling @code{ess-execute-in-process-buffer}. @end deffn @deffn Command ess-execute-search @var{invert} @kindex C-c C-s @pindex search() @cindex search list @kbd{C-c C-s} Sends the @code{inferior-ess-search-list-command} command to the @code{ess-language} process; @code{search()} in R. Prefix @var{invert} toggles @code{ess-execute-in-process-buffer}. @end deffn @code{ess-execute} may seem pointless when you could just type the command in anyway, but it proves useful for `spot' calculations which would otherwise clutter your transcript, or for evaluating an expression while partway through entering a command. You can also use this command to generate new hot keys using the Emacs keyboard macro facilities; @pxref{Keyboard Macros, Keyboard Macros, Keyboard Macros, emacs, The GNU Emacs Reference Manual}. @cindex hot keys @cindex keyboard short cuts The following hot keys do not use @code{ess-execute-in-process-buffer} to decide where to display the output --- they either always display in the process buffer or in a separate buffer, as indicated: @c @deffn Command ess-execute-attach @var{dir} @var{posn} @c @pindex attach() @c Prompts for a directory @var{dir} to attach to the ESS process with the @c @code{attach()} command. If a numeric prefix argument @var{posn} is @c given, it is used as the position on the search list to attach the @c directory; otherwise the R default of 2 is used. The @c @code{attach()} command actually executed appears in the process buffer. @c @end deffn @deffn Command ess-load-file @var{filename} @kindex C-c M-l @kbd{C-c M-l} Prompts for a file (@var{filename}) to load into the ESS process using @code{source()}. If there is an error during loading, you can jump to the error in the file with the following function. @end deffn @deffn Command ess-parse-errors @var{arg} @var{reset} Visits next @code{next-error} message and corresponding source code. If all the error messages parsed so far have been processed already, the message buffer is checked for new ones. A prefix @var{arg} specifies how many error messages to move; negative means move back to previous error messages. Just @kbd{C-u} as a prefix means reparse the error message buffer and start at the first error. The @var{reset} argument specifies restarting from the beginning. @xref{Error Checking}, for more details. @end deffn @deffn Command ess-display-help-on-object @var{object} @var{command} @kindex C-c C-v @kbd{C-c C-v} Pops up a help buffer for an R object or function. If @var{command} is supplied, it is used instead of @code{inferior-ess-help-command}. See @ref{Help} for more details. @end deffn @deffn Command ess-quit @kindex C-c C-q @pindex q() @findex ess-cleanup @cindex quitting from ESS @cindex killing the ESS process @cindex cleaning up @cindex temporary buffers, killing @cindex killing temporary buffers @kbd{C-c C-q} Issue an exiting command to the inferior process, additionally also running @code{ess-cleanup} for disposing of any temporary buffers (such as help buffers and edit buffers) that may have been created. Use this command when you have finished your R session instead of simply quitting at the inferior process prompt, otherwise you will need to issue the command @code{ess-cleanup} explicitly to make sure that all the files that need to be saved have been saved, and that all the temporary buffers have been killed. @end deffn @node Statistical Process running in ESS? @section Is the Statistical Process running under ESS? @cindex STERM @pindex STERM For the R languages (R, S, S-Plus) ESS sets an option in the current process that programs in the language can check to determine the environment in which they are currently running. ESS sets @code{options(STERM="iESS")} for R language processes running in an inferior @code{@iESS{[S]}} or @code{@iESS{[R]}} buffer. ESS sets @code{options(STERM="ddeESS")} for independent S-Plus for Windows processes running in the GUI and communicating with ESS via the DDE (Microsoft Dynamic Data Exchange) protocol through a @code{ddeESS[S]} buffer. Other values of @code{options()$STERM} that we recommend are: @itemize @bullet @item @code{length}: Fixed length xterm or telnet window. @item @code{scrollable}: Unlimited length xterm or telnet window. @item @code{server}: S-Plus Stat Server. @item @code{BATCH}: BATCH. @item @code{Rgui}: R GUI. @item @code{Commands}: S-Plus GUI without DDE interface to ESS. @end itemize Additional values may be recommended in the future as new interaction protocols are created. Unlike the values @code{iESS} and @code{ddeESS}, ESS can't set these other values since the R language program is not under the control of ESS. @node Emacsclient @section Using emacsclient @cindex emacsclient When starting R or S under Unix, ESS sets @code{options(editor="emacsclient")}. Under Microsoft Windows, it will use gnuclient.exe rather than emacsclient, but the same principal applies. Within your R session, if you have a function called @code{iterator}, typing @code{fix(iterator)}, will show that function in a temporary Emacs buffer. You can then correct the function. When you kill the buffer, the definition of the function is updated. Using @code{edit()} rather than @code{fix()} means that the function is not updated. Finally, the R function @code{page(x)} will also show a text representation of the object @code{x} in a temporary Emacs buffer. @node Other @section Other commands provided by inferior-ESS The following commands are also available in the process buffer: @deffn Command comint-interrupt-subjob @kindex C-c C-c @cindex aborting R commands @cindex interrupting R commands @cindex aborting S commands @cindex interrupting S commands @kbd{C-c C-c} Sends a Control-C signal to the iESS process. This has the effect of aborting the current command. @end deffn @deffn Command ess-switch-to-inferior-or-script-buffer @var{toggle-eob} @kindex C-c C-z @kbd{C-c C-z} When in process buffer, return to the most recent script buffer. When in a script buffer pop to the associated process buffer. Consecutive presses of @kbd{C-z} switch between the script and process buffers. If @var{toggle-eob} is given, the value of @code{ess-switch-to-end-of-proc-buffer} is toggled. @end deffn @defvr {User Option} ess-switch-to-end-of-proc-buffer If non-@code{nil}, @code{ess-switch-to-inferior-or-script-buffer} goes to end of process buffer. @end defvr Other commands available in iESS modes are discussed in @ref{Shell Mode,,, emacs, The Gnu Emacs Reference Manual}. @node Evaluating code @chapter Sending code to the ESS process Other commands are also available for evaluating portions of code in the R process. These commands cause the selected code to be evaluated directly by the ESS process as if you had typed them in at the command line; the @code{source()} function is not used. You may choose whether both the commands and their output appear in the process buffer (as if you had typed in the commands yourself) or if the output alone is echoed. The behavior is controlled by the variable: @defvr {User Option} ess-eval-visibly Non-@code{nil} means @code{ess-eval-*} commands display commands and output in the process buffer. A value of @code{t} blocks Emacs while R is busy. A value of @code{nowait} does not block Emacs but printing may be slightly off. @end defvr @pindex source() @cindex echoing commands when evaluating @cindex evaluating code with echoed commands @cindex ESS commands blocking Emacs Passing a prefix (@kbd{C-u}) (in Elisp terms, the argument VIS) to any of the following commands, however, reverses the meaning of @code{ess-eval-visibly} for that command only --- for example @kbd{C-u C-c C-j} evaluates the current line without showing the input in the iESS buffer. The default value of @code{ess-eval-visibly} (@code{t}) means that ESS calls block Emacs until they finish. This may be undesirable, especially if commands take long to finish. Users who want input to be displayed and Emacs not to be blocked can set @code{ess-eval-visibly} to @code{'nowait}. This sends the input to the iESS buffer but does not wait for the process to finish, ensuring Emacs is not blocked. Primary commands for evaluating code are: @cindex evaluating R expressions @cindex evaluating S expressions @deffn Command ess-eval-region-or-line-and-step @var{vis} @kindex C-RET @kbd{C-} Sends the highlighted region or current line and step to next line of code. @end deffn @deffn Command ess-eval-region-or-function-or-paragraph @var{vis} @kindex C-M-x @kbd{C-M-x} Sends the current selected region or function or paragraph. @end deffn @deffn Command ess-eval-region-or-function-or-paragraph-and-step @var{vis} @kindex C-c C-c @kbd{C-c C-c} Like @code{ess-eval-region-or-function-or-paragraph} but steps to next line of code. @end deffn Other, not so often used, evaluation commands are: @deffn Command ess-eval-line @var{vis} @kindex C-c C-j @kbd{C-c C-j} Sends the current line to the ESS process. @end deffn @deffn Command ess-eval-line-and-go @var{vis} @kindex C-c M-j @kbd{C-c M-j} Like @code{ess-eval-line} but additionally switches point to the ESS process. @end deffn @deffn Command ess-eval-function @var{vis} @var{no-error} @kindex C-c C-f @kbd{C-c C-f} Sends the function containing point to the ESS process. @end deffn @deffn Command ess-eval-function-and-go @var{vis} @kindex C-c M-f @kbd{C-c M-f} Like @code{ess-eval-function} but additionally switches point to the ESS process. @end deffn @deffn Command ess-eval-region @var{start} @var{end} @var{toggle} @var{message} @kindex C-C C-r @kbd{C-c C-r} Sends the current region to the ESS process. @end deffn @deffn Command ess-eval-region-and-go @var{start} @var{end} @var{vis} @kindex C-c M-r @kbd{C-c M-r} Like @code{ess-eval-region} but additionally switches point to the ESS process. @end deffn @deffn Command ess-eval-buffer @var{vis} @kindex C-c C-b @kbd{C-c C-b} Sends the current buffer to the ESS process. @end deffn @deffn Command ess-eval-buffer-and-go @var{vis} @kindex C-c M-b @kbd{C-c M-b} Like @code{ess-eval-buffer} but additionally switches point to the ESS process. @end deffn All the above @code{ess-eval-*} commands are useful for evaluating small amounts of code and observing the results in the process buffer for debugging purposes, or for generating transcripts from source files. When editing R functions, it is generally preferable to use @kbd{C-c C-l} to update the function's value. In particular, @code{ess-eval-buffer} is now largely obsolete. A useful way to work is to divide the frame into two windows; one containing the source code and the other containing the process buffer. If you wish to make the process buffer scroll automatically when the output reaches the bottom of the window, you will need to set the variable @code{comint-move-point-for-output} to @code{'others} or @code{t}. @node Transcript Mode @chapter Manipulating saved transcript files Inferior R mode records the transcript (the list of all commands executed, and their output) in the process buffer, which can be saved as a @dfn{transcript file}, which should normally have the suffix @file{.Rout}. The most obvious use for a transcript file is as a static record of the actions you have performed in a particular R session. Sometimes, however, you may wish to re-execute commands recorded in the transcript file by submitting them to a running ESS process. This is what Transcript Mode is for. If you load file a with the suffix @file{.Rout} into Emacs, it is placed in R Transcript Mode. Transcript Mode is similar to inferior R mode (@pxref{Entering commands}): @cindex transcript mode motion @cindex motion in transcript mode paragraphs are defined as a command and its output, and you can move though commands either with the paragraph commands or with @kbd{C-c C-p} and @kbd{C-c C-n}. @menu * Resubmit:: Resubmitting commands from the transcript file * Clean:: Cleaning transcript files @end menu @node Resubmit @section Resubmitting commands from the transcript file Three commands are provided to re-submit command lines from the transcript file to a running ESS process. They are: @deffn Command ess-transcript-send-command @kindex M-RET @kbd{M-RET} Sends the current command line to the ESS process, and execute it. @end deffn @deffn Command ess-transcript-copy-command @kindex C-c RET @kbd{C-c RET} Copy the current command to the ESS process, and switch to it (ready to edit the copied command). @end deffn @deffn Command ess-transcript-send-command-and-move @kindex RET @kbd{RET} Sends the current command to the ESS process, and move to the next command line. This command is useful for submitting a series of commands. @end deffn @noindent Note that the first two commands are similar to those on the same keys in inferior R Mode. In all three cases, the commands should be executed when the cursor is on a command line in the transcript; the prompt is automatically removed before the command is submitted. @node Clean @section Cleaning transcript files Yet another use for transcript files is to extract the command lines for inclusion in an R source file or function. Transcript mode provides one command which does just this: @deffn Command ess-transcript-clean-region @var{beg} @var{end} @var{even-if-read-only} @kindex C-c C-w @kbd{C-c C-w} Strip the transcript in the region (given by @var{beg} and @var{end}), leaving only commands. Deletes any lines not beginning with a prompt, and then removes the prompt from those lines that remain. Prefix argument @var{even-if-read-only} means to clean even if the buffer is read-only. Don't forget to remove any erroneous commands first! @end deffn @noindent The remaining command lines may then be copied to a source file or edit buffer for inclusion in a function definition, or may be evaluated directly (@pxref{Evaluating code}) using the code evaluation commands from R mode, also available in R Transcript Mode. @node Editing objects @chapter Editing objects and functions @cindex editing functions ESS provides facilities for editing R objects within your Emacs session. Most editing is performed on R functions, although in theory you may edit datasets as well. Edit buffers are always associated with files, although you may choose to make these files temporary if you wish. Alternatively, you may make use of a simple yet powerful mechanism for maintaining backups of text representations of R functions. Error-checking is performed when R code is loaded into the ESS process. @menu * Edit buffer:: Edit objects in a specialized buffer * Loading:: Loading source files into the ESS process * Error Checking:: Detecting errors in source files * Indenting:: Indenting and formatting S code * Other edit buffer commands:: Commands for motion, completion and more * Source Files:: Maintaining R source files * Source Directories:: Names and locations of dump files @end menu @node Edit buffer @section Creating or modifying R objects @cindex edit buffer To edit an object, type @deffn Command ess-dump-object-into-edit-buffer @var{object} @kindex C-c C-e C-d @kbd{C-c C-e C-d} Edit an object in its own edit buffer. @end deffn from within the iESS process buffer (@code{*R*}). You will then be prompted for an object to edit: you may either type in the name of an existing object (for which completion is available using the @kbd{TAB} key), @cindex completion, when prompted for object names or you may enter the name of a new object. @cindex creating new objects @cindex new objects, creating A buffer will be created containing the text representation of the requested object or, if you entered the name of a non-existent object at the prompt and the variable @code{ess-function-template} @vindex ess-function-template is non-@code{nil}, you will be presented with a template defined by that variable, which defaults to a skeleton function construct. You may then edit the function as required. The edit buffer generated by @code{ess-dump-object-into-edit-buffer} is placed in the @code{ESS} major mode which provides a number of commands to facilitate editing R source code. Commands are provided to intelligently indent R code, evaluate portions of R code and to move around R code constructs. @cindex dump files @cindex reverting function definitions Note: when you dump a file with @kbd{C-c C-e C-d}, ESS first checks to see whether there already exists an edit buffer containing that object and, if so, pops you directly to that buffer. If not, ESS next checks whether there is a file in the appropriate place with the appropriate name (@pxref{Source Files}) and if so, reads in that file. You can use this facility to return to an object you were editing in a previous session (and which possibly was never loaded to the R session). Finally, if both these tests fail, the ESS process is consulted and a @code{dump()} command issued. @pindex dump() If you want to force ESS to ask the ESS process for the object's definition (say, to reformat an unmodified buffer or to revert back to R's idea of the object's definition) pass a prefix argument to @code{ess-dump-object-into-edit-buffer} by typing @kbd{C-u C-c C-e C-d}. @node Loading @section Loading source files into the ESS process The best way to get information --- particularly function definitions --- into R is to load them in as source file, using R's @code{source} function. You have already seen how to create source files using @kbd{C-c C-e C-d}; ESS provides a complementary command for loading source files (even files not created with ESS!) into the ESS process, namely @code{ess-load-file} (@kbd{C-c M-l}). @findex ess-load-file @pindex source() @pxref{Hot keys}. @noindent After typing @kbd{C-c M-l} you will prompt for the name of the file to load into R; usually this is the current buffer's file which is the default value (selected by simply pressing @kbd{RET} at the prompt). You will be asked to save the buffer first if it has been modified (this happens automatically if the buffer was generated with @kbd{C-c C-e C-d}). The file will then be loaded, and if it loads successfully you will be returned to the ESS process. @node Error Checking @section Detecting errors in source files @cindex errors @cindex parsing errors If any errors occur when loading a file with @code{C-c C-l}, ESS will inform you of this fact. In this case, you can jump directly to the line in the source file which caused the error by typing @kbd{C-c `} (@code{ess-parse-errors}). @kindex C-c ` @findex ess-parse-errors You will be returned to the offending file (loading it into a buffer if necessary) with point at the line @Sl{} reported as containing the error. You may then correct the error, and reload the file. Note that none of the commands in an R source file will take effect if any part of the file contains errors. Sometimes the error is not caused by a syntax error (loading a non-existent file for example). In this case typing @kbd{C-c `} will simply display a buffer containing S's error message. You can force this behavior (and avoid jumping to the file when there @emph{is} a syntax error) by passing a prefix argument to @code{ess-parse-errors} with @kbd{C-u C-c `}. @node Indenting @section Indenting and formatting R code ESS provides a sophisticated mechanism for indenting R source code. Compound statements (delimited by @samp{@{} and @samp{@}}) are indented relative to their enclosing block. In addition, the braces have been electrified to automatically indent to the correct position when inserted, and optionally insert a newline at the appropriate place as well. Lines which continue an incomplete expression are indented relative to the first line of the expression. Function definitions, @code{if} statements, calls to @code{expression()} and loop constructs are all recognized and indented appropriately. User variables are provided to control the amount of indentation in each case, and there are also a number of predefined indentation styles to choose from. @cindex comments in R Comments are also handled specially by ESS, using an idea borrowed from the Emacs-Lisp indentation style. By default, comments beginning with @samp{###} are aligned to the beginning of the line. Comments beginning with @samp{##} are aligned to the current level of indentation for the block containing the comment. Finally, comments beginning with @samp{#} are aligned to a column on the right (the 40th column by default, but this value is controlled by the variable @code{comment-column},) @vindex comment-column or just after the expression on the line containing the comment if it extends beyond the indentation column. You turn off the default behavior by adding the line @code{(setq ess-indent-with-fancy-comments nil)} to your @file{.emacs} file. @vindex ess-indent-with-fancy-comments ESS also supports roxygen2 entries which is R documentation maintained in the source code as comments @xref{roxygen2}. The indentation commands provided by ESS are: @cindex indenting @cindex formatting source code @deffn Command ess-indent-or-complete @kindex TAB @kbd{TAB} Indents the current line as R code. Try to indent first, and if code is already properly indented, complete instead. In ess-mode, only tries completion if @code{tab-always-indent} is @code{'complete}. See also @code{ess-first-tab-never-complete}. @end deffn @defvr {User Option} ess-first-tab-never-complete If non-@code{nil}, @kbd{TAB} never tries to complete in ess-mode. The default @code{'symbol} does not try to complete if the next char is a valid symbol constituent. There are more options, see the help (@kbd{C-h v}). @end defvr @deffn Command ess-indent-exp @kindex C-M-q @kindex M-C-q @kindex ESC C-q @kbd{TAB} Indents each line in the R (compound) expression which follows point. Very useful for beautifying your R code. @end deffn @deffn Command ess-electric-brace @kindex @{ @kindex @} @kbd{@{} @kbd{@}} The braces automatically indent to the correct position when typed. @end deffn The following Emacs command are also helpful: @table @kbd @item RET @itemx LFD @kindex C-j @code{newline-and-indent} Insert a newline, and indent the next line. (Note that most keyboards nowadays do not have a @key{LINEFEED} key, but @key{RET} and @kbd{C-j} are equivalent.) @item M-; @kindex M-; @code{indent-dwim} Call the comment command you want (Do What I Mean). @end table @menu * Styles:: Changing styles for indentation and alignment @end menu @node Styles @subsection Changing styles for code indentation and alignment The combined value of twelve variables (4 of three groups @code{ess-indent-*}, @code{ess-offset-*} and @code{ess-align-*}) that control indentation are collectively termed a @i{style}. ESS provides several styles covering the common styles of indentation: @code{DEFAULT}, @code{OWN}, @code{GNU}, @code{BSD}, @code{K&R}, @code{C++}, @code{RRR}, @code{RRR+}, @code{Rstudio}, @code{Rstudio-}, and @code{CLB}. The variable @code{ess-style-alist} lists the value of each indentation variable per style (and its documentation contains more). @deffn Command ess-set-style @kindex C-c C-e s @kindex C-c C-e C-s @kbd{C-c C-e C-s} (or @kbd{C-c C-e s}) sets the formatting style in this buffer to be one of the predefined styles, see above. The @code{DEFAULT} style uses the default values for the indenting variables; The @code{OWN} style allows you to use your own private values of the indentation variable, see below. @end deffn @defvr {User Option} ess-style The style to use. See the variable @code{ess-style-alist} for how these groups (DEFAULT, OWN, GNU, RRR, @dots{}) map onto different settings for variables. You can set this in your Emacs configuration file: @example (setq ess-style 'C++) @end example @end defvr @defvr {User Option} ess-style-alist Predefined formatting styles for ESS code. Values for all groups, except OWN, are fixed. To change the value of variables in the OWN group, customize the variable @code{ess-own-style-list}. The default style in use is controlled by @code{ess-style}. @end defvr The styles @code{DEFAULT} and @code{OWN} are initially identical. If you wish to edit some of the default values, set @code{ess-style} to @code{'OWN} and change @code{ess-own-style-list}. @xref{Customization}, for convenient ways to set both these variables. If you prefer not to use the customization facility, you can change individual indentation variables within a hook, for example: @example (defun myindent-ess-hook () (setq ess-indent-level 4)) (add-hook 'ess-mode-hook 'myindent-ess-hook) @end example In the rare case that you'd like to add an entire new indentation style of your own, copy the definition of @code{ess-own-style-list} to a new variable and ensure that the last line of the @code{:set} declaration calls @code{ess-add-style} with a unique name for your style (e.g. @code{'MINE}). Finally, add @code{(setq ess-style 'MINE)} to use your new style. @node Other edit buffer commands @section Commands for motion, completion and more A number of commands are provided to move across function definitions in the edit buffer: @deffn Command ess-goto-beginning-of-function-or-para @kindex ESC C-a @kindex C-M-a @kbd{ESC C-a} aka @kbd{C-M-a} If inside a function go to the beginning of it, otherwise go to the beginning of paragraph. @end deffn @deffn Command ess-goto-end-of-function-or-para @kindex ESC C-e @kindex C-M-e @kbd{ESC C-e} aka @kbd{C-M-e} Move point to the end of the function containing point. @end deffn @deffn Command ess-mark-function @kindex ESC C-h @kindex C-M-h @kbd{ESC C-h} aka @kbd{C-M-h} Place point at the beginning of the R function containing point, and mark at the end. @end deffn @noindent Don't forget the usual Emacs commands for moving over balanced expressions and parentheses: @xref{Lists, Lists and Sexps, Lists and Sexps, Emacs, The GNU Emacs Reference Manual}. @cindex completion in edit buffer Completion is provided in the edit buffer in a similar fashion to the process buffer: @key{TAB} first indents, and if there is nothing to indent, completes the object or file name; @kbd{M-?} lists file completions. See @xref{Completion}, for more. Finally, @kbd{C-c C-z} (@code{ess-switch-to-inferior-or-script-buffer}) returns you to the @code{iESS} process buffer, if done from a script buffer, placing point at the end of the buffer. If this is done from the @code{iESS} process buffer, point is taken to the script buffer. In addition many commands available in the process buffer are also available in the script buffer. You can still read help files with @kbd{C-c C-v}, edit another function with @kbd{C-c C-e C-d} and of course @kbd{C-c C-l} can be used to load a source file into R. @node Source Files @section Maintaining R source files Every edit buffer in ESS is associated with a @dfn{dump file} on disk. Dump files are created whenever you type @kbd{C-c C-e C-d} (@code{ess-dump-object-into-edit-buffer}), and may either be deleted after use, or kept as a backup file or as a means of keeping several versions of an R function. @cindex dump files @defvr {User Option} ess-delete-dump-files If non-@code{nil}, dump files created with C-c C-e C-d are deleted immediately after they are created by the ess-process. @end defvr Since immediately after R dumps an object's definition to a disk file the source code on disk corresponds exactly to R's idea of the object's definition, the disk file isn't needed; deleting it now has the advantage that if you @emph{don't} modify the file (say, because you just wanted to look at the definition of one of the standard R functions) the source dump file won't be left around when you kill the buffer. Note that this variable only applies to files generated with R's @code{dump} function; it doesn't apply to source files which already exist. The default value is @code{t}. @defvr {User Option} ess-keep-dump-files Variable controlling whether to delete dump files after a successful load. If @samp{nil}: always delete. If @samp{ask}, confirm to delete. If @samp{check}, confirm to delete, except for files created with @code{ess-dump-object-into-edit-buffer}. Anything else, never delete. This variable only affects the behaviour of @code{ess-load-file}. Dump files are never deleted if an error occurs during the load. @end defvr After an object has been successfully (without error) loaded back into R with @kbd{C-c C-l}, the disk file again corresponds exactly (well, almost --- see below) to R's record of the object's definition, and so some people prefer to delete the disk file rather than unnecessarily use up space. This option allows you to do just that. @cindex comments @cindex project work in R @cindex project work in S @cindex historic backups If the value of @code{ess-keep-dump-files} is @code{t}, dump files are never deleted after they are loaded. Thus you can maintain a complete text record of the functions you have edited within ESS. Backup files are kept as usual, and so by using the Emacs numbered backup facility --- @pxref{Backup Names, Single or Numbered Backups, Single or Numbered Backups, emacs, The Gnu Emacs Reference Manual}, you can keep a historic record of function definitions. Another possibility is to maintain the files with a version-control system such as git @xref{Version Control, Version Control, Version Control, emacs, The Gnu Emacs Reference Manual}. As long as a dump file exists in the appropriate place for a particular object, editing that object with @kbd{C-c C-e C-d} finds that file for editing (unless a prefix argument is given) --- the ESS process is not consulted. Thus you can keep comments @emph{outside} the function definition as a means of documentation that does not clutter the R object itself. Another useful feature is that you may format the code in any fashion you please without R re-indenting the code every time you edit it. These features are particularly useful for project-based work. If the value of @code{ess-keep-dump-files} is nil, the dump file is always silently deleted after a successful load with @kbd{C-c C-l}. While this is useful for files that were created with @kbd{C-c C-e C-d} it also applies to any other file you load (say, a source file of function definitions), and so can be dangerous to use unless you are careful. Note that since @code{ess-keep-dump-files} is buffer-local, you can make sure particular files are not deleted by setting it to @code{t} in the Local Variables section of the file @xref{File Variables, Local Variables in Files, Local Variables in Files, emacs, The Gnu Emacs Reference Manual}. A safer option is to set @code{ess-keep-dump-files} to @code{ask}; this means that ESS will always ask for confirmation before deleting the file. Since this can get annoying if you always want to delete dump files created with @code{C-c C-e C-d}, but not any other files, setting @code{ess-keep-dump-files} to @code{check} (the default value) will silently delete dump files created with @kbd{C-c C-e C-d} in the current Emacs session, but query for any other file. Note that in any case you will only be asked for confirmation once per file, and your answer is remembered for the rest of the Emacs session. Note that in all cases, if an error (such as a syntax error) is detected while loading the file with @kbd{C-c C-l}, the dump file is @emph{never} deleted. This is so that you can edit the file in a new Emacs session if you happen to quit Emacs before correcting the error. @cindex autosaving Dump buffers are always autosaved, regardless of the value of @code{ess-keep-dump-files}. @node Source Directories @section Names and locations of dump files @cindex dump file names Every dump file should be given a unique file name, usually the dumped object name with some additions. @defvr {User Option} ess-dump-filename-template Template for filenames of dumped objects. @code{%s} is replaced by the object name. @end defvr @noindent By default, dump file names are the user name, followed by @samp{.} and the object and ending with @samp{.R}. Thus if user @code{joe} dumps the object @code{myfun} the dump file will have name @file{joe.myfun.R}. The username part is included to avoid clashes when dumping into a publicly-writable directory, such as @file{/tmp}; you may wish to remove this part if you are dumping into a directory owned by you. @cindex dump file directories You may also specify the directory in which dump files are written: @defvr {User Option} ess-source-directory Directory name (ending in a slash) where R dump files are to be written. @end defvr By default, dump files are always written to @file{/tmp}, which is fine when @code{ess-keep-dump-files} is @code{nil}. If you are keeping dump files, then you will probably want to keep them somewhere in your home directory, say @file{~/R-source}. This could be achieved by including the following line in your Emacs configuration file: @example (setq ess-source-directory (expand-file-name "~/R-source/")) @end example If you would prefer to keep your dump files in separate directories depending on the value of some variable, ESS provides a facility for this also. By setting @code{ess-source-directory} to a lambda expression which evaluates to a directory name, you have a great deal of flexibility in selecting the directory for a particular source file to appear in. The lambda expression is evaluated with the process buffer as the current buffer and so you can use the variables local to that buffer to make your choice. For example, the following expression causes source files to be saved in the subdirectory @file{Src} of the directory the ESS process was run in. @example (setq ess-source-directory (lambda () (concat ess-directory "Src/"))) @end example @noindent @vindex ess-directory (@code{ess-directory} is a buffer-local variable in process buffers which records the directory the ESS process was run from.) This is useful if you keep your dump files and you often edit objects with the same name in different ESS processes. Alternatively, if you often change your R working directory during an R session, you may like to keep dump files in some subdirectory of the directory pointed to by the first element of the current search list. This way you can edit objects of the same name in different directories during the one R session: @cindex search list @cindex working directory @example (setq ess-source-directory (lambda () (file-name-as-directory (expand-file-name (concat (car ess-search-list) "/.Src"))))) @end example @vindex ess-search-list If the directory generated by the lambda function does not exist but can be created, you will be asked whether you wish to create the directory. If you choose not to, or the directory cannot be created, you will not be able to edit functions. @node Help @chapter Reading help files @cindex help files ESS provides an easy-to-use facility for reading R help files from within Emacs. From within the ESS process buffer or any ESS edit buffer, typing @kbd{C-c C-v} (@code{ess-display-help-on-object}) @findex ess-display-help-on-object will prompt you for the name of an object for which you would like documentation. Completion is provided over all objects which have help files. If the requested object has documentation, you will be popped into a buffer (named @code{*help(@var{obj-name})*}) containing the help file. This buffer is placed in a special ESS help mode which disables the usual editing commands but which provides a number of keys for paging through the help file. Help commands: @table @kbd @item ? @findex ess-describe-help-mode @code{ess-describe-help-mode} Pops up a help buffer with a list of the commands available in R help mode. @item h @findex ess-display-help-on-object @code{ess-display-help-on-object} Pop up a help buffer for a different object. @end table Paging commands: @cindex paging commands in help buffers @table @kbd @item DEL @code{scroll-down-command} Move one screen backwards through the help file. @item SPC @code{scroll-up-command} Move one screen forwards through the help file. @item > @itemx < @code{end/beginning-of-buffer} Move to the end or beginning of the help file, respectively. @end table Section-based motion commands: @table @kbd @item n @itemx p @findex ess-skip-to-next-section @findex ess-skip-to-previous-section @code{ess-skip-to-previous-section} and @code{ess-skip-to-next-section} Move to the next and previous section header in the help file, respectively. A section header consists of a number of capitalized words, followed by a colon. @end table In addition, the @kbd{s} key followed by one of the following letters will jump to a particular section in the help file. Note that the exact headings available and capitalization scheme may vary across languages. You may use @kbd{s ?} to get the current list of active key bindings. @findex ess-skip-to-help-section @table @samp @item a Arguments: @item b Background: @item B Bugs: @item d Description: @item D Details: @item e Examples: @item n Note: @item O Optional Arguments: @item R Required Arguments: @item r References: @item s See Also: @item S Side Effects: @item u Usage: @item v Value: @item ? Pops up a help buffer with a list of the defined section motion keys. @end table Evaluation: @table @kbd @item l @findex ess-eval-line-and-step @code{ess-eval-line-and-step} Evaluates the current line in the ESS process, and moves to the next line. Useful for running examples in help files. @item r @findex ess-eval-region @code{ess-eval-region} Send the contents of the current region to the ESS process. Useful for running examples in help files. @end table Quit commands: @table @kbd @item q @findex ess-switch-to-end-of-ESS @code{ess-help-quit} Return to previously selected buffer, and bury the help buffer. @item k @code{kill-buffer} Return to previously selected buffer, and kills the help buffer. @item x @code{ess-kill-buffer-and-go} Return to the ESS process, killing this help buffer. @end table Miscellaneous: @table @kbd @item i @code{ess-display-index} Prompt for a package and display it's help index. @item v @code{ess-display-vignettes} Display all available vignettes. @item w @code{ess-display-help-in-browser} Display current help page with the web browser. @item / @code{isearch-forward} Same as @kbd{C-s}. @end table In addition, all of the ESS commands available in the edit buffers are also available in R help mode (@pxref{Edit buffer}). Of course, the usual (non-editing) Emacs commands are available, and for convenience the digits and @key{-} act as prefix arguments. If a help buffer already exists for an object for which help is requested, that buffer is popped to immediately; the ESS process is not consulted at all. If the contents of the help file have changed, you either need to kill the help buffer first, or pass a prefix argument (with @kbd{C-u}) to @code{ess-display-help-on-object}. Help buffers are marked as temporary buffers in ESS, and are deleted when @code{ess-quit} or @code{ess-cleanup} are called. Help buffers normally appear in another window within the current frame. If you wish help buffers to appear in their own frame (either one per help buffer, or one for all help buffers), you can customize the variable @code{ess-help-own-frame}. Help buffers are displayed by calling the function @code{ess-display-help}. You can customize where these buffers are displayed by adding an entry in @code{display-buffer-alist}; for examples, see @xref{Controlling buffer display,,, ess}. Or by customizing the options @code{ess-help-own-frame}, @code{ess-help-frame-alist}, and @code{ess-display-buffer-reuse-frame}. @findex ess-quit @findex ess-cleanup @cindex temporary buffers @node Completion @chapter Completion @menu * Object names:: * Function arguments:: * Minibuffer completion:: * Company:: * Icicles:: @end menu @node Object names @section Completion of object names @cindex completion of object names @cindex command-line completion @vindex ess-first-tab-never-complete The @key{TAB} key is for completion. The value of the variable @code{ess-first-tab-never-complete} controls when completion is allowed to occur. In @code{ess-mode} @key{TAB} first tries to indent, and if there is nothing to indent, complete the object name instead. @table @kbd @item TAB @findex comint-dynamic-complete @code{comint-dynamic-complete} Complete the R object name or filename before point. @end table When the cursor is just after a partially-completed object name, pressing @key{TAB} provides completion in a similar fashion to the rest of Emacs. ESS maintains a list of all objects known to R at any given time, which basically consists of all objects (functions and datasets) in every attached directory listed by the @code{search()} command @pindex search() along with the component objects of attached data frames @cindex data frames For example, consider three functions @code{binomplot()}, @code{binom.test()} and @code{binomial()}. Typing @kbd{bin TAB} will insert the characters @samp{om}, completing the longest prefix (@samp{binom}) which distinguishes these three commands. Pressing @kbd{TAB} once more provides a list of the three commands which have this prefix, allowing you to add more characters (say, @samp{.}) which specify the function you desire. After entering more characters pressing @kbd{TAB} yet again will complete the object name up to uniqueness, etc. If you just wish to see what completions exist without adding any extra characters, type @kbd{M-?}. @deffn Command ess-complete-object-name @kindex M-? @kbd{M-?} List all possible completions of the object name at point. @end deffn ESS also provides completion over the components of named lists and environments (after @samp{$}), S4 classes slots (after @@), package and namespace objects (after :: and :::). @cindex lists, completion on @cindex completion on lists @cindex completion on file names Completion is also provided over file names, which is particularly useful when using R functions such as @code{get()} or @code{scan()} which require fully expanded file names. In the iESS buffer, if the cursor is not in a string and does not follow a (partial) object name, the @key{TAB} key has a third use: it expands history references. @xref{History expansion}. Efficiency in completion is gained by maintaining a cache of objects currently known to R; when a new object becomes available or is deleted, only one component of the cache corresponding to the associated directory needs to be refreshed. If ESS ever becomes confused about what objects are available for completion (such as when if refuses to complete an object you @strong{know} is there), the command @kbd{M-x ess-resynch} @findex ess-resynch forces the @emph{entire} cache to be refreshed, which should fix the problem. @node Function arguments @section Completion of function arguments When inside a function call (i.e. following `@code{(}'), @kbd{TAB} completion also provides function arguments. If function is a generic, completion will provide all the arguments of @code{S3} methods known to @code{R}. @cindex Space in function argument completion In R versions newer than 2.14.1, ESS uses R's built-in completion engine and will honor its settings. You may read about them by issuing @code{?rc.options} at the prompt. For example, to have the equals sign for function arguments contain spaces on both sides (e.g. @code{lm(for)} suggests @code{formula = } rather than @code{formula=}), you can adjust @code{funarg.suffix}: @example utils::rc.options(funarg.suffix = " = ") @end example A related functionality is @xref{ESS ElDoc}, which displays function arguments in the echo area whenever the point is inside a function call. @node Minibuffer completion @section Minibuffer completion @cindex IDO completions @findex ess-use-ido, ess-completing-read ESS uses @code{IDO} mechanism (part of default Emacs) for minibuffer completion if the @code{ido} package is available and the value of @code{ess-use-ido} it @code{t} (the default). The completion command @code{ess-completing-read} falls back on classic @code{completion-read} interface if this feature is not available for whatever reason. @node Company @section Company @cindex company Another popular package for completion is company, short for complete anything. ESS provides support for company out-of-the-box. To disable company support, set @code{ess-use-company} to @code{nil}. You can set it to @code{'script-only} to only activate company in R scripts. @node Icicles @section Icicles @cindex icicles Another option for comprehensively handling completion in Emacs is via Icicles (@uref{https://www.emacswiki.org/emacs/Icicles}). It allows users to have completions shown temporarily in the standard @samp{*Completions*} buffer, and interactively select completion candidates using several methods. As of version 2013.04.04, Icicles provides support for completion in ESS. Please consult Icicles documentation, which is easily accessible via @kbd{customize-group Icicles}, for more details on installation and customization options. Once installed, Icicles can be activated by evaluating): @example (require 'icicles) (icy-mode 1) @end example Icicles can be toggled by typing @kbd{M-x icy}. When Icicles is on, @kbd{TAB} offers completion, provided the conditions determined by @code{ess-first-tab-never-complete} allow it. Typing @kbd{M-TAB} will attempt completion regardless. Typing @kbd{M-?} in @code{ESS} or @code{iESS} modes brings up the relevant completion candidates from which to choose. Minibuffer input filters the available candidates. Use @kbd{TAB} for prefix completion or @kbd{S-TAB} for substring or regexp completion. Use @kbd{S-SPC} to match an additional pattern (repeatable). You can cycle among the matching candidates, choosing with @kbd{RET} or @kbd{mouse-2}. @node Developing with ESS @chapter Developing with ESS ESS provides several tools to help you with the development of your R packages: @menu * ESS tracebug:: Visual debugging, breakpoints, tracing, watch etc. * Editing documentation:: Tools to edit R documentation * Namespaced Evaluation:: Develop your packages on the fly @end menu @node ESS tracebug @section ESS tracebug @cindex ESS tracebug @findex ess-tracebug @menu * Getting started with tracebug:: Quick tutorial @end menu ESS @code{tracebug} offers visual debugging, interactive error navigation, interactive backtrace, breakpoint manipulation, control over R error actions, watch window and interactive flagging/unflagging of functions for debugging. @code{ess-tracebug} is on by default. You can toggle it on and off with @kbd{M-x} @code{ess-tracebug}. To disable startup activation of @code{ess-tracebug} set @code{ess-use-tracebug} to nil. Tracebug functionality can be found on @code{ess-dev-map}, bound to @kbd{C-c C-t}. Additionally, when subprocess is in a debugging state @code{ess-debug-minor-mode} is active and the following additional shortcuts are available: @verbatim * Interactive Debugging (`ess-debug-minor-mode-map'): M-C . Continue . `ess-debug-command-continue' M-C-C . Continue multi . `ess-debug-command-continue-multi' M-N . Next step . `ess-debug-command-next' M-C-N . Next step multi . `ess-debug-command-next-multi' M-U . Up frame . `ess-debug-command-up' M-Q . Quit debugging . `ess-debug-command-quit' @end verbatim These are all the tracebug commands defined in @code{ess-dev-map} (@kbd{C-c C-t ?} to show this table): @verbatim * Breakpoints (`ess-dev-map'): b . Set BP (repeat to cycle BP type) . `ess-bp-set' B . Set conditional BP . `ess-bp-set-conditional' k . Kill BP . `ess-bp-kil' K . Kill all BPs . `ess-bp-kill-all' o . Toggle BP state . `ess-bp-toggle-state' l . Set logger BP . `ess-bp-set-logger' n . Goto next BP . `ess-bp-next' p . Goto previous BP . `ess-bp-previous' (C- prefixed equivalents are also defined) * Debugging (`ess-dev-map'): ` . Show traceback . `ess-show-traceback' (also on C-c `) ~ . Show callstack . `ess-show-call-stack' (also on C-c ~) e . Toggle error action (repeat to cycle). `ess-debug-toggle-error-action' d . Flag for debugging . `ess-debug-flag-for-debugging' u . Unflag for debugging . `ess-debug-unflag-for-debugging' w . Watch window . `ess-watch' (C- prefixed equivalents are also defined) * Navigation to errors (general Emacs functionality): C-x `, M-g n . `next-error' M-g p . `previous-error' * Misc: ? . Show this help . `ess-tracebug-show-help' @end verbatim To configure how electric watch window splits the display see @code{ess-watch-width-threshold} and @code{ess-watch-height-threshold} variables. @emph{Note:} Currently, ess-tracebug does not detect some of R's debug related messages in non-English locales. To set your R messages to English add the following line to your .Rprofile init file: @verbatim Sys.setlocale("LC_MESSAGES", "C") @end verbatim @node Getting started with tracebug @subsection Getting started with tracebug @cindex tracebug tutorial @findex getting started with tracebug Consider a buffer with the following function: @verbatim test <- function(x){ mean(x), } @end verbatim Evaluating the function (e.g. @code{C-c C-c}) results in an error about an unexpected comma. You can use @code{next-error} (bound by default to @code{C-x `}, @code{M-g n}, and @code{M-g M-n}) to jump to the place where the error occurred. Alternatively, use the mouse to click on the error to jump to where it occurred. Correct the error by deleting the comma. Now put point on @code{mean} and set the breakpoint using @kbd{C-c C-t b} (@code{ess-bp-set}) and reevaluate the function. Jump to the inferior buffer (possibly using @code{C-c C-z}) and evaluate @code{test(1:10)}. An interactive debug process starts, stopping at the breakpoint we just specified. Here you can debug your function (what is @code{x} at this point?). Use @code{M-N} to continue. Let's replace our test function with one slightly more complicated: @verbatim test <- function(x){ x <- x + 1 y <- mean(x) x <- ifelse(x > 5, x, x - 100) list(x, y) } @end verbatim Try setting multiple breakpoints. You can unset a breakpoint by killing it with @kbd{C-c C-t k}. You can set conditional breakpoints too. Try setting one by placing point on the line @code{x <- x + 1} and doing @kbd{C-c C-t B}. ESS will ask for the condition. Let's set it to @code{!is.numeric(x)}. After re-evaluating @code{test}, try calling @code{test(1:100)} and @code{test('foo')}. You can remove all breakpoints with @kbd{C-c C-t K}. You can flag a function for debugging (similar to calling @code{debug(test)} at R's prompt) by doing @kbd{C-c C-t d}. Try this yourself by putting point over @code{test} and doing @kbd{C-c C-t d}. If an error occurs, you can get the complete call stack by doing @kbd{C-c `} or @kbd{C-c C-t `} (@code{ess-show-traceback}). Tracebug also offers a watch window where you can watch values of objects. Open it with @kbd{C-c C-t w} (@code{ess-watch}). Initially you aren't watching anything. Add something with @kbd{a} (e.g. @code{a test}). The watch window displays what the object is at any given time and automatically updates. Quit the watch window with @kbd{q}. @node Editing documentation @section Editing documentation ESS provides two ways of writing documentation for R objects. Either using the standard R documentation system or using in-source documentation written as structured comment fields for use with the roxygen2 package. @menu * R documentation files:: Edit objects in a specialized buffer * roxygen2:: Loading source files into the ESS process @end menu @node R documentation files @subsection Editing R documentation (Rd) files @R{} objects are documented in files written in the @dfn{R documentation} (``Rd''), a simple markup language closely resembling (La)@TeX{}, which can be processed into a variety of formats, including La@TeX{}, @acronym{HTML}, and plain text. Rd format is described in section ``Rd format'' of the ``Writing R Extensions'' manual in the R distribution. ESS has several features that facilitate editing Rd files. Visiting an Rd file as characterized by its extension @file{Rd} will activate Rd Mode, which provides several facilities for making editing R documentation files more convenient, by helping with indentation, insertions, even doing some of the typing for you (with Abbrev Mode), and by showing Rd keywords, strings, etc.@: in different faces (with Font Lock Mode). In Rd mode, the following special Emacs commands can be used in addition to the standard Emacs commands. @table @kbd @item C-h m Describe the features of Rd mode. @item LFD @itemx RET Reindent the current line, insert a newline and indent the new line (@code{reindent-then-newline-and-indent}). An abbrev before point is expanded if @code{abbrev-mode} is non-@code{nil}. @item TAB Indent current line based on its contents and on previous lines. (@code{indent-according-to-mode}). @item C-c C-e Insert a ``skeleton'' with Rd markup for at least all mandatory entries in Rd files (@code{Rd-mode-insert-skeleton}). Note that many users might prefer to use the R function @code{prompt} on an existing R object to generate a non-empty Rd ``shell'' documenting the object (which already has all information filled in which can be obtained from the object). @item C-c C-f Insert ``font'' specifiers for some of the Rd markup commands markup available for emphasizing or quoting text, including markup for URLs and email addresses (@code{Rd-font}). @kbd{C-c C-f} is only a prefix; see e.g.@: @kbd{C-c C-f TAB} for the available bindings. Note that currently, not all of the Rd text markup as described in section ``Marking text'' of ``Writing R Extensions'' can be accessed via @kbd{C-c C-f}. @item C-c C-j Insert a suitably indented @samp{\item@{} on the next line (@code{Rd-mode-insert-item}). @item C-c C-p Preview a plain text version (``help file'', @pxref{Help}) generated from the Rd file (@code{Rd-preview-help}). @end table In addition, when editing Rd files one can interact with a running R process in a similar way as when editing R language files. For example, @kbd{C-c C-v} provides access to on-line help, and @kbd{C-c C-n} sends the current line to the R process for evaluation. This interaction is particularly useful when editing the examples in the Rd file. See @kbd{C-h m} for all available commands. Rd mode also provides access to abbreviations for most of the Rd markup commands. Type @kbd{M-x list-abbrevs} with Abbrev mode turned on to list all available abbrevs. Note that all Rd abbrevs start with a grave accent. Rd mode can be customized via the following variables. @defvr {User Option} Rd-mode-hook Hook to be run when Rd mode is entered. @end defvr @defvr {User Option} Rd-indent-level The indentation of Rd code with respect to containing blocks. Default is 2. @end defvr @defvr {User Option} Rd-to-help-command The shell command used for converting Rd source to help text. Default is @samp{R CMD Rd2txt}. @end defvr To automatically turn on the abbrev and font-lock features of Rd mode, add the following lines to one of your Emacs startup files: @example (add-hook 'Rd-mode-hook (lambda () (abbrev-mode 1) (font-lock-mode 1))) @end example @node roxygen2 @subsection Editing roxygen2 documentation @cindex roxygen2 @cindex roxy @cindex ess-roxy The roxygen2 R package makes it possible to keep the intended contents for Rd files as structured comments in the R source files. roxygen2 can then parse R files and generate appropriate Rd files from these comments, fill the usage fields as well as updating @file{NAMESPACE} files. See the roxygen2 documentation found via @uref{https://roxygen2.r-lib.org} for more information on its usage. An example of an roxygen2 entry for a simple R function can look like this: @example @verbatim ##' Description of the function ##' ##' Further details about this function ##' @title A title ##' @param me all parameters must be listed and documented ##' @return Description of the return value ##' @author The author myfun <- function(me) cat("Hello", me, "\n") @end verbatim @end example The entry is immediately preceding the object to document and all lines start with the roxygen2 prefix string, in this case @code{##'}. ESS provides support to edit these documentation entries by providing line filling, navigation, template generation etc. Syntax highlighting is provided. roxygen2 is customized by the variables in the customization group ``Ess Roxy''. Customizations include the roxygen2 prefix, use of folding to toggle visibility of roxygen2 entries and the roxygen2 template. All ESS roxygen2 support is defined in @file{ess-roxy.el} which is loaded by default in ESS. The following special Emacs commands are provided. @deffn Command ess-roxy-update-entry @kindex C-c C-o C-o @kbd{C-c C-o C-o} Generate a roxygen2 template or update the parameter list in roxygen2 entry at point (or above the function at the point). Documented parameters that are not in the function are placed last in the list, parameters that are not documented and not in the definition are dropped. Parameter descriptions are filled if @code{ess-roxy-fill-param-p} is non-nil. @end deffn @deffn Command ess-roxy-toggle-roxy-region @var{beg} @var{end} @kindex C-c C-o C-c @kbd{C-c C-o C-c} Toggle the presence of the leading roxygen2 string on all lines in the marked region (between @var{beg} and @var{end}. Convenient for transferring text to roxygen2 entries and to evaluate example fields. @end deffn @deffn Command ess-roxy-preview-Rd @var{name-file} @kindex C-c C-o C-r @kbd{C-c C-o C-r} Use the attached R process to parse the entry at point to obtain the Rd code. Convenient for previewing and checking syntax. When used with the prefix argument @var{name-file}, i.e. @kbd{C-u C-c C-e C-r}, place the content in a buffer associated with a Rd file with the same name as the documentation. Requires the roxygen2 package to be installed. @end deffn @deffn Command ess-roxy-preview-HTML @var{visit-instead-of-open} @kindex C-c C-o C-t @kbd{C-c C-o C-t} Use the attached R process to parse the entry at to generate HTML for the entry and open it in a browser. When used with the prefix argument @var{visit-instead-of-open}, i.e. @kbd{C-u C-c C-e C-t}, visit the generated HTML file instead. Requires the roxygen2 and tools packages to be installed. @end deffn @deffn Command ess-roxy-previous-entry @kindex C-c C-o p @kbd{C-c C-o p} Go to start of the roxygen2 entry above point. @end deffn @deffn Command ess-roxy-next-entry @kindex C-c C-o n @kbd{C-c C-o n} Go to end of the roxygen2 entry above point. @end deffn @deffn Command ess-roxy-hide-all @kindex C-c C-o C-h @kbd{C-c C-o C-h} Use the hideshow mode to fold away the visibility of all roxygen2 entries. Hide-show support must be enabled for this binding to get defined. @end deffn ESS also advises the following standard editing functions in order to make roxygen2 editing more intuitive: @c not very precise, TAB calls it indirectly @table @kbd @item TAB @findex ess-R-complete-object-name @code{ess-R-complete-object-name} Complete roxygen2 tag at point. E.g. doing @kbd{TAB} when the point is at the end of @code{@@par} completes to @code{@@param}. @item M-h @findex mark-paragraph @code{mark-paragraph} If the transient mark mode is active, place mark and point at start end end of the field at point and activate the mark. @item TAB @findex ess-indent-command @code{ess-indent-command} If hide-show support is enabled, fold away the visibility of the roxygen2 entry at point. @item M-q @findex fill-paragraph @code{fill-paragraph} Fill the roxygen2 field at point. @item C-a @findex ess-roxy-move-beginning-of-line @code{ess-roxy-move-beginning-of-line} Move to the point directly to the right of the roxygen2 start string. If already there, move to the beginning of the line. @item RET @findex newline-and-indent @code{newline-and-indent} Insert a new line and the roxygen2 prefix string. @end table @node Namespaced Evaluation @section Namespaced Evaluation @cindex ess developer In non package files evaluation commands, @xref{Evaluating code}, send portions of the current buffer environment (@code{R_GlobalEnv}. When developing packages, ESS sends code to the corresponding package namespace and (for visible objects) into package environment (visible on search path). All objects that are assigned are displayed in the minibuffer alongside the environment in which they are assigned. Here is a short overview of how namespace and package environments work in R. All objects defined in a package 'foo' are stored in an environment called 'namespace:foo'. Parent environment of 'namespace:foo' is an environment 'imports:foo' which contains copies of all objects from other packages which 'foo' imports. Parent environment of 'imports:foo' is the 'namespace:base'. Parent environment of 'namespace:base' is .GlobalEnv. Thus functions and methods stored in 'namespace:foo' see all the objects in .GlobalEnv unless shadowed by objects in 'imports:foo', 'namespace:base', or 'namespace:foo' itself. There is another environment associated with 'foo' - 'package:foo'. This environment stores *copies* of exported objects from 'namespace:foo' and is placed on the search() path, i.e. if 'foo' is loaded and if you start with .GlobalEnv and iteratively call parent.env() you will get eventually to 'package:foo'. Thus all methods and functions defined in .GlobalEnv can "see" objects in 'package:foo' environment. See also @uref{https://cran.r-project.org/doc/manuals/R-ints.html#Namespaces}. Occasionally you want to evaluate into a package from a non-package file, or the other way around, evaluate into @code{GlobalEnv} from inside a package. In such cases @kbd{C-c C-t C-s} is your friend. @deffn Command ess-r-set-evaluation-env @var{arg} @kindex C-c C-t C-s @kbd{C-c C-t C-s} Set or unset the current evaluation environment (a package). @end deffn @node Extras @chapter Other ESS features and tools ESS has a few extra features, which didn't fit anywhere else. @c todo: sort alphabetically @menu * ESS ElDoc:: Display function arguments in minibuffer * ESS Flymake:: On-the-fly syntax checking * Handy commands:: Usefully commands at your fingertips * Highlighting:: Syntactic highlighting of buffers * Parens:: Parenthesis matching * Graphics:: Using graphics with ESS * Imenu:: Support for Imenu in ESS * Toolbar:: Support for toolbar in ESS * Xref:: Xref * Rdired:: Directory editor for R objects * Package listing:: R object/package management and help utilities * Org:: Interaction with Org mode * Sweave and AUCTeX:: Support for Sweave in ESS and AUCTeX @end menu @node ESS ElDoc @section ElDoc @cindex ElDoc In @code{ElDoc} mode, the echo area displays function's arguments at point. ElDoc is active by default in @code{ess-mode} and @code{inferior-ess-mode} buffers. To activate it only in @code{ess-mode} buffers, place the following into your init file: @example (setq ess-use-eldoc 'script-only) @end example @defvr {User Option} ess-use-eldoc If @samp{t}, activate eldoc in ess-mode and inferior-ess-mode buffers. If @samp{'script-only} activate in ess-mode buffers only. Set @code{ess-use-eldoc} to @code{nil} to stop using @code{ElDoc} altogether. @end defvr @defvr {User Option} ess-eldoc-show-on-symbol This variable controls whether the help is shown only inside function calls. If set to @samp{t}, @code{ElDoc} shows help string whenever the point is on a symbol, otherwise (the default), shows only when the point is in a function call, i.e. after @samp{'('}. @end defvr @defvr {User Option} ess-eldoc-abbreviation-style The variable determines how the doc string should be abbreviated to fit into minibuffer. Posible values are @samp{nil}, @samp{mild}, @samp{normal}, @samp{strong} and @samp{aggressive}. Please see the documentation of the variable for more details. The default filter is @samp{normal}. @end defvr Ess-eldoc also honors the value of @code{eldoc-echo-area-use-multiline-p}, which if set to @samp{nil}, will cause the truncation of doc string indifferent of the value of @code{ess-eldoc-abbreviation-style}. This way you can combine different filter levels with the truncation. @node ESS Flymake @section Flymake @cindex flymake The minor mode @code{flymake-mode} provides on-the-fly syntax checking. ESS provides support for flymake in R-mode in Emacs versions 26 and newer. It is enabled by default, to disable it you may set @code{ess-use-flymake} to @code{nil}. In order to use it, you may need to install the @code{lintr} R package, available from CRAN. @defvr {User Option} ess-use-flymake When non-nil, use flymake. If @code{'process}, only use flymake when the buffer has an inferior process running. @end defvr @defvr {User Option} ess-r-flymake-linters This variable describes the linters to use. It can either be a string with an R expression to be used as-is or a list of strings where each element is passed to @code{lintr::with_defaults}. See the help page for @code{lintr::default_linters} for information on available linters and their defaults. @end defvr @defvr {User Option} ess-r-flymake-lintr-cache When @code{t} (the default), lintr uses a cache. Change to @code{nil} to disable lintr's caching mechanism. @end defvr @node Handy commands @section Handy commands @cindex Handy commands @findex ess-handy-commands @vindex ess-handy-commands @findex ess-smart-comma @kindex , @deffn Command ess-handy-commands Request and execute a command from @code{ess-handy-commands} list. @end deffn @defvr {User Option} ess-handy-commands An alist of custom ESS commands available for call by @code{ess-handy-commands} and @code{ess-smart-comma} function. Currently contains: @table @asis @item change-directory @code{ess-change-directory} @item help-index @code{ess-display-index} @item help-object @code{ess-display-help-on-object} @item vignettes @code{ess-display-vignettes} @item objects[ls] @code{ess-execute-objects} @item search @code{ess-execute-search} @item set-width @code{ess-execute-screen-options} @item install.packages @code{ess-install.packages} @item library @code{ess-library} @item setRepos @code{ess-setRepositories} @item sos @code{ess-sos} @end table @end defvr @c If ``@kbd{,}`` (@code{ess-smart-comma}) is invoked at the beginning of @c line of an ESS inferior buffer (i.e. at process marker), ESS requests and @c executes a command from @code{`ess-handy-commands'} list. If @c @code{ess-R-smart-operators} is t @code{`ess-smart-comma} also inserts @c `` `` after comma. Handy commands: @code{ess-library}, @code{ess-install.packages}, etc - ask for item with completion and execute the correspond command. @code{ess-sos} is a interface to @code{findFn} function in package @code{sos}. If package @code{sos} is not found, ask user for interactive install. @node Highlighting @section Syntactic highlighting of buffers ESS provides Font-Lock (@pxref{Faces,,Using Multiple Typefaces, emacs, The Gnu Emacs Reference Manual}) patterns for inferior R Mode, S Mode, and R Transcript Mode buffers. @cindex font-lock mode @cindex highlighting The font-lock patterns are defined by the following variables, which you may modify if desired: @defvr {User Option} inferior-R-font-lock-keywords Font-lock patterns for inferior *R* processes. (There is a corresponding @code{inferior-S-font-lock-keywords} for *S* processes.) The default value highlights prompts, inputs, assignments, output messages, vector and matrix labels, and literals such as @samp{NA} and @code{TRUE}. @end defvr @defvr {User Option} ess-R-font-lock-keywords Font-lock patterns for ESS R programming mode. (There is a corresponding @code{ess-S-font-lock-keywords} for S buffers.) The default value highlights function names, literals, assignments, source functions and reserved words. @end defvr @node Parens @section Parenthesis matching Emacs has facilities for highlighting the parenthesis matching the parenthesis at point. This feature is very useful when trying to examine which parentheses match each other. This highlighting also indicates when parentheses are not matching. You may activate it putting this in your Emacs configuration file: @example (show-paren-mode) @end example @node Graphics @section Using graphics with ESS @cindex graphics One of the main features of R is its ability to generate high-resolution graphics plots. When using R in a windowing environment, no additional configuration is necessary; plots will be shown in a new (non-Emacs) window. If not using a windowing environment or S, ESS provides a number of features for dealing with such plots. @menu * printer:: The printer() graphics driver * X11:: The X11() (and other X Windows based) driver * winjava:: Java Graphics Device @end menu @node printer @subsection Using ESS with the @code{printer()} driver This is the simplest (and least desirable) method of using graphics within ESS. S's @code{printer()} device driver produces crude character based plots which can be contained within the ESS process buffer itself. To start using character graphics, issue the S command @example printer(width=79) @end example @pindex printer() (the @code{width=79} argument prevents Emacs line-wrapping at column 80 on an 80-column terminal. Use a different value for a terminal with a different number of columns.) Plotting commands do not generate graphics immediately, but are stored until the @code{show()} command is issued, which displays the current figure. @node X11 @subsection Using ESS with windowing devices @cindex X Windows Of course, the ideal way to use graphics with ESS is to use a windowing system. Under X Windows, or X11, this requires that the DISPLAY environment variable be appropriately set. @node winjava @subsection Java Graphics Device @cindex winjava S+6.1 and newer on Windows contains a java library that supports graphics. Send the commands: @example library(winjava) java.graph() @end example @noindent to start the graphics driver. This allows you to use ESS for both interaction and graphics within S-PLUS. (Thanks to Tim Hesterberg for this information.) @node Imenu @section Imenu Imenu is an Emacs tool for providing mode-specific buffer indexes. In some of the ESS editing modes (currently SAS and R), support for Imenu is provided. For example, in R mode buffers, the menubar should display an item called "Imenu-R". Within this menubar you will then be offered bookmarks to particular parts of your source file (such as the starting point of each function definition). Imenu works by searching your buffer for lines that match what ESS thinks is the beginning of a suitable entry, for example the beginning of a function definition. To examine the regular expression that ESS uses, check the value of @code{imenu-generic-expression}. This value is set by various ESS variables such as @code{ess-imenu-S-generic-expression}. @node Toolbar @section Toolbar The R and S editing modes have support for a toolbar. This toolbar provides icons to act as shortcuts for starting new S/R processes, or for evaluating regions of your source buffers. The toolbar should be present if your Emacs can display images. @xref{Customization}, for ways to change the toolbar. @node Xref @section Xref @cindex xref @cindex finding function definitions Xref is an Emacs interface that supports finding ``identifiers,'' usually function definitions in ESS's view. ESS ships with support for Xref in Emacs versions 25.1 and higher. For how to use this feature, see @xref{Xref,,, emacs, The Gnu Emacs Reference Manual}. @node Rdired @section Rdired Ess-rdired provides a dired-like buffer for viewing, editing and plotting objects in your current R session. If you are used to using the dired (directory editor) facility in Emacs, this mode gives you similar functionality for R objects. Start an R session with @kbd{M-x R} and then store a few variables, such as: @example s <- sin(seq(from=0, to=8*pi, length=100)) x <- c(1, 4, 9) y <- rnorm(20) z <- TRUE @end example Then use @kbd{M-x ess-rdired} to create a buffer listing the objects in your current environment and display it in a new window: @example mode length s numeric 100 x numeric 3 y numeric 20 z logical 1 @end example Type @kbd{C-h m} or @kbd{?} to get a list of the keybindings for this mode. For example, with your point on the line of a variable, `p' will plot the object, `v' will view it, and `d' will mark the object for deletion (`x' will actually perform the deletion). @node Package listing @section Package listing ESS[R] provides several commands to list and manage packages and objects under the @code{C-c C-.} keymap: @deffn Command ess-r-package-list-local-packages @kindex C-c C-. l @kbd{C-c C-. l} List all packages in all available libraries. @end deffn @deffn Command ess-r-package-list-available-packages @kindex C-c C-. r @kbd{C-c C-. r} List available packages from repositories listed by @command{getOptions(``repos'')} in the current R session. @end deffn @deffn Command ess-r-package-update-packages @var{lib} @var{repos} @kindex C-c C-. u @kbd{C-c C-. u} Update packages in a particular library @var{lib} and repository @var{repos}. @end deffn @deffn Command ess-rutils-rm-all @kindex C-c C-. m @kbd{C-c C-. m} Remove all R objects. @end deffn @deffn Command ess-rutils-load-workspace @kindex C-c C-. w @kbd{C-c C-. w} Load a workspace file into R. @end deffn @deffn Command ess-rutils-save-workspace @kindex C-c C-. s @kbd{C-c C-. s} Save a workspace file. @end deffn @deffn Command ess-change-directory @kindex C-c C-. d @kbd{C-c C-. d} Change the working directory for the current R session. @end deffn @deffn Command ess-rutils-html-docs @kindex C-c C-. H @kbd{C-c C-. H} Use @command{browse-url} to navigate R html documentation. @end deffn Functions for listing objects and packages (@command{ess-rutils-local-pkgs}, @command{ess-rutils-repos-pkgs}, and @command{ess-rutils-objs}) show results in a separate buffer and window, in @code{ess-rutils-mode}, providing useful key bindings in this mode (type @kbd{?} in this buffer for a description). @node Org @section Interaction with Org mode Org-mode (@uref{https://orgmode.org}) now supports reproducible research and literate programming in many languages (including R) -- see chapter 15 of the Org manual (@uref{https://orgmode.org/org.html#Working-with-Source-Code}). For ESS users, this offers a document-based work environment within which to embed ESS usage. R code lives in code blocks of an Org document, from which it can be edited in ess-mode, evaluated, extracted ("tangled") to pure code files. The code can also be exported ("woven") with the surrounding text to several formats including HTML and LaTeX. Results of evaluation including figures can be captured in the Org document, and data can be passed from the Org document (e.g. from a table) to the ESS R process. (This section contributed by Dan Davison and Eric Schulte.) @node Sweave and AUCTeX @section Support for Sweave in ESS and AUCTeX Libraries for literate data analysis are obsolete and not loaded by default. This includes @code{ess-noweb}, @code{ess-swv}, and related functionality like @code{Rnw-mode}. Users are encouraged to switch to one of several other packages that deal with these modes. For example, polymode @url{https://github.com/polymode/poly-R/}, @url{https://polymode.github.io/}, or markdown-mode with edit-indirect @url{https://jblevins.org/projects/markdown-mode}. ESS provides support for writing and processing Sweave (@uref{https://leisch.userweb.mwn.de/Sweave/}), building up on Emacs' ess-noweb-mode for literate programming. When working on an Sweave document, the following key bindings are available: @deffn Command ess-swv-weave @var{choose} @kindex M-n s @kbd{M-n s} Run Sweave on the current .Rnw file. If @var{choose} is non-@samp{nil}, offer a menu of available weavers. @end deffn @deffn Command ess-swv-latex @kindex M-n l @kbd{M-n l} Run LaTeX after Sweave'ing. @end deffn @deffn Command ess-swv-PS @kbd{M-n p} Generate and display a postscript file after LaTeX'ing. @end deffn @deffn Command ess-swv-PDF @var{pdflatex-cmd} @kindex M-n P @kbd{M-n P} Generate and display a PDF file after LaTeX'ing. Optional argument @var{pdflatex-cmd} is the command to use, which by default, is the command used to generate the PDF file is the first element of @code{ess-swv-pdflatex-commands}. @end deffn @defvr {User Option} ess-swv-pdflatex-commands Commands used by @code{ess-swv-PDF} to run a version of pdflatex; the first entry is the default command. @end defvr Sweave'ing with @code{ess-swv-weave} starts an inferior-ESS process, if one is not available. Other commands are available from the @samp{Sweaving, Tangling, ...} submenu of the Noweb menu. AUCTeX (@uref{https://www.gnu.org/software/auctex}) users may prefer to set the variable @code{ess-swv-plug-into-AUCTeX-p} (available from the ``ESS Sweave'' customization group) to t. Alternatively, the same can be achieved by activating the entry ``AUCTeX Interface'' from the @samp{Sweaving, Tangling, ...} submenu, which toggles this variable on or off. When the interface is activated, new entries for Sweave'ing and LaTeX'ing thereafter are available from AUCTeX's ``Command'' menu. Sweave'ing can, thus, be done by @kbd{C-c C-c Sweave RET} without an inferior-ESS process. Similarly, LaTeX'ing can be done by @kbd{C-c C-c LaTeXSweave RET}. In both cases, the process can be monitored with @kbd{C-c C-l} (@code{TeX-recenter-output-buffer}). Open the viewer with @kbd{C-c C-v} (@code{TeX-view}), as usual in AUCTeX. @node ESS for R @chapter Overview of ESS features for the S family @menu * ESS(R)--Editing files:: * iESS(R)--Inferior ESS processes:: * Philosophies for using ESS(R):: * Example ESS usage:: @end menu @include help-s.texi @node ESS for SAS @chapter ESS for SAS @menu * ESS(SAS)--Design philosophy:: * ESS(SAS)--Editing files:: * ESS(SAS)--TAB key:: * ESS(SAS)--Batch SAS processes:: * ESS(SAS)--Function keys for batch processing:: * iESS(SAS)--Interactive SAS processes:: * iESS(SAS)--Common problems:: * ESS(SAS)--Graphics:: * ESS(SAS)--Windows:: @end menu @include help-sas.texi @node ESS for BUGS @chapter ESS for BUGS @include help-bugs.texi @node ESS for JAGS @chapter ESS for JAGS @include help-jags.texi @node Mailing lists/bug reports @chapter Bugs and Bug Reporting, Mailing Lists @menu * Bugs:: * Reporting Bugs:: * Mailing Lists:: * Help with Emacs:: @end menu @node Bugs @section Bugs @cindex bugs @include bugs.texi @node Reporting Bugs @section Reporting Bugs @cindex bug reports @findex ess-submit-bug-report @include bugrept.texi @node Mailing Lists @section Mailing Lists @include mailing.texi @node Help with Emacs @section Help with Emacs Emacs is a complex editor with many abilities that we do not have space to describe here. If you have problems with other features of Emacs (e.g. printing), there are several sources to consult, including the Emacs FAQs (try @kbd{M-x view-emacs-faq}) and EmacsWiki (@uref{https://www.emacswiki.org}). Please consult them before asking on the mailing list about issues that are not specific to ESS. @node Customization @appendix Customizing ESS @cindex customization ESS can be easily customized to your taste simply by including the appropriate lines in your Emacs configuration file. There are numerous variables which affect the behavior of ESS in certain situations which can be modified to your liking. Keybindings may be set or changed to your preferences, and for per-buffer customizations hooks are also available. Most of these variables can be viewed and set using the Custom facility within Emacs. Type @kbd{M-x customize-group RET ess RET} to see all the ESS variables that can be customized. Variables are grouped by subject to make it easy to find related variables. @node Indices @unnumbered Indices @menu * Key index:: * Function and program index:: * Variable index:: * Concept index:: @end menu @node Key index @unnumberedsec Key index @printindex ky @node Function and program index @unnumberedsec Function and program index @printindex fn @node Variable index @unnumberedsec Variable index @printindex vr @node Concept index @unnumberedsec Concept Index @printindex cp @bye @iftex @lucidbook @bindingoffset = 0.5in @parindent = 0pt @end iftex @comment Local Variables: @comment TeX-master: "ess.texi" @comment End: ESS-24.01.1/doc/help-bugs.texi000066400000000000000000000031701455642170100156450ustar00rootroot00000000000000@ESS{[BUGS]} provides 5 features. First, BUGS syntax is described to allow for proper fontification of statements, distributions, functions, commands and comments in BUGS model files, command files and log files. Second, @ESS{} creates templates for the command file from the model file so that a BUGS batch process can be defined by a single file. Third, @ESS{} provides a BUGS batch script that allows @ESS{} to set BUGS batch parameters. Fourth, key sequences are defined to create a command file and submit a BUGS batch process. Lastly, interactive submission of BUGS commands is also supported. @section ESS[BUGS]--Model files Model files with the @file{.bug} extension are edited in @ESS{[BUGS]} mode. Three keys are bound for your use in @ESS{[BUGS]}, @kbd{F2}, @kbd{C-c C-c} and @kbd{=}. @kbd{F2} performs the same action as it does in @ESS{[SAS]}, @xref{ESS(SAS)--Function keys for batch processing}. @kbd{C-c C-c} performs the function @code{ess-bugs-next-action} which you will use a lot. Pressing it in an empty buffer for a model file will produce a template for you. @kbd{=} inserts the set operator, @code{<-}. @section ESS[BUGS]--Command files Files ending in @file{.bmd} are used for BUGS command files. When you have finished editing your model file and press @kbd{C-c C-c}, a command file is created if one does not already exist. When you are finished editing your command file, pressing @kbd{C-c C-c} again will submit your command file as a batch job. @section ESS[BUGS]--Log files The @file{.bog} extension is used for BUGS log files. The command line generated by @ESS{} creates the @file{.bog} transcript file. ESS-24.01.1/doc/help-jags.texi000066400000000000000000000064161455642170100156370ustar00rootroot00000000000000@ESS{[JAGS]} provides 4 features. First, JAGS syntax is described to allow for proper fontification of statements, distributions, functions, commands and comments in JAGS model files, command files and log files. Second, @ESS{} creates templates for the command file from the model file so that a JAGS batch process can be defined by a single file. Third, @ESS{} provides a JAGS batch script that allows @ESS{} to set JAGS batch parameters. Fourth, key sequences are defined to create a command file and submit a JAGS batch process. @section ESS[JAGS]--Model files Files with the @file{.jag} extension are edited in @ESS{[JAGS]} mode. Three keys are bound for your use in @ESS{[JAGS]}, @kbd{F2}, @kbd{C-c C-c} and @kbd{=}. @kbd{F2} performs the same action as it does in @ESS{[SAS]}, @xref{ESS(SAS)--Function keys for batch processing}. @kbd{C-c C-c} performs the function @code{ess-bugs-next-action} which you will use a lot. Pressing it in an empty buffer for a model file will produce a template for you. @kbd{=} inserts the set operator, @code{<-}. The first press of @kbd{C-c C-c} will set up a template, including some necessary file-local variables in an empty buffer. These variables are @code{ess-jags-chains}, @code{ess-jags-monitor}, @code{ess-jags-thin}, @code{ess-jags-burnin} and @code{ess-jags-update}; they appear in the @code{Local Variables} section. When you are finished editing your model file, pressing @kbd{C-c C-c} will perform the necessary actions to build your command file for you. The @code{ess-jags-chains} variable is the number of chains that you want to initialize and sample from; defaults to 1. The @code{ess-jags-monitor} variable is a list of variables that you want monitored: encase each variable in double quotes. When you press @kbd{C-c C-c}, the appropriate statements are created in the command file to monitor the list of variables. By default, no variables are explicitly monitored which means JAGS will implicitly monitor all ``default'' variables. The @code{ess-jags-thin} variable is the thinning parameter. By default, the thinning parameter is set to 1, i.e. no thinning. The @code{ess-jags-burnin} variable is the number of initial samples to discard. By default, the burnin parameter is set to 10000. The @code{ess-jags-update} variable is the number of post-burnin samples to keep. By default, the update parameter is set to 10000. Both @code{ess-jags-burnin} and @code{ess-jags-update} are multiplied by @code{ess-jags-thin} since JAGS does not do it automatically. @section ESS[JAGS]--Command files Files ending in @file{.jmd} are for JAGS command files. For your @file{.jmd} file, there is only one variable, @code{ess-jags-command}, in the @code{Local Variables} section. When you have finished editing your model file and press @kbd{C-c C-c}, a command file is created if one does not already exist. When you are finished editing your command file, pressing @kbd{C-c C-c} again will submit your command file as a batch job. The @code{ess-jags-command} variable allows you to specify a different JAGS program to use to run your model; defaults to ``jags''. @section ESS[JAGS]--Log files The @file{.jog} extension is used for JAGS log files. You may find @kbd{F2} useful to refresh the @file{.jog} if the batch process over-writes or appends it. ESS-24.01.1/doc/help-s.texi000066400000000000000000000116671455642170100151610ustar00rootroot00000000000000@node ESS(R)--Editing files @section ESS[R]--Editing files @ESS{[R]} mode should be automatically turned on when visiting a file ending with an R or S suffix (*.R, *.S, *.s, etc), which enables the features discussed previously. Alternatively, type @kbd{M-x R-mode} to put the current buffer into R mode. However, one will have to start up an inferior process to take advantage of the interactive features. @node iESS(R)--Inferior ESS processes @section iESS[R]--Inferior ESS processes To start up iESS mode for R, use: @example M-x R M-x S+3 M-x S4 M-x S+5 M-x S+6 @end example @noindent (for R, S-PLUS 3.x, S4, S+5, S+6 or S+7, respectively. This assumes that you have access to each). @cindex command line arguments In the case that you wish to pass command line arguments to the starting R process, call it with the universal prefix. To set command line arguments that apply to all future iESS sessions, set the variable @code{inferior-R-args}. Note that R has some extremely useful command line arguments. For example, @code{--vanilla} will ensure R starts up without loading in any init files. If you have other versions of R or S available on the system, ESS is also able to start those versions. How this exactly works depend on which OS you are using (details below). The general principle, regardless of OS, is that ESS searches the paths listed in the variable @code{exec-path} for R binaries. If ESS cannot find your R binaries, on Unix you can change the Unix environment variable @code{PATH}, as this variable is used to set @code{exec-path}. R on GNU/Linux systems and other Unix-like systems (macOS): If you have "R-3.6.3" on your @code{exec-path}, it can be started using @kbd{M-x R-3.6.3}. By default, ESS will find versions of R beginning ``R-1'', ``R-2'', @dots{}, ``R-7'', ``R-devel'', or ``R-patched''. If your versions of R are called other names, consider renaming them with a symbolic link or change the variable @code{ess-r-runners-prefixes}. To see which functions have been created for starting different versions of R, type @kbd{M-x R-} and then hit [Tab]. These other versions of R can also be started from the "ESS->Start Process->Other" menu. R on Windows systems: If you have "rw1081" on your @code{exec-path}, it can be started using @kbd{M-x rw1081}. By default, ESS will find versions of R located in directories parallel to the version of R in your @code{PATH}. If your versions of R are called other names, you will need to change the variable @code{ess-rterm-versions}. To see which functions have been created for starting different versions of R, type @kbd{M-x rw} and then hit [Tab]. These other versions of R can also be started from the "ESS->Start Process->Other" menu. Once ESS has found these extra versions of R, it will then create a new function, called @kbd{M-x run-ess-r-newest}, which will call the newest version of R that it found. (ESS examines the date in the first line of information from @code{R --version} to determine which is newest.) @node Philosophies for using ESS(R) @section Philosophies for using ESS[R] There are two philosophies for using ESS. Most modern best practices prefer the first. ESS is configured for the first, and this is what the manual focuses on. 1: The source code is real. Objects are realizations of the source code. Source for EVERY user modified object is placed in a particular directory or directories, for later editing and retrieval. 2: R objects are real. Source code is a temporary realization of the objects. Dumped buffers should not be saved. _We_strongly_discourage_this_approach_. However, if you insist, add the following lines to your Emacs configuration file: @example (setq ess-keep-dump-files nil) (setq ess-delete-dump-files t) (setq ess-mode-silently-save nil) @end example @node Example ESS usage @section Example ESS usage Comments as to what should be happening are prefixed by "##". @display ### Data Analysis Example ## Open the file you want with C-x C-f myfile.R ## Edit as appropriate, then start and switch to an *R* process buffer with C-c C-z ## A new buffer *R* will appear. R will have been started ## in this buffer. The buffer is in iESS [R] mode. ## Return to the script C-z (or C-c C-z if you have pressed other keys in between) ## Send current region (if active), or function, or paragraph at point with C-M-x ## Send current region or function or paragraph and step with C-c C-c ## Send current line with C-RET ## or load the entire buffer with C-c C-l ## Save the revised myfile.R with C-x C-s. ## Save the entire *R* interaction buffer with C-x C-s. ## Search for documentation with C-c C-d ## Investigate available ESS commands with C-c C-h ## You will be prompted for a file name. The recommended name is ## myfile.Rout. With this suffix, the file will be opened in ## ess-transcript. @end display ESS-24.01.1/doc/help-sas.texi000066400000000000000000000665101455642170100155020ustar00rootroot00000000000000@ESS{[SAS]} was designed for use with @SAS{}. It is descended from emacs macros developed by John Sall for editing @SAS{} programs and @code{SAS-mode} by Tom Cook. Those editing features and new advanced features are part of @ESS{[SAS]}. The user interface of @ESS{[SAS]} has similarities with @ESS{[S]} and the @SAS{} Display Manager. @node ESS(SAS)--Design philosophy @section ESS[SAS]--Design philosophy @ESS{[SAS]} was designed to aid the user in writing and maintaining @SAS{} programs, such as @file{@var{foo}.sas}. Both interactive and batch submission of @SAS{} programs is supported. @ESS{[SAS]} was written with two primary goals. @enumerate @item The emacs text editor provides a powerful and flexible development environment for programming languages. These features are a boon to all programmers and, with the help of @ESS{[SAS]}, to @SAS{} users as well. @item Although a departure from @SAS{} Display Manager, @ESS{[SAS]} provides similar key definitions to give novice @ESS{[SAS]} users a head start. Also, inconvenient @SAS{} Display Manager features, like remote submission and syntax highlighting, are provided transparently; appealing to advanced @ESS{[SAS]} users. @end enumerate @node ESS(SAS)--Editing files @section ESS[SAS]--Editing files @ESS{[SAS]} is the mode for editing @SAS{} language files. This mode handles: @itemize @bullet @item proper indenting, generated by both @key{TAB} and @key{RET}. @item color and font choices based on syntax. @item ability to save and submit the file you are working on as a batch @SAS{} process with a single keypress and to continue editing while it is runs in the background. @item capability of killing the batch @SAS{} process through the @file{*shell*} buffer or allow the @SAS{} process to keep on running after you exit emacs. @item single keypress navigation of @file{.sas}, @file{.log} and @file{.lst} files (@file{.log} and @file{.lst} files are refreshed with each keypress). @item ability to send the contents of an entire buffer, a highlighted region, or a single line to an interactive @SAS{} process. @item ability to switch between processes which would be the target of the buffer (for the above). @end itemize @ESS{[SAS]} is automatically turned on when editing a file with a @file{.sas} suffix (or other extension, if specified via @code{auto-mode-alist}). The function keys can be enabled to use the same function keys that the @SAS{} Display Manager does. The interactive capabilities of @ESS{} require you to start an inferior @SAS{} process with @wkbd{M-x SAS} (@xref{iESS(SAS)--Interactive SAS processes}.) At this writing, the indenting and syntax highlighting are generally correct. Known issues: for multiple line @code{*} or @code{%*} comments, only the first line is highlighted; for @file{.log} files, only the first line of a @code{NOTE:}, @code{WARNING:} or @code{ERROR:} message is highlighted; unmatched single/double quotes in @code{CARDS} data lines are @strong{NOT} ignored; in an iterative @code{DO} statement, @code{TO} and @code{BY} are not highlighted. @node ESS(SAS)--TAB key @section ESS[SAS]--@key{TAB} key Two options. The @key{TAB} key is bound by default to @code{sas-indent-line}. This function is used to syntactically indent @SAS{} code so @code{PROC} and @code{RUN} are in the left margin, other statements are indented @code{sas-indent-width} spaces from the margin, continuation lines are indented @code{sas-indent-width} spaces in from the beginning column of that statement. This is the type of functionality that emacs provides in most programming language modes. This functionality is activated by placing the following line in your initialization file prior to a @code{require}/@code{load}: @example (setq ess-sas-edit-keys-toggle nil) @end example @ESS{} provides an alternate behavior for @key{TAB} that makes it behave as it does in @SAS{} Display Manager, i.e. move the cursor to the next stop. The alternate behavior also provides a "TAB" backwards, @wkbd{C-@key{TAB}}, that moves the cursor to the stop to the left and deletes any characters between them. This functionality is obtained by placing the following line in your initialization file prior to a @code{require}/@code{load}: @example (setq ess-sas-edit-keys-toggle t) @end example Under the alternate behavior, @key{TAB} is bound to @wkbd{M-x tab-to-tab-stop} and the stops are defined by @code{ess-sas-tab-stop-list}. @node ESS(SAS)--Batch SAS processes @section ESS[SAS]--Batch SAS processes Submission of a @SAS{} batch job is dependent on your environment. @code{ess-sas-submit-method} is determined by your operating system and your shell. It defaults to @code{'sh} unless you are running Windows or Mac Classic. Under Windows, it will default to @code{'sh} if you are using a @UNIX{}-imitating shell; otherwise @code{'ms-dos} for an @acronym{MS-DOS} shell. On macOS, it will default to @code{'sh}, but under Mac Classic, it defaults to @code{'apple-script}. You will also set this to @code{'sh} if the @SAS{} batch job needs to run on a remote machine rather than your local machine. This works transparently if you are editing the remote file via ange-ftp/EFS or tramp. Note that @code{ess-sas-shell-buffer-remote-init} is a Local Variable that defaults to @code{"ssh"} which will be used to open the buffer on the remote host and it is assumed that no password is necessary, i.e. you are using @code{ssh-agent}/@code{ssh-add} or the equivalent (see the discussion about Local Variables below if you need to change the default). However, if you are editing the file locally and transferring it back and forth with Kermit, you need some additional steps. First, start Kermit locally before remotely logging in. Open a local copy of the file with the @code{ess-kermit-prefix} character prepended (the default is @code{"#"}). Execute the command @wkbd{M-x ess-kermit-get} which automatically brings the contents of the remote file into your local copy. If you transfer files with Kermit manually in a @file{*shell*} buffer, then note that the Kermit escape sequence is @wkbd{C-q C-\ c} rather than @wkbd{C-\ c} which it would be in an ordinary terminal application, i.e. not in an emacs buffer. Lastly, note that the remote Kermit command is specified by @code{ess-kermit-command}. The command used by the @code{SUBMIT} function key (@key{F3} or @key{F8}) to submit a batch @SAS{} job, whether local or remote, is @code{ess-sas-submit-command} which defaults to @code{sas-program}. @code{sas-program} is @code{"invoke SAS using program file"} for Mac Classic and @code{"sas"} otherwise. However, you may have to alter @code{ess-sas-submit-command} for a particular program, so it is defined as buffer-local. Conveniently, it can be set at the end of the program: @example endsas; Local variables: ess-sas-submit-command: "sas8" End: @end example The command line is also made of @code{ess-sas-submit-pre-command}, @code{ess-sas-submit-post-command} and @code{ess-sas-submit-command-options} (the last of which is also buffer-local). Here are some examples for your @initfile{} file (you may also use @wkbd{M-x customize-variable}): @example ;'sh default (setq ess-sas-submit-pre-command "nohup") ;'sh default (setq ess-sas-submit-post-command "-rsasuser &") ;'sh example (setq-default ess-sas-submit-command "/usr/local/sas/sas") ;'ms-dos default (setq ess-sas-submit-pre-command "start") ;'ms-dos default (setq ess-sas-submit-post-command "-rsasuser -icon") ;Windows example (setq-default ess-sas-submit-command "c:/progra~1/sas/sas.exe") ;Windows example (setq-default ess-sas-submit-command "c:\\progra~1\\sas\\sas.exe") @end example There is a built-in delay before a batch @SAS{} job is submitted when using a @UNIX{}-imitating shell under Windows. This is necessary in many cases since the shell might not be ready to receive a command. This delay is currently set high enough so as not to be a problem. But, there may be cases when it needs to be set higher, or could be set much lower to speed things up. You can over-ride the default in your @initfile{} file by: @example (setq ess-sleep-for 0.2) @end example For example, @code{(setq ess-sas-global-unix-keys t)} keys shown, @code{(setq ess-sas-global-pc-keys t)} in parentheses; @ESS{[SAS]} function keys are presented in the next section. Open the file you want to work with @wkbd{C-x C-f foo.sas}. @file{@var{foo}.sas} will be in @ESS{[SAS]} mode. Edit as appropriate, then save and submit the batch @SAS{} job. @example @key{F3} (@key{F8}) @end example The job runs in the @file{*shell*} buffer while you continue to edit @file{@var{foo}.sas}. If @code{ess-sas-submit-method} is @code{'sh}, then the message buffer will display the shell notification when the job is complete. The @code{'sh} setting also allows you to terminate the @SAS{} batch job before it is finished. @example @key{F8} (@key{F3}) @end example Terminating a @SAS{} batch in the @file{*shell*} buffer. @example kill @var{PID} @end example You may want to visit the @file{.log} (whether the job is still running or it is finished) and check for error messages. The @file{.log} will be refreshed and you will be placed in it's buffer. You will be taken to the first error message, if any. @example @key{F5} (@key{F6}) @end example Goto the next error message, if any. @example @key{F5} (@key{F6}) @end example Now, @samp{refresh} the @file{.lst} and go to it's buffer. @example @key{F6} (@key{F7}) @end example If you wish to make changes, go to the @file{.sas} file with. @example @key{F4} (@key{F5}) @end example Make your editing changes and submit again. @example @key{F3} (@key{F8}) @end example @node ESS(SAS)--Function keys for batch processing @section ESS[SAS]--Function keys for batch processing The setup of function keys for @SAS{} batch processing is unavoidably complex, but the usage of function keys is simple. There are five distinct options: Option 1 (default). Function keys in @ESS{[SAS]} are not bound to Elisp commands. This is in accordance with the GNU Elisp Coding Standards (@acronym{GECS}) which do not allow function keys to be bound so that they are available to the user. Options 2-5. Since @acronym{GECS} does not allow function keys to be bound by modes, these keys are often unused. So, @ESS{[SAS]} provides users with the option of binding Elisp commands to these keys. Users who are familiar with @SAS{} will, most likely, want to duplicate the function key capabilities of the @SAS{} Display Manager. There are four options (noted in parentheses). @enumerate a @item @SAS{} Display Manager has different function key definitions for @UNIX{} (2, 4) and Windows (3, 5); @ESS{[SAS]} can use either. @item The @ESS{[SAS]} function key definitions can be active in all buffers (global: 4, 5) or limited (local: 2, 3) only to buffers with files that are associated with @ESS{[SAS]} as specified in your @code{auto-mode-alist}. @end enumerate The distinction between local and global is subtle. If you want the @ESS{[SAS]} definitions to work when you are in the @file{*shell*} buffer or when editing files other than the file extensions that @ESS{[SAS]} recognizes, you will most likely want to use the global definitions. If you want your function keys to understand @SAS{} batch commands when you are editing @SAS{} files, and to behave normally when editing other files, then you will choose the local definitions. The option can be chosen by the person installing @ESS{} for a site or by an individual. @enumerate a @item For a site installation or an individual, place @strong{ONLY ONE} of the following lines in your initialization file prior to a @code{require}/@code{load}. @ESS{[SAS]} function keys are available in @ESS{[SAS]} if you choose either 2 or 3 and in all modes if you choose 4 or 5: @example ;;2; (setq ess-sas-local-unix-keys t) ;;3; (setq ess-sas-local-pc-keys t) ;;4; (setq ess-sas-global-unix-keys t) ;;5; (setq ess-sas-global-pc-keys t) @end example The names @code{-unix-} and @code{-pc-} have nothing to do with the operating system that you are running. Rather, they mimic the definitions that the @SAS{} Display Manager uses by default on those platforms. @item If your site installation has configured the keys contrary to your liking, then you must call the appropriate function. @example (load "ess-site") ;; local-unix-keys (ess-sas-global-pc-keys) @end example @end enumerate Finally, we get to what the function keys actually do. You may recognize some of the nicknames as @SAS{} Display Manager commands (they are in all capitals). @multitable {123456} {123456} {really-really-really-really-really-really-really-really-really-really-long} @item @UNIX{} @tab @PC @tab Nickname @item @key{F2} @tab @key{F2} @tab @samp{refresh} @item @tab @tab revert the current buffer with the file of the same name if the file is newer than the buffer @item @key{F3} @tab @key{F8} @tab @code{SUBMIT} @item @tab @tab save the current @file{.sas} file (which is either the @file{.sas} file in the current buffer or the @file{.sas} file associated with the @file{.lst} or @file{.log} file in the current buffer) and submit the file as a batch @SAS{} job @item @key{F4} @tab @key{F5} @tab @code{PROGRAM} @item @tab @tab switch buffer to @file{.sas} file @item @key{F5} @tab @key{F6} @tab @code{LOG} @item @tab @tab switch buffer to @file{.log} file, @samp{refresh} and goto next error message, if any @item @key{F6} @tab @key{F7} @tab @code{OUTPUT} @item @tab @tab switch buffer to @file{.lst} file and @samp{refresh} @item @key{F7} @tab @key{F4} @tab @samp{filetype-1} @item @tab @tab switch buffer to @samp{filetype-1} (defaults to @file{.txt}) file and @samp{refresh} @item @key{F8} @tab @key{F3} @tab @samp{shell} @item @tab @tab switch buffer to @file{*shell*} @item @key{F9} @tab @key{F9} @tab @code{VIEWTABLE} @item @tab @tab open an interactive @code{PROC FSEDIT} session on the @SAS{} dataset near point @item @key{F10} @tab @key{F10} @tab toggle-log @item @tab @tab toggle @ESS{[SAS]} for @file{.log} files; useful for certain debugging situations @item @key{F11} @tab @key{F11} @tab @samp{filetype-2} @item @tab @tab switch buffer to @samp{filetype-2} (defaults to @file{.dat}) file and @samp{refresh} @item @key{F12} @tab @key{F12} @tab viewgraph @item @tab @tab open a @code{GSASFILE} near point for viewing either in emacs or with an external viewer @item @kbd{C-@key{F1}} @tab @kbd{C-@key{F1}} @tab rtf-portrait @item @tab @tab create an @sc{MS RTF} portrait file from the current buffer with a file extension of @file{.rtf} @item @kbd{C-@key{F2}} @tab @kbd{C-@key{F2}} @tab rtf-landscape @item @tab @tab create an @sc{MS RTF} landscape file from the current buffer with a file extension of @file{.rtf} @item @kbd{C-@key{F3}} @tab @kbd{C-@key{F8}} @tab submit-region @item @tab @tab write region to @file{ess-temp.sas} and submit @item @kbd{C-@key{F5}} @tab @kbd{C-@key{F6}} @tab append-to-log @item @tab @tab append @file{ess-temp.log} to the current @file{.log} file @item @kbd{C-@key{F6}} @tab @kbd{C-@key{F7}} @tab append-to-output @item @tab @tab append @file{ess-temp.lst} to the current @file{.lst} file @item @kbd{C-@key{F9}} @tab @kbd{C-@key{F9}} @tab @code{INSIGHT} @item @tab @tab open an interactive @code{PROC INSIGHT} session on the @SAS{} dataset near point @item @kbd{C-@key{F10}} @tab @kbd{C-@key{F10}} @tab toggle-listing @item @tab @tab toggle @ESS{[SAS]} for @file{.lst} files; useful for toggling read-only @end multitable @code{SUBMIT}, @code{PROGRAM}, @code{LOG} and @code{OUTPUT} need no further explanation since they mimic the @SAS{} Display Manager commands and related function key definitions. However, six other keys have been provided for convenience and are described below. @samp{shell} switches you to the @file{*shell*} buffer where you can interact with your operating system. This is especially helpful if you would like to kill a @SAS{} batch job. You can specify a different buffer name to associate with a @SAS{} batch job (besides @file{*shell*}) with the buffer-local variable @code{ess-sas-shell-buffer}. This allows you to have multiple buffers running @SAS{} batch jobs on multiple local/remote computers that may rely on different methods specified by the buffer-local variable @code{ess-sas-submit-method}. @key{F2} performs the @samp{refresh} operation on the current buffer. @samp{refresh} compares the buffer's last modified date/time with the file's last modified date/time and replaces the buffer with the file if the file is newer. This is the same operation that is automatically performed when @code{LOG}, @code{OUTPUT}, @samp{filetype-1} or @key{F11} are pressed. @samp{filetype-1} switches you to a file with the same file name as your @file{.sas} file, but with a different extension (@file{.txt} by default) and performs @samp{refresh}. You can over-ride the default extension; for example in your @initfile{} file: @example (setq ess-sas-suffix-1 "csv") ; for example @end example @key{F9} will prompt you for the name of a permanent @SAS{} dataset near point to be opened for viewing by @code{PROC FSEDIT}. You can control the @SAS{} batch command-line with @code{ess-sas-data-view-submit-options}. For controlling the @SAS{} batch commands, you have the global variables @code{ess-sas-data-view-libname} and @code{ess-sas-data-view-fsview-command} as well as the buffer-local variable @code{ess-sas-data-view-fsview-statement}. If you have your @SAS{} @code{LIBNAME} defined in @file{~/autoexec.sas}, then the defaults for these variables should be sufficient. Similarly, @wkbd{C-@key{F9}} will prompt you for the name of a permanent @SAS{} dataset near point to be opened for viewing by @code{PROC INSIGHT}. You can control the @SAS{} batch command-line with @code{ess-sas-data-view-submit-options}. For controlling the @SAS{} batch commands, you have the global variables @code{ess-sas-data-view-libname} and @code{ess-sas-data-view-insight-command} as well as the buffer-local variable @code{ess-sas-data-view-insight-statement}. @key{F10} toggles @ESS{[SAS]} mode for @file{.log} files which is off by default (technically, it is @code{SAS-log-mode}, but it looks the same). The syntax highlighting can be helpful in certain debugging situations, but large @file{.log} files may take a long time to highlight. @key{F11} is the same as @samp{filetype-1} except it is @file{.dat} by default. @key{F12} will prompt you for the name of a @code{GSASFILE} near the point in @file{.log} to be opened for viewing either with emacs or with an external viewer. Depending on your version of emacs and the operating system you are using, emacs may support @file{.gif} and @file{.jpg} files internally. You may need to change the following variables for your own situation. @code{ess-sas-graph-view-suffix-regexp} is a regular expression of supported file types defined via file name extensions. @code{ess-sas-graph-view-viewer-default} is the default external viewer for your platform. @code{ess-sas-graph-view-viewer-alist} is an alist of exceptions to the default; i.e. file types and their associated viewers which will be used rather than the default viewer. @example (setq ess-sas-graph-view-suffix-regexp (concat "[.]\\([eE]?[pP][sS]\\|" "[pP][dD][fF]\\|[gG][iI][fF]\\|[jJ][pP][eE]?[gG]\\|" "[tT][iI][fF][fF]?\\)")) ;; default (setq ess-sas-graph-view-viewer-default "kodakimg") ;; Windows default (setq ess-sas-graph-view-viewer-default "sdtimage") ;; Solaris default (setq ess-sas-graph-view-viewer-alist '(("[eE]?[pP][sS]" . "gv") ("[pP][dD][fF]" . "gv")) ;; default w/ gv @end example @wkbd{C-@key{F2}} produces US landscape by default, however, it can produce A4 landscape (first line for "global" key mapping, second for "local"): @example (global-set-key [(control f2)] 'ess-sas-rtf-a4-landscape) (define-key sas-mode-local-map [(control f2)] 'ess-sas-rtf-a4-landscape) @end example @node iESS(SAS)--Interactive SAS processes @section iESS[SAS]--Interactive SAS processes Inferior @ESS{} (@iESS{}) is the method for interfacing with interactive statistical processes (programs). @iESS{[SAS]} is what is needed for interactive @SAS{} programming. @iESS{[SAS]} works best with the @SAS{} command-line option settings @code{"-stdio -linesize 80 -noovp -nosyntaxcheck"} (the default of @code{inferior-SAS-args}). @display @code{-stdio} required to make the redirection of stdio work @code{-linesize 80} keeps output lines from folding on standard terminals @code{-noovp} prevents error messages from printing 3 times @code{-nosyntaxcheck} permits recovery after syntax errors @end display To start up @iESS{[SAS]} mode, use: @example @wkbd{M-x SAS} @end example The @file{*SAS:1.log*} buffer in @code{ESStr} mode corresponds to the file @file{@var{foo}.log} in @SAS{} batch usage and to the @samp{SAS: LOG} window in the @SAS{} Display Manager. All commands submitted to @SAS{}, informative messages, warnings, and errors appear here. The @file{*SAS:1.lst*} buffer in @code{ESSlst} mode corresponds to the file @file{@var{foo}.lst} in @SAS{} batch usage and to the @samp{SAS: OUTPUT} window in the @SAS{} Display Manager. All printed output appears in this window. The @file{*SAS:1*} buffer exists solely as a communications buffer. The user should never use this buffer directly. Files are edited in the @file{@var{foo}.sas} buffer. The @wkbd{C-c C-r} key in @ESS{[SAS]} is the functional equivalent of bringing a file into the @samp{SAS: PROGRAM EDITOR} window followed by @code{SUBMIT}. For example, open the file you want to work with. @example @wkbd{C-x C-f foo.sas} @end example @file{@var{foo}.sas} will be in @ESS{[SAS]} mode. Edit as appropriate, and then start up @SAS{} with the cursor in the @file{@var{foo}.sas} buffer. @example @wkbd{M-x SAS} @end example Four buffers will appear on screen: @multitable {buffer-names} {long-mode-names} {much-much-much-much-longer-description} @item Buffer @tab Mode @tab Description @item @file{@var{foo}.sas} @tab @code{@ESS{[SAS]}} @tab your source file @item @file{*SAS:1*} @tab @code{@iESS{[SAS:1]}} @tab @iESS{} communication buffer @item @file{*SAS:1.log*} @tab @code{Shell ESStr []} @tab @SAS{} log information @item @file{*SAS:1.lst*} @tab @code{Shell ESSlst []} @tab @SAS{} listing information @end multitable If you would prefer each of the four buffers to appear in its own individual frame, you can arrange for that. Place the cursor in the buffer displaying @file{@var{foo}.sas}. Enter the sequence @wkbd{C-c C-w}. The cursor will normally be in buffer @file{@var{foo}.sas}. If not, put it there and @wkbd{C-x b @var{foo}.sas}. Send regions, lines, or the entire file contents to @SAS{} (regions are most useful: a highlighted region will normally begin with the keywords @code{DATA} or @code{PROC} and end with @code{RUN;}), @wkbd{C-c C-r}. Information appears in the log buffer, analysis results in the listing buffer. In case of errors, make the corrections in the @file{@var{foo}.sas} buffer and resubmit with another @wkbd{C-c C-r}. At the end of the session you may save the log and listing buffers with the usual @wkbd{C-x C-s} commands. You will be prompted for a file name. Typically, the names @file{@var{foo}.log} and @file{@var{foo}.lst} will be used. You will almost certainly want to edit the saved files before including them in a report. The files are read-only by default. You can make them writable by the emacs command @wkbd{C-x C-q}. At the end of the session, the input file @file{@var{foo}.sas} will typically have been revised. You can save it. It can be used later as the beginning of another @iESS{[SAS]} session. It can also be used as a batch input file to @SAS{}. The @file{*SAS:1*} buffer is strictly for @ESS{} use. The user should never need to read it or write to it. Refer to the @file{.lst} and @file{.log} buffers for monitoring output! Troubleshooting: @xref{iESS(SAS)--Common problems}. @node iESS(SAS)--Common problems @section iESS[SAS]--Common problems @enumerate @item @iESS{[SAS]} does not work on Windows. In order to run @SAS{} inside an emacs buffer, it is necessary to start @SAS{} with the @code{-stdio} option. @SAS{} does not support the @code{-stdio} option on Windows. @item If @wkbd{M-x SAS} gives errors upon startup, check the following: @itemize @bullet @item you are running Windows: see 1. @item @file{ess-sas-sh-command} (from the @ESS{} @file{etc} directory) needs to be executable; too check, type @wkbd{M-x dired}; if not, fix it as follows, type @kbd{M-:}, then at the minibuffer prompt @wsamp{Eval:}, type @code{(set-file-modes "ess-sas-sh-command" 493)}. @c (solution: @code{chmod ugo+rx ess-sas-sh-command}). @item @code{sas} isn't in your executable path; to verify, type @kbd{M-:} and at the minibuffer prompt @samp{Eval:}, type @code{(executable-find "sas")} @end itemize @item @wkbd{M-x SAS} starts @w{@SAS{} Display} Manager. Probably, the command @code{sas} on your system calls a shell script. In that case you will need to locate the real @code{sas} executable and link to it. You can execute the @UNIX{} command: @example find / -name sas -print @end example Now place a soft link to the real @code{sas} executable in your @code{~/bin} directory, with for example @example cd ~/bin ln -s /usr/local/sas9/sas sas @end example @end enumerate Check your @code{PATH} environment variable to confirm that @code{~/bin} appears before the directory in which the @code{sas} shell script appears. @comment Specify the path to the real @comment @code{sas} executable in @file{ess-sas-sh-command}, i.e.: @comment @example @comment /usr/local/sas9/sas $@@ $stdout 2>$stderr @comment @end example @comment To find the @code{sas} executable, you can execute the @UNIX{} command: @comment @example @comment find / -name sas -print @comment @end example @comment @end enumerate @node ESS(SAS)--Graphics @section ESS[SAS]--Graphics Output from a @SAS{/GRAPH} @code{PROC} can be displayed in a @SAS{/GRAPH} window for @SAS{} batch on Windows or for both @SAS{} batch and interactive with XWindows on @UNIX{}. If you need to create graphics files and view them with @key{F12}, then include the following (either in @file{@var{foo}.sas} or in @file{~/autoexec.sas}): @example filename gsasfile 'graphics.ps'; goptions device=ps gsfname=gsasfile gsfmode=append; @end example @code{PROC PLOT} graphs can be viewed in the listing buffer. You may wish to control the vertical spacing to allow the entire plot to be visible on screen, for example: @example proc plot; plot a*b / vpos=25; run; @end example @node ESS(SAS)--Windows @section ESS[SAS]--Windows @itemize @bullet @item @iESS{[SAS]} does not work on Windows. @xref{iESS(SAS)--Common problems}. @item @ESS{[SAS]} mode for editing @SAS{} language files works very well. @xref{ESS(SAS)--Editing files}. @item There are two execution options for @SAS{} on Windows. You can use batch. @xref{ESS(SAS)--Batch SAS processes}. Or you can mark regions with the mouse and submit the code with `submit-region' or paste them into @SAS{} Display Manager. @end itemize @comment Local Variables: @comment TeX-master: "ess.texi" @comment End: ESS-24.01.1/doc/images/000077500000000000000000000000001455642170100143305ustar00rootroot00000000000000ESS-24.01.1/doc/images/ess_176_176.gif000066400000000000000000000062331455642170100166070ustar00rootroot00000000000000GIF89a°°ç˙˙b˙býf ţgűk˙jűkůpůp&ôs-ţt!ńw-÷v'óy7đ}7ë=ö;ő‚Cé…Mř=ćMě‡H˙9çŠU˙…BďŠQëŤQ˙ŚL˙Mů’Yô”Xó”_ÚšsŮ›y÷—aءíťněťt˙š`é uŐ¦‹Ó¦‘Ď©’˙ iüŁp㪅̱ŁôŞ~ő¬€˙´ȶ«˙µň¶7ö­‡ű·ń¶?ú¶%˙¶ů¶0äąTő¸/Âşłę¸UËąŻţąĺş\Ř»zřş'ëł”îşH÷ş2đ»BŇĽ“ů»3ď»QÚ˝|íµ–ÇżĄĂľĽľŔ˝×ľĆŔ¬ĽÁÄţ´‡ÄÁ˛˙˝-ěżSşÂĘëżZŔÂľ®Ĺ×đľZ·ĂѰÄÝőżF´Ä׫ĆާÇäÂÄŔ¤Éë Ęň©ÉćśËů÷ÂHĚ˙ŞĘçÄÇĂ™Î˙žÍű˙ĂDő˝ťšĎ˙îĹs±Ěä˙˝”éÇs ĎýÇÉĆóÇa˙ľ›ţÇFéČzäČŚůŔ ¦ĐůóČi˘Ń˙ÉËČ˝Íŕőá˙ÉP˙ÉWţĂžËÎĘĄÔ˙őĹ©ŞÓüÄĐŢďČŻŢĚÁËĐÓ°Őř¬Ö˙ĎŃÍďĘ·˙Č©ÇÓáěĐ”®Ř˙×ŃĐŃÓĐóŃëŃ›łŘűţŃkÉŐăÓŐŇţŇróÓ‹¶Űţ»ŰůÝ×Â×ŮŐąŢ˙ŇÚâŐÚÜŮŰŘŔŕţűŐÂÄŕř÷ÚžţÖ˝ëÝ·ţÜŤńÜ·řŮÄĂă˙×ŕčřݦńÜËŢŕÜŘáé÷Ţ­ČäüďÝŇßáŢńŢÓ˙ŕťáäŕŕĺč˙ă¦Íé˙×çűęäăäćă˙ä®˙âÓÓëýćčĺńčÍÚęţüçÂđéÔ÷éÂčęçÜě˙ćëîöęÉúçÜéëč˙ężáíüäíőüéŢëíęţíŔăďţőíćíďëëđó˙ěáîđíýíčĺň˙řďč˙îăđňîţňŃëôü÷óäúóŢňôđőôëóőňíö˙ţőŮýôíúöçô÷óţ÷âţöîđů˙öůőý÷öýůęřú÷öűţ˙ůřůűřüűň÷ý˙űýú˙üűřţ˙ü˙űţ˙ü!ţCreated with GIMP,°°ţ˙ H° Á*\ȰˇĂ‡#JśH±˘Ĺ‹3jÜȱŁÇŹ CŠI˛¤É“(SŞ\ɲĄË—0cĘśIł¦Í›8sęÜÉł§Ďź@ J´¨ŃŁH“*]Ę´©Ó§PŁJťJµŞŐ«XłjÝĘ!=_ťÚTŁ¬ŮłhÓŞ]˶íŮ]]¶Ó䶮ݻx—đŠËpYĽ€ÖËWá.Á»%\řŕ5Ĺ#›eÜŕľ*’3'¦\YŕaÍ sîŚ'´i»Łď;ÍşmęÂëZËNűšď¸Ů¸ËÖŽű.7îÝq˙úf Ľ« á­‹ső…śřŢÎó o®Y9×ĎliA½»÷ďŕĂţ‹OI”çĐzÉţä‘1mđăËźOżľýűřµÉKO޵AÂßOĺđ ˇ ř:JřŚ‚>ᣇZ6Ř";„¬`Ŕ‡ †(â$–h≠Ţ1+6¨ĺÉGÜ0Š4ÖhŁŤ  Ô1:¨ŐGG‘păD™#Q塖ůht‡‡EF)Ą‰G%ĎjaF«@9ĺ—`VYÔZtŹ`¦ůĄEMBˇ…ɡćśQ˛Y”+-¦őâDĐéçŤvuŚiýŃ=^ţ©h‰ „Ě/F*餔VjéĄ^ŠÍ?I.ŮäCĐ,**Ł:t ¨¦Şęެ¶ęę«ţ°ľÚ5˙ÔcE–[:D̨Ľ†Řč?ýđë°ÄK,ś G™ qÓëłżţóŤ±ÔVk,ŹäfZ6tŹĎŽí?™Xkîą«šńGAxşŘĐáŠ[jAöî˝ÖšQ‡AúČ!ńŠ:î?ŔĆ'¬đ ?!ĹĂR\Á]„AF±bÔiZL*4+:đ?KĘEűŕSŹ;âDĂ‹)ŚpF¬R T¸*tŠ „€B @-ôĐDmôŃHË0ŻAä\›HÝ”RĆ«Wŕ“вiáđ B÷L`âí˝—ßŘd—=ß~ ťb, "áCŠ˝¬^6Bۢe, ±s@ţ‰xT?lkF/#Q·Ş\śł‹j]’P5 HŔ"IMclV‹důŞ\ĂPżiŮ‘8hŔ+I5bě&$˛ę´2´1Z„O 3Š8Ŕ!HĹsí6#ŮłŞĆ8tsÎ)˛Ô€Ô©ĹĆA’Ú©‚±tBy0{Đ,(Â=Fkl,#5ťj´D„ÉZx#”M$FŔŽQÓ;ĆÜ •Ś*ú±‚Că ™GHÄ€jĹuĹJÄH`‘Ş1b"Ę ZD—uD±Gŕeg LÖDС$Ž}ę DČ]vWd+ ™ű>R…­Š/-ZJňFÔĽ˘čŹXţ' ‰ţĚŕ·Šd/kËH÷Ľ>ˇ¨ăZŠÉ'PĄ/ڬO-í;8ŕ7"ů %k I<6Á…+¨!#ţ BH@Ątá@"qŘQ#T bÁťN( , TBڝР) R®b±î'řŔsu2AŃ`±Č< -8HFBtŃ˝} ‰>)Xô„rĹ´dŃ [Śßü|ŇŹ«BqĹ˙Ňâ¸5pD €ĆOĚG¬1¸C(y ťBú(˘?úÄR PHč©„AŠä]Oô±Áaup(‘DŢA ±Ľ“=qˇ c”OžĹID)ItĘž¨®XAţJ+ѢŠŃ9€DĄN|·É(E—z<$AŘLaîŚĹb[Q”‘'´ˇLÔ‡ €ŠťŹs$J'ÖÂtX›"@ vR?ba®(m`KŘYrňđ;ć°™|Ľă§@ ŞP‡JÔ˘ő¨Ň„[ô yš•6Ńä±:‰VP48(ž?*P›¨’XŇKUŻŞ(ěĂcżQ0sbKX}!}U%«fŠŔ †”@Łp¦M «iő c•kdl`‰†\sDŘN ú*2Háblf¨ŕ›2§6¬®P‡łFV˛‘iB=âTŐł&›kŐ˛`и‚2QxţšCŔńĎÔ&÷\Őžđ×Ďľ61O8ćCćˇ!Ŕˇ3iiŞĚ .$°ż Ě ˛0‘ŕ•Ł3é‡#âVšş6şB¶&rŘ”*6& \U˛ŕą†@ĽvÁÁ®×Ëšł.Imçű÷Â×-HPg)RÚyŞ)‰GUĹÜÂö÷żwBşÚru%ý «¸ ď*Äż¶x«âą'žŞŔđ„ö>8ÄkńÄPWŽXwDččI”‹*ÇÂ" Ż p@ YĹh=”†Hn0‰=ü.)ŚW"´h–·Ěĺ.{ů bPC!Da o Qţş*Ĺ «aÉj.Ę"xC$ż`ŐÁ´g° DHřÚc)ü¸Ď ±€‰"€ŕŚčĘ ľBÂnXúŇδ¦7ÍéNwş«ŕŠZŕ‘)ľN ÂĘBć'#ęTŐÁj”UłšN#đEŤÇBV(¶ľµš@k‹Ô2nĐµŞ…=§T"#éUŐÄ Űˇ›Ů`úFšˇgĺÚŘž’ ŕ<Wů×,Á†ÖMމ€;ÜQ’Aµ%’aîšů$¦6\üwĂ{HpBŞ%˘âTi˝/!fÎ(˙ŰF .ExچÝŇß©âşűýp)ŕĘ™r•ţťŰľJ!îîx‘ŕ„‹+ÄÔë.L4ŚŞ1dáŢ q¸ĘKx"y^ţ’b¨J ‡ÎwÎĽLx"·8L}—'déL˙Fŕí<şĘI_ 9 Ýă'ŕOéY7‘$ SćďđK¦ŃMTa]Á:Ľ`€P =H2ą!btˇ?Â-QÜ3~h,ůńŹ|Ç\ćŠđÚÇ,±2żÜ÷ůŘ‘f„>úAúŇ›ţô¨O=ęőaŹx¨Ř@Ć->AvW-ŃÔ×ń>s{÷Ŕ/ÖÉăLĐŕ˙U6Ç9_´{üć· éqŽ¶ó§Ź†ŞC(Ôź>Ět® ‘gúwWP˝ż?ý+4ľ3'żńÍŕyţP\ýŔż=Ľ˙ă÷~@řPCä÷ĎţÇŃ€8€X€x€€ ¸€ Ř€ř€8Xx¸Řř ‚"8‚$X‚&x‚(‚;ESS-24.01.1/doc/images/ess_32_32.ico000066400000000000000000000042761455642170100164370ustar00rootroot00000000000000 ¨( @b˙b˙kűMćUŠç´˙7¶ň/¸ő”łëÄÁĽĘÂşŃĂ·ŔÄÂëɤůËś˙ĚűÍžzČéüÓŞ‹Óóţ۶ÂŐű·Ýë­Ţ÷üäȦă˙ĺčćëďíüôëŢóúňőó÷úřřů˙řűůü˙ţ""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" """"""""""""""""""""""""""""""""""""""""""""""""""""""""" """"""""" """""""""""""""""""""""""""""""""""""""""""""""""""""""""" """"""""""""" """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""!"""""""""""""""""""""""""""""""""""""""""""""""" """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""ESS-24.01.1/doc/images/icons/000077500000000000000000000000001455642170100154435ustar00rootroot00000000000000ESS-24.01.1/doc/images/icons/icon_external.png000066400000000000000000000003401455642170100210000ustar00rootroot00000000000000‰PNG  IHDRÔşS PLTEp)A}ĎŐäÔÔÔ7z˙˙˙w˘¨~ĹKtRNS@ćŘfbKGDH pHYs  šśtIMEÚ;%ËÔDIDAT×c`Ŕ\\X\\BĂD€thhh#66VQÓF®ˇ`Z%¨–%ŘČB«‡€č g Ô¦]€€'¸ě ¸ľřIEND®B`‚ESS-24.01.1/doc/images/icons/icon_mailto.png000066400000000000000000000006071455642170100204510ustar00rootroot00000000000000‰PNG  IHDRJľ“PLTEHÁďšÉôřZ8üýţúüţq±ëţţ˙q˛ěŘčůđ÷ýđöü×čůÝëúâîúËá÷łłłčńűÄŢöŇĺů÷M"óřýŇĺřÇß÷ŘéůéńűĽŮőĺđűăîűíôüîöýův^ŕíúÁÜöÜëůěôüöúýÎăř÷úýćđűÇßöôřýĺđüaaa```›Ęô˛˛˛˙˙˙q˛ë(z¤FtRNS@ćŘfbKGDH pHYs  šśtIMEÚ3$łŁămIDAT×c` 耀č0čé‹— Ź.”ËÎ*Ş,-Ϭ« ä0˛±Č©ó2‹0ieYT¸%$TĹÁŠ9 8e8…5Á\vVMY-%1~!)^]`a WGGG[Dhi XëĎ‚bńIEND®B`‚ESS-24.01.1/doc/images/logoESS.gif000066400000000000000000000062771455642170100163460ustar00rootroot00000000000000GIF89aŔ˝ç˙˙b˙býf ţgűk˙jűkůpůp&ôs-ţt!ńw-÷v'óy7đ}7ë=ö;ő‚Cé…Mř=ćMě‡H˙9çŠU˙…BďŠQëŤQ˙ŚL˙Mů’Yô”Xó”_ÚšsŮ›y÷—aءíťněťt˙š`é uŐ¦‹Ó¦‘Ď©’˙ iüŁp㪅̱ŁôŞ~ő¬€˙´ȶ«˙µň¶7ö­‡ű·ń¶?ú¶%˙¶ů¶0äąTő¸/Âşłę¸UËąŻţąĺş\Ř»zřş'ëł”îşH÷ş2đ»BŇĽ“ů»3ď»QÚ˝|íµ–ÇżĄĂľĽľŔ˝×ľĆŔ¬ĽÁÄţ´‡ÄÁ˛˙˝-ěżSşÂĘëżZŔÂľ®Ĺ×đľZ·ĂѰÄÝőżF´Ä׫ĆާÇäÂÄŔ¤Éë Ęň©ÉćśËů÷ÂHĚ˙ŞĘçÄÇĂ™Î˙žÍű˙ĂDő˝ťšĎ˙îĹs±Ěä˙˝”éÇs ĎýÇÉĆóÇa˙ľ›ţÇFéČzäČŚůŔ ¦ĐůóČi˘Ń˙ÉËČ˝Íŕőá˙ÉP˙ÉWţĂžËÎĘĄÔ˙őĹ©ŞÓüÄĐŢďČŻŢĚÁËĐÓ°Őř¬Ö˙ĎŃÍďĘ·˙Č©ÇÓáěĐ”®Ř˙×ŃĐŃÓĐóŃëŃ›łŘűţŃkÉŐăÓŐŇţŇróÓ‹¶Űţ»ŰůÝ×Â×ŮŐąŢ˙ŇÚâŐÚÜŮŰŘŔŕţűŐÂÄŕř÷ÚžţÖ˝ëÝ·ţÜŤńÜ·řŮÄĂă˙×ŕčřݦńÜËŢŕÜŘáé÷Ţ­ČäüďÝŇßáŢńŢÓ˙ŕťáäŕŕĺč˙ă¦Íé˙×çűęäăäćă˙ä®˙âÓÓëýćčĺńčÍÚęţüçÂđéÔ÷éÂčęçÜě˙ćëîöęÉúçÜéëč˙ężáíüäíőüéŢëíęţíŔăďţőíćíďëëđó˙ěáîđíýíčĺň˙řďč˙îăđňîţňŃëôü÷óäúóŢňôđőôëóőňíö˙ţőŮýôíúöçô÷óţ÷âţöîđů˙öůőý÷öýůęřú÷öűţ˙ůřůűřüűň÷ý˙űýú˙üűřţ˙ü˙űţ˙ü!ţCreated with GIMP,Ŕ˝@ţ˙ H° Á*\ȰˇĂ‡#JśH±˘Ĺ‹3jÜȱŁÇŹ CŠůžŻNmމÁ˛ĄË—0cĘśIÓĺ.’8s"ÜWł§Ďź@a.ᥳ¨Ń]5iA´©Ó§PŁJťJI˘FłjýWîHL/ů4Ţ  ¬ŮłhÓŞ]˶­[ °ZěÇŤÝ»xóęÝË·Ż_ľd8 „Ç3‡ÜŢ*^̸1\ąű±ů{×LŻ‘ÔĚčĺrn!+1/%¬Ć@-E[S´7™23ÎDb»;FđDt^a‚MHd@Ú‡Tkeí ™mÂ%ć)ś,ˇ.j?ÜKN2^qăť©Ot…#¦ť°çţePËšvŹä\‡yb,a« đăÇ·a©!iě9_qšŢ1O@¶Đ{ňh`LH¨±ŹEĎ©ĺÁtü ”^^dHAK„Bd[@¨S~(Ĺ#É‘Să]dzĐ=°µŔŹŁÍ˙  HŔđ€Úř‘G ö.’¸ë._ C^Ą›X-ÝYŘ·‹g ‰Óě¸=[ˇIxČ®pŤĐ5¤ÉÍ:‹ ë%8X†±…eEj6ţĹIüŇt® ňFfá źšvťZ´‰;)äy*¦'d\GoşˇKl C„ -Ă]Šc™8uB&<@Gşň±5RuŃ­ĽĺŤä°2/_ĂĂŘD3ňŐĚÁČ ,ô’ËőÍĚ—łűANt•-dAÂy™ŮІL›9 #ů…^ŔđĚä/QR5k€dˇ!ůf^Ŕđt¦F·ä¤ %B‹PŮóžřţ ! c|ň#ÍŘž@×64XMhqzÂŃyPˇĄĚ4 JŃŠZô˘ͨF7ĘŃŽzôŁ ©HGJŇ’šô¤(M©JWĘŇ–şôĄ0Ť©LgJÓ‰´C˘4”čT'ąśęÔr‡ŰG|ş°ťBD-*P ·Ž¤*Ő ďpꡌŠ8AH5PK-\>wUůPr^ řç?šő¬h`C Z&5ý>ôŘB$ě Ä , €eśŤą¤Žˇôˇ#‘(`5eľ=Éc 11‚90˛Šż.6SŤÔ$ęzWŠČᲵʬ˘ŽáV6"÷°,h‡$Z03˘°˝ţK#ČT+Dv˛!Ćj7ŐZ<4¶%%˙±Yص!÷PěnY›Ő‡ŘC3Ŕ…¨ę`Ň–!„X.s9ňBĘÄĐ"űŔG=Ü!ŽhđÂŚŕBţ"„Ô ·UČÜŇ€  řÍŻ~÷Ëßţú÷ż–As#â«â@+$ř tór…µ¤¸/±,ÂŽ¬ĺ5 —ŠS†zdĂxá4b]Ř!!਀Z đЏYgˇČ‰=š™0†Ľ7ľQÄ,Ď€ mŚĹ‰ĹH‚VÂ`B&FH6 –°#\¤LąD2L»ŚAfQFi_râ„`Ĺ-Ž”čáŤčGĂŤČţŤa"Ů„č8-=Ž”:®C†ě|ä–ÓĹČ‘c’ä€Éiq˛˘ú"×”$ň‡˘5˘eď(äËia±˘˛×@5áľlĆíAŢŚ–Ŕ`PotM×´gôŮ nň“ő„>żŚa—kj´‰ f=éŁ5”Ť›.Ťă@bÇfń´žC8•ú%Ş@±ÔUŰÉYŽ“2(ő#´ĂËŞ-‹Pq§ßţĄĂpjĂLŠPfüÎ/°q\s…„˛«@ÁAŤýĽě´4»NÝőËćIwĂű'EČ™BJmHzNĐîKĚÜýďQÁ!çîtşĺbbfÁÎl¸|˘`L†€ŁŢhą7śţĽýźRăđą6%r‚‚oŰMUĆKşyr”˙ŞHÄyőn €`’hŔ#‰'° ‘Űăž- řşGây.Ŕ>9›Dò{…˙řťV‚DâűśG“ÁŔ7Čő±ŚŔô!aľ]:Y}śL×v÷ÄIţň AJĆúŹ´:c[aČ ~•ńµGQ]°5|őb [Ó×~†sQW~Óu[ňWQM· ehP‚Ĺ€q•‚*¸‚,Ř‚.ř‚0284X6x8:¸<Ř>ř@„;ESS-24.01.1/doc/images/skyline.jpg000066400000000000000000000114431455642170100165130ustar00rootroot00000000000000˙Ř˙ŕJFIFHH˙ţCreated with GIMP˙ŰC  !"$"$˙ŰC˙Ŕ˝Ŕ"˙Ä˙ÄM  Qa!1ATU“Ń"q‘’”ˇ±Ň#2BRSÁb˘Óđ5st˛á$%346Vdr‚˙Ä˙Ä<1!AQSa‘’ˇŃá2qđ"˘ÁâBcd±ńCD˙Ú ?ý”‹ĺzĘöE¤‘Á¬`.q<€! ”ëŮY1%}Ρâ)¤‚”™–c[˛ă*’Nd’v¬ _O`ŽBŘb/y6żZ8z;#š Ź±ákţˇmȱQ~đ§ü˙µu÷oůľ«oE"}ŕ˙Oů˙j{·üßU·˘Ä>đ§ü˙µ=Űţo‡ŞŰŃcvg˝—ZW1Îk„­Č‘ă["Ö`Ö·ŇčhŘÚ׾ŕx*ź űšW¸ľVóDDWŠ˝ęÔYë Ź2ů {Z5’ÓŔ»|K–70äE»WÓXŕáąb®Ç J&’ămf›KĄ„q´ň–ë?ˇ…*-p\żŢ° "{tZç ò5/—’–¸RŐ;@śFĂŔýe˝o™6Zs4#HŤŰţżĘ‡E®˛Íf{ö[é× Á ­{w’ŃŃ´˝XZź»÷ý—÷*Źy/ÇŃdµţňZ:6—« ĺSk°ŇÓľ˘¦ŽŠcn“Ţö†µŁY%~řýŔ\Ôďî_٤w6xú,•ŠăŹ·;¤™ŃĹBúĚŽZPRŤâ-\›ĺ`ű~»ŮbůŐcş3BÓcZŢďîVě“x¸¤wo˘âµiŇ˙zߊŮVPÍÓ0ŰxsN`Šh¸®»÷äĂÂńÔÇüĹŞčűđü"Dj®o•·×ÁTbX^'[ ŮÜ,-Ĺił}ů0Ç0Ľu1˙17äĂÂńÔÇüĹ}ŻpîhUţîâ|’´„Yľüc^:˙›ňaŽaxęcţbkÜ;šÝÜO’VŠâ: Ok7 {'daĺ…“45ŔŹ!#ަUśr6V°Ü•L±>Ţ,FÂsÖÖŇŃ5®Şť‡š]Ęşę‚;•şJWä ±ß…îц—ü—éť×Ëż¶ŽŇťý´t„•šTC%<ď‚V–ČǸB˘ľDD\8ŞcŠJ ´BÓ»űhé=)ßŰGHAéTú<+_WKL4NŽFé4é»ĺ__nżźEë»ĺPŚ#aöz)bjĂü·ŐZűűhé=)ßŰGHAéUOnżźEë»ĺ^ŻÂfŚĂ©ź±˛Ô ‚„˙Ř{=ÍX?€}umďíŁ¤ ôŞĆ$µZîÓěŐP}5Ů—BB]ŁSľ*áj¸[ĆutŻŤĽZ\ľ‘ŔĽXťˇ{ˇ?ů Ä KŁ´8…#›!Ň$e°őp+ę“ަ¨m…Ť×FÄUVYŤ[$}(qŤĂĆňĺźÁhÔ•0UÓ˛˘šVËĆmsyT>(Ăt÷xĚŃhĂX‹&\ŘîŐIµÜ®xfäř%ŤÁˇß[϶úŹzóX+*ú9 §«»ŕ? ··¨ůvp[!‡i’Ă Ěqú˙kTXÇí z©ú}‚'ą”âQ0í¸¸†äŃ'ϱkv›•%ŇTŇI¤Ţ'4ý¦D,łö„°Ď!ŁÄPF_lú=FCě ÉcŽĚÜF~Mjó¤:|-ϧ7ĆăxßëÔľú,#Źcg;m~6ŮéÖ±ä^ZŇç´fIČp¦ÜÓÔ@ÉŁˇŹAă1Ą %ć”Ô5Wö,.¶v^łUSQŰŰČ|®U9×zě_̢ëBo]‹ů”]hRµ&!Éwb‡ŻđÎ{{U)×zě_̢ëBo]‹ů”]hMIr]Řš˙ ç·µR‘]w®ĹüĘ.´&őŘż™EÖ„Ô‡%݉ŻđÎ{{V‰¸ý!7ř‚´uKÜŠĹrĂřzZ+ś")LĹŔWEę\nŽŽ&A#ŔTžş:×rl®'¸?Ĺ”l×ĺ GZľ‹X+ˇnPÎ|p>ë˙׏ҫkX×2®˘łNkéĄë _kšć‡4‚Ň3r…ĺU°%×»Ó›lÎúȆqxŰ«Íđň+4ҡ|®†4¸ĺ±e*#0<µŰ–’ĚnőáŐŻšÖz­ů“Ă«_5¬ő[ó,÷Ľ¸WŢY2}ŹŰ©Ţśů2ü!Šoó-şľžSL•Mś§ń3Q÷ć#SŔé_0´ÖH^ú‡»Śe÷N̸˝”–<Á¶ÜWCŁP±·(*Z›2Ę'aűf#¶:‚ç›8Řöđ>7kiä?‚ßě‹sĽA]4ď Ň˙g«Śx’ÂáŻ[OżŤ~\·K}Ň‚Z…;*)ĺ=ʰíKľ+G\Ť:2 ś?_­Šf ŽÉ‡ĆśNͧôú±UŤÎńÝ*¦IˇKtcs’ź>ës5ŤścŢ®+óÎč8*á+ŁşŰj%uuĆv»)!wËÜGą_74Ý. Çq´ßŘ.G&G6Y2sČ?uÇWäÔˇaŘÓŰ/ŘëĆŚ#ąŢľÁOĹpß۰ăĄĚoo ícjŇ‘i–IF(»¶ŐBK52pDÝ_˝ćRŐPŃRIS;´c`ĚíŘ6¬Ňľ¦ŞőuÓŃ.’WhÇäOˇ¦#ţćˇVTŔc>"˝ě–éď.ĺ¤íôćđä9|ĺitđĹO …‘±ˇ­.,?kŽŐ@Ř“ĄwŤ+˙»ŠĺWRj$ŇÝąu¦§2Ű÷˘"(ŞB"/€3<yEźŢk_yÄĐĂK#„m‘±Ä杼.ţµ%"x : ť¤_ä¸Ă0–äd ľkĘË7kĹ7ě?s·Ăh¸:•’Âç<ŘěČv_x©¬OöŚţŮ´˙‡ů–k¤’É÷Ćâ ĆĐls QŃXc›c%hp±ŘEĆGЬo“ŤşqţĎĘ›äănśłĹňŞ’/4ÖuĽçwŹšő}SAČgty+nů8ۧěń|©ľN6éÇű<_*©"k:Ţs»ÇÍ5M!ťŃä­»äănśłĹň¦ů8ۧěń|ޤ‰¬ëyÎď4Ő4†wG’šżâĽC~§e=Úç-L,vf‹ZÜőäĐ3ó¨PH ‚A „^ôđË<͆9ň<äÖÂTgÉ,ď»ÉsŹĄJŽ(iăŃcCZ8Xú[rűÔ×ÜGYRâú† ®¤Źž2GţÎŕěŐůW°/p˛÷r2uCËżůŕOťXVr˛_k3śŻ©cöq5¨«ŘłŮ1ĺYí±MŘp^˛Č%˘ otO“Ć*Ä‹¤T4°»J8ÚPr›«ťş2ĘçÄ˙’Ą(hąęhhŞ^SIO3€Č:HøWB"..ôÚş2‹¨obw¦ŐŃ”]C{j"..ôÚş2‹¨obw¦ŐŃ”]C{j"..ôÚş2‹¨obw¦ŐŃ”]C{j"..ôÚş2‹¨obw¦ŐŃ”]C{j"/XŁdQ¶8ŘÖ1Ł&µŁ Ŕ˝‘˙ŮESS-24.01.1/doc/info/000077500000000000000000000000001455642170100140165ustar00rootroot00000000000000ESS-24.01.1/doc/info/dir000066400000000000000000000011651455642170100145220ustar00rootroot00000000000000This is the file .../info/dir, which contains the topmost node of the Info hierarchy, called (dir)Top. The first time you invoke Info you start off looking at this node.  File: dir, Node: Top, This is the top of the INFO tree This (the Directory node) gives a menu of major topics. Typing "q" exits, "?" lists all Info commands, "d" returns here, "h" gives a primer for first-timers, "mEmacs" visits the Emacs manual, etc. In Emacs, you can click mouse button 2 on a menu item or cross reference to select it. * Menu: Emacs * ESS: (ess). Emacs Speaks Statistics (S/S+/R, SAS, BUGS, Stata, XLisp-Stat). ESS-24.01.1/doc/installation.texi000066400000000000000000000102201455642170100164520ustar00rootroot00000000000000@include requires.texi There are two main methods used for installing ESS. You may install from a third-party repository or from source code. Once you install it, you must also activate or load ESS in each Emacs session, though installation from a third-party repository likely takes care of that for you. See @ref{Activating and Loading ESS} for more details. @menu * Installing from a third-party repository:: * Installing from source:: * Activating and Loading ESS:: * Check Installation:: @end menu @node Installing from a third-party repository, Installing from source @section Installing from a third-party repository ESS is packaged by many third party repositories. Many GNU/Linux distributions package it, usually with the name ``emacs-ess'' or similar. ESS is also available through Milkypostman’s Emacs Lisp Package Archive (MELPA), a popular repository for Emacs packages. Instructions on how to do so are found on @uref{https://melpa.org/, MELPA's website}. MELPA also hosts MELPA-stable with stable ESS builds. You may choose between MELPA with the latest and greatest features (and bugs) or MELPA-stable, which may lag a bit behind but should be more stable. After installing, users should make sure ESS is activated or loaded in each Emacs session. See @ref{Activating and Loading ESS}. Depending on install method, this may be taken care of automatically. @node Installing from source, Activating and Loading ESS, Installing from a third-party repository @section Installing from source Stable versions of ESS are available at the @uref{https://ess.r-project.org, ESS web page} as a .tgz file or .zip file. ESS releases are GPG-signed, you should check the signature by downloading the accompanying @code{.sig} file and doing: @example gpg --verify ess-18.10.tgz.sig @end example Alternatively, you may download the git repository. ESS is currently hosted on GitHub: @uref{https://github.com/emacs-ess/ESS}. @code{git clone https://github.com/emacs-ess/ESS.git} will download it to a new directory @code{ESS} in the current working directory. We will refer to the location of the ESS source files as @file{/path/to/ESS/} hereafter. After installing, users should make sure they activate or load ESS in each Emacs session, see @ref{Activating and Loading ESS} Optionally, compile Elisp files, build the documentation, and the autoloads: @example cd /path/to/ESS/ make @end example Without this step the documentation, reference card, and autoloads will not be available. Uncompiled ESS will also run slower. Optionally, you may make ESS available to all users of a machine by installing it site-wide. To do so, run @code{make install}. You might need administrative privileges: @example make install @end example The files are installed into @code{/usr/share/emacs} directory. For this step to run correctly on macOS, you will need to adjust the @file{PREFIX} path in @file{Makeconf}. The necessary code and instructions are commented in that file. @node Activating and Loading ESS, Check Installation, Installing from source @section Activating and Loading ESS After installing ESS, you must activate or load it each Emacs session. ESS can be autoloaded, and if you used a third-party repository (such as your Linux distribution or MELPA) to install, you can likely skip this section and proceed directly to @ref{Check Installation} Otherwise, you may need to add the path to ESS to @code{load-path} with: @example (add-to-list 'load-path "/path/to/ESS/lisp") @end example You then need to decide whether to take advantage of deferred loading (which will result in a faster Emacs startup time) or require ESS when Emacs is loaded. To autoload ESS when needed (note that if installed from source, you must have run @code{make}): @example (load "ess-autoloads") @end example To require ESS on startup, you can either put @example (require 'ess-site) @end example or @example (require 'ess-r-mode) @end example In your configuration file, depending on whether you want all ESS features or only R related features. @node Check Installation, , Activating and Loading ESS @section Check Installation Restart Emacs and check that ESS was loaded from a correct location with @code{M-x ess-version}. ESS-24.01.1/doc/license.texi000066400000000000000000000011371455642170100154020ustar00rootroot00000000000000@comment ESS is free software; you can redistribute it and/or modify it under The source and documentation of ESS is free software. You can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. ESS 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 in the file COPYING in the same directory as this file for more details. ESS-24.01.1/doc/mailing.texi000066400000000000000000000011451455642170100153770ustar00rootroot00000000000000 There is a mailing list for discussions and announcements relating to ESS. Join the list by sending an e-mail with "subscribe ess-help" (or "help") in the body to @email{ess-help-request@@r-project.org}; contributions to the list may be mailed to @email{ess-help@@r-project.org}. Rest assured, this is a fairly low-volume mailing list. The purposes of the mailing list include @itemize @item helping users of ESS to get along with it. @item discussing aspects of using ESS. @item suggestions for improvements. @item announcements of new releases of ESS. @item posting small patches to ESS. @end itemize ESS-24.01.1/doc/newfeat.texi000066400000000000000000000624631455642170100154220ustar00rootroot00000000000000@comment @itemize @w{} @comment @item Changes and New Features in 24.01.1: @itemize @bullet @item Revert a bug introduced with the @code{ess-request-a-process} change @end itemize Changes and New Features in 24.01.0: @itemize @bullet @item fix docstring warnings in ess-custom @item :package-version is now set to "VERSION" in ess-custom. By make this is replaced with "24.01.0" (or similar). @item Better ``collaboration'' with org-mode Now @code{ess-request-a-process} obeys @code{ess-gen-proc-buffer-name-function}, thanks to Ihor Radchenko. @end itemize Changes and New Features in 19.04 (unreleased): @itemize @bullet @item ESS[R]: When a background command is interrupted with C-g, ESS now asks the user if they want to disable background evaluations altogether. This is a resiliency measure against cases where background evals cause cascading errors or hangs. @item ESS[R]: Background commands now propagate errors to Emacs. @item ESS[R]: Background commands can now be disabled by process instad of globally. For instance when a process has failed to initialize properly, background evals are disabled for that particular process to avoid cascading errors. Other processes may still use background commands. @item ESS[R]: ESSR commands are now more robust when ESSR is not in scope. This can happen when using @code{browser()} in an environment that doesn't inherit from the search path. @item ESS[R]: Unexpected exits are now detected during startup. In that case an error is thrown with advice about how to recover. @item ESS[R]: @code{options(width = )} is now set on startup based on the width of the inferior window. @item ESS[R]: Add support for R projects and start R by default in the project folder. @item ESS[R]: Backticked symbols in the process buffer are no longer fontified as strings. @item ESS[R]: @code{ess-command} now runs R code in a sandboxed environment. Use @code{.ess.environment()} to inspect the current environment. @item ESS[R]: Added support for new syntax in R 4.0 and R 4.1. This concerns raw strings, lambda functions, and the pipe operator. @item ESS[R]: Highlight error locations in rlang style backtraces @item ESS[R]: Fixed issue that caused ESS-help to hang when usage blocks include R comments (#1025). Fix contributed by Bill Evans. @item ESS: New @code{ess-elisp-trace-mode} minor mode. Toggle it to start or stop tracing all @code{ess}-prefixed functions with @code{trace-function}. Tracing is useful for debugging background ESS behaviour. @item ESS[R]: @code{ess-get-help-aliases-list} now caches the aliases on the R side. This should speed up help lookup when the search path has changed and the aliases are read again. @item ESS: @code{ess-command} now uses a default timeout of 30 seconds. It should normally be avoided with long-running tasks because it causes Emacs to block while the command is running. If the timeout is reached, an error is thrown. An interrupt is also sent to the process in case of early exit. This is a behaviour change: you will now have to explicitly opt in blocking the whole Emacs UI for more than 30 seconds by supplying a larger timeout (use @code{most-positive-fixnum} for infinity). @item ESS: @code{ess-wait-for-process} now returns nil if a timeout is reached. @item ESS: @code{ess-get-words-from-vector} gains a @code{timeout} argument. @item ESS[R]: Fixed performance issue with argument completions. The help summary for the argument is no longer displayed in the echo area. This fixes delays and hangs (#1062). @item ESS[R]: @code{ess-command} is now more robust and resilient to hangs and custom prompts (#1043). It also strips continuation prompts (@code{+} prompts) automatically and reliably (#1116). @item ESS[R]: @code{ess-command} now handles sinked consoles correctly. @item ESS[R]: @code{ess-command} no longer changes @code{.Last.value}. As a result, background tasks like completions no longer affect the last value binding (#1058). @item ESS[R]: Namespaced evaluation is disable in roxygen examples (#1026). Part of this change is that namespaced evaluation has become a buffer-local rather than process-local setting (#1046). This makes it possible to disable namespaced evaluation in specific buffers or contexts. @item iESS: Inferior processes can now properly reuse frames (#987). Fixed issue that caused the current buffer to be incorrectly displayed in the new frame when @code{display-buffer} is set to pop up frames. @item ESS[R]: Better support for tramp. Fixed package evaluation on remote servers with Tramp (#950); process reloading (#1001); and an evaluation issue (#1024). These fixes were contributed by David Pritchard. @item ESS[R]: Automatic offsetting of R process output is now disabled by default because it produces undesirable output in some situations. To re-enable, set @code{inferior-ess-fix-misaligned-output} to t. @item ESS[R]: Improved @code{xref} lookup (@kbd{M-.}). Function locations are now always detected for package libraries listed in @code{ess-r-package-library-paths}. @item ESS[R]: Evaluated lines starting with the Roxygen prefix are now always stripped from the prefix, so they can be sent to the process easily. Previously, this was only the case inside the @code{examples} field. Since roxygen is switching to R markdown, it becomes useful to evaluate chunks of R outside examples. @item stata support is now obsolete since we were unable to elicit FSF paperwork from some of the original authors: see the lisp/obsolete sub-directory on the ESS github repo @item @code{ess-set-working-directory} no longer changes the active directory (as defined by the buffer-local variable @code{default-directory}) of the buffer where the command is called. Instead, the active directory of the inferior buffer is updated to the new working directory. @item The default of ess-eval-visibly is now @code{'nowait}. With this change you should no longer experience freezes while evaluating code. @item ESS[R]: There is a new menu entry for reloading the R process. It is otherwise bound to @code{C-c C-e C-r}. Reloading now reuses the same process name and start arguments that were used to start the process. @item iESS: Process runners now return the inferior buffer. Note that callers of inferior runners should not assume that the current buffer has been set to the inferior buffer. Instead, use @code{with-current-buffer} with the return value of the inferior. @item iESS[SAS]: The SAS keymap was only set in iESS buffers called `*SAS*`. This is now fixed. @item ESS[R]: Fixed longstanding indentation issues involving @code{::} and @code{:::} operators. @item Implement a more reliable check for the process busy state. Background actions such as completion and directory synchronization should not block the process and should not cause printing of the extraneous output to the interpreter. @item Activate @code{goto-address-mode} for url and email highlighting in inferior buffers. @item @code{smart-underscore} and @code{ess-smart-S-assign-key} have been removed. Users who liked the previous behavior (i.e. underscore inserting ``<-'') should bind @code{ess-insert-assign} to the underscore in their Emacs initialization file. For example, @code{(define-key ess-r-mode-map "_" #'ess-insert-assign)} and @code{(define-key inferior-ess-r-mode-map "_" #'ess-insert-assign)} will activate it in all ESS R buffers. @item ESS major modes are now defined using 'define-derived-mode'. This makes ESS major modes respect modern conventions such as having -mode-hook and -mode-map. Users are encouraged to place customizations under the appropriate mode. @item New option ess-auto-width controls setting the width option on window changes. Users can change it to 'frame, 'window, or an integer. See the documentation for details. @code{ess-auto-width-visible} controls visibility. @item ESS now respects @code{display-buffer-alist}. Users can now use @code{display-buffer-alist} to manage how and where windows appear. For more information and examples, see @xref{Controlling buffer display,,, ess}. @item @code{ess-roxy-mode} can now be enabled in non-R buffers. This is primarily intended to support roxygen documentation for cpp buffers. Preview functionality is not supported outside R buffers. @item ESS[R]: DESCRIPTION files now open in @code{conf-colon-mode}. @item @code{ess-style} now has effects when set as a file or directory local variable. @item @code{ess-default-style} is now obsolete, use @code{ess-style} instead. @item Options for 'ess-gen-proc-buffer-name-function' have been renamed. ess-gen-proc-buffer-name:projectile-or-simple was renamed to ess-gen-proc-buffer-name:project-or-simple and ess-gen-proc-buffer-name:projectile-or-directory was renamed to ess-gen-proc-buffer-name:project-or-directory. As the name suggests, these now rely on project.el (included with Emacs) rather than projectile.el, which is a third-party package. @item Eldoc fully honors @code{eldoc-echo-area-use-multiline-p} @item ESS[R]: @code{ess-r-rhub-check-package} gained new @code{RECOMMENDED}. @item ESS[R]: devtools commands ask about saving modified buffers before running. Users can disable the questioning with @code{ess-save-silently}. @item ESS[R] help pages now provide links to other help topics. This is similar with what you would see with, for example @code{options(help_type = ``html'')} but works with the plain-text version as well. This only works with @code{options(useFancyQuotes = TRUE)} (the default). @item @code{ess-rdired} buffers now derive from tabulated-list-mode. They should look better and be a bit faster overall. The size column now displays object sizes in bytes. @item @code{ess-rdired} buffers now auto-update. The frequency is governed by the new option @code{ess-rdired-auto-update-interval}. @item ESS[R]: @code{electric-layout-mode} is now supported. This automatically inserts a newline after an opening curly brace in R buffers. To enable it, customize @code{ess-r-mode-hook}. @item ESS[R]: imenu now supports assignment with the equals sign. @item ESS[Rd]: Rd no longer writes abbrevs to user's abbrev file. @item ESS removed support for many unused languages. This includes old versions of S+, ARC, OMG, VST, and XLS. @item ess-r-runner-prefixes was modified to find R-4 and later. @item ESS no longer activates eldoc if the user has disabled global-eldoc-mode. @end itemize The following have been made obsolete or removed, see their documentation for more detail: @itemize @bullet @item Libraries for literate data analysis are obsolete and not loaded by default. This includes @code{ess-noweb}, @code{ess-swv}, and related functionality like @code{Rnw-mode}. Users are encouraged to switch to one of several other packages that deal with these modes. For example, polymode @url{https://github.com/polymode/poly-R/}, @url{https://polymode.github.io/}, or markdown-mode with edit-indirect @url{https://jblevins.org/projects/markdown-mode}. @item Support for @code{auto-complete} is obsolete. The @code{auto-complete} package is unmaintained and so ESS support is now obsolete. Users are encouraged to switch to @code{company-mode} instead. @item User options for controlling display of buffers. This includes @code{ess-show-buffer-action}, @code{inferior-ess-same-window}, @code{inferior-ess-own-frame}, and @code{inferior-ess-frame-alist}. See above about ESS respecting @code{display-buffer-alist}. @item Variables @code{ess-tab-always-indent} and @code{ess-tab-complete-in-script}. Use the Emacs-wide setting of @code{tab-always-indent} instead. @item @code{inferior-ess-*-start-file} variables. All modes except Stata did not respect customization of this variable. In order to load a file on startup, you should put a function on @code{ess-*-post-run-hook}. @end itemize Bug Fixes in 18.10.3: @itemize @bullet @item More @file{Makefile} fixes, notably installing @file{*.el}s. @end itemize Bug Fixes in 18.10.2: @itemize @bullet @item @ESS{[R]} Fix namespace evaluation in non-installed packages. Evaluation is directed into GlobalEnv as originally intended. @item @file{Makefile} fixes, notably for @code{make install} and including full docs in the tarballs. @end itemize Bug Fixes in 18.10.1: @itemize @bullet @item New functions @code{ess-eval-line-visibly-and-step} (@kbd{C-c C-n} and @code{ess-eval-region-or-line-visibly-and-step} (@kbd{C-RET}) which behave as the old versions of @code{ess-eval-line-and-step} and @code{ess-eval-region-or-line-and-step}. @end itemize Changes and New Features in 18.10: @itemize @bullet @item This is the last release to support Emacs older than 25.1. Going forward, only GNU Emacs 25.1 and newer will be supported. Soon after this release, support for older Emacs versions will be dropped from the git master branch. Note that MELPA uses the git master branch to produce ESS snapshots, so if you are using Emacs < 25.1 from MELPA and are unable to upgrade, you should switch to MELPA-stable. @item ESS now displays the language dialect in the mode-line. So, for example, R buffers will now show ESS[R] rather than ESS[S]. @item The ESS manual has been updated and revised. @item The ESS initialization process has been further streamlined. If you update the autoloads (which installation from @code{package-install} does), you should not need to @code{(require 'ess-site)} at all, as autoloads should automatically load ESS when it is needed (e.g. the first time an R buffer is opened). In order to defer loading your ESS config, you may want to do something like @code{(with-require-after-load "ess" )} in your Emacs init file. Users of the popular @code{use-package} Emacs package can now do @code{(use-package ess :defer t)} to take advantage of this behavior. For more information on this feature, see @xref{Activating and Loading ESS,,, ess,}. @item ESS now respects Emacs conventions for keybindings. This means that The @code{C-c [letter]} bindings have been removed. This affects @code{C-c h}, which was bound to @code{ess-eval-line-and-step-invisibly} in @code{sas-mode-local-map}; @code{C-c f}, which was bound to @code{ess-insert-function-outline} in @code{ess-add-MM-keys}; and @code{C-c h}, which was bound to @code{ess-handy-commands} in @code{Rd-mode-map}, @code{ess-noweb-minor-mode-map}, and @code{ess-help-mode-map} @item Functions @code{ess-eval-line-and-step} and @code{ess-eval-region-or-line-and-step} now behave consistently with other evaluation function inside a package. @item @ESS{[R]}: @code{ess-r-package-use-dir} now works with any mode. This sets the working directory to the root of the current package including for example C or C++ files within @code{/src}). @item @ESS{[R]}: Long + + prompts in the inferior no longer offset output. @item @ESS{[R]}: New option @code{strip} for @code{inferior-ess-replace-long+}. This strips the entire + + sequence. @item ESS modes now inherit from @code{prog-mode}. In the next release, ESS modes will use @code{define-derived-mode} so that each mode will have (for example) its own hooks and keymaps. @item @ESS{[R]}: Supports flymake in R buffers for Emacs 26 and newer. Users need to install the @code{lintr} package to use it. Customizable options include @code{ess-use-flymake}, @code{ess-r-flymake-linters}, and @code{ess-r-flymake-lintr-cache}. @item @ESS{[R]}: Gained support for xref in Emacs 25+ @xref{Xref,,, emacs, The Gnu Emacs Reference Manual}. @item @ESS{[R]}: The startup screen is cleaner. It also displays the startup directory with an explicit @code{setwd()}. @item @ESS{[R]}: Changing the working directory is now always reflected in the process buffer. @item @ESS{[R]}: @code{Makevars} files open with @code{makefile-mode}. @item New variable @code{ess-write-to-dribble}. This allows users to disable the dribble (@code{*ESS*}) buffer if they wish. @item All of the @code{*-program-name} variables have been renamed to @code{*-program}. Users who previously customized e.g. @code{inferior-ess-R-program-name} will need to update their customization to @code{inferior-ess-R-program}. These variables are treated as risky variables. @item @code{ess-smart-S-assign} was renamed to @code{ess-insert-assign}. It provides similar functionality but for any keybinding, not just `_`. For instance if you bind it to `;`, repeated invocations cycle through between assignment and inserting `;`. @item @code{C-c C-=} is now bound to @code{ess-cycle-assign} by default. See the documentation for details. New user customization option @code{ess-assign-list} controls which assignment operators are cycled. @item @ESS{[R]} In remote sessions, the ESSR package is now fetched from GitHub. @item Commands that send the region to the inferior process now deal with rectangular regions. See the documentation of @code{ess-eval-region} for details. This only works on Emacs 25.1 and newer. @item @ESS{[R]}: Improvements to interacting with iESS in non-R files. Interaction with inferior process in non-R files within packages (for instance C or C++ files) has been improved. This is a work in progress. @item @ESS{[R]}: Changing the working directory is now always reflected in the process buffer. @item @ESS{[JAGS]}: *.jog and *.jmd files no longer automatically open in JAGS mode. @end itemize Many improvements to fontification: @itemize @bullet @item Improved customization for faces. ESS now provides custom faces for (nearly) all faces used and places face customization options into their own group. Users can customize these options using @kbd{M-x customize-group RET ess-faces}. @item Many new keywords were added to @code{ess-R-keywords} and @code{ess-R-modifiers}. See the documentation for details. @item @ESS{[R]}: @code{in} is now only fontified when inside a @code{for} construct. This avoids spurious fontification, especially in the output buffer where `in` is a common English word. @item @ESS: Font-lock keywords are now generated lazily. That means you can now add or remove keywords from variables like @code{ess-R-keywords} in your Emacs configuration file after loading ESS (i.e. in the @code{:config} section for @code{use-package} users). @item @ESS{[R]}: Fontification of roxygen @code{@@param} keywords now supports comma-separated parameters. @item @ESS{[R]}: Certain keywords are only fontified if followed by a parenthesis. Function-like keywords such as @code{if ()} or @code{stop()} are no longer fontified as keyword if not followed by an opening parenthesis. The same holds for search path modifiers like @code{library()} or @code{require()}. @item @ESS{[R]}: Fixed fontification toggling. Especially certain syntactic elements such as @code{%op%} operators and backquoted function definitions. @item @ESS{[R]}: @code{ess-font-lock-toggle-keyword} can be called interactively. This command asks with completion for a font-lock group to toggle. This functionality is equivalent to the font-lock menu. @end itemize Notable bug fixes: @itemize @bullet @item @code{prettify-symbols-mode} no longer breaks indentation. This is accomplished by having the pretty symbols occupy the same number of characters as their non-pretty cousins. You may customize the new variable @code{ess-r-prettify-symbols} to control this behavior. @item @ESS{}: Inferior process buffers are now always displayed on startup. Additionally, they don't hang Emacs on failures. @end itemize Obsolete libraries, functions, and variables: @itemize @bullet @item The @code{ess-r-args.el} library has been obsoleted and will be removed in the next release. Use @code{eldoc-mode} instead, which is on by default. @item Functions and options dealing with the smart assign key are obsolete. The following functions have been made obsolete and will be removed in the next release of ESS: @code{ess-smart-S-assign}, @code{ess-toggle-S-assign}, @code{ess-toggle-S-assign-key}, @code{ess-disable-smart-S-assign}. The variable @code{ess-smart-S-assign-key} is now deprecated and will be removed in the next release. If you would like to continue using `_` for inserting assign in future releases, please bind @code{ess-insert-assign} in @code{ess-mode-map} the normal way. @item @ESS{[S]}: Variable @code{ess-s-versions-list} is obsolete and ignored. Use @code{ess-s-versions} instead. You may pass arguments by starting the inferior process with the universal argument. @end itemize Changes and New Features in 17.11: @itemize @bullet @item The ESS initialization process has been streamlined. You can now load the R and Stata modes independently from the rest of ESS. Just put @code{(require 'ess-r-mode)} or @code{(require 'ess-stata-mode)} in your init file. This is for experienced Emacs users as this requires setting up autoloads for @code{.R} files manually. We will keep maintaining @code{ess-site} for easy loading of all ESS features. @item Reloading and quitting the process is now more robust. If no process is attached, ESS now switches automatically to one (prompting you for selection if there are several running). Reloading and quitting will now work during a debug session or when R is prompting for input (for instance after a crash). Finally, the window configuration is saved and restored after reloading to prevent the buffer of the new process from capturing the cursor. @item @ESS{[R]}: New command @code{ess-r-package-use-dir}. It sets the working directory of the current process to the current package directory. @item @ESS{[R]} Lookup for references in inferior buffers has been improved. New variable @code{ess-r-package-source-roots} contains package sub-directories which are searched recursively during the file lookup point. Directories in @code{ess-tracebug-search-path} are now also searched recursively. @item @ESS{[R]} Namespaced evaluation is now automatically enabled only in the @code{R/} directory. This way ESS will not attempt to update function definitions from a package if you are working from e.g. a test file. @end itemize Changes and New Features in 16.10: @itemize @bullet @item @ESS{[R]}: Syntax highlighting is now more consistent. Backquoted names are not fontified as strings (since they really are identifiers). Furthermore they are now correctly recognized when they are function definitions or function calls. @item @ESS{[R]}: Backquoted names and @code{%op%} operators are recognized as sexp. This is useful for code navigation, e.g. with @kbd{C-M-f} and @kbd{C-M-b}. @item @ESS{[R]}: Integration of outline mode with roxygen examples fields. You can use outline mode's code folding commands to fold the examples field. This is especially nice to use with well documented packages with long examples set. Set @code{ess-roxy-fold-examples} to non-nil to automatically fold the examples field when you open a buffer. @item @ESS{[R]}: New experimental feature: syntax highlighting in roxygen examples fields. This is turned off by default. Set @code{ess-roxy-fontify-examples} to non-nil to try it out. @item @ESS{[R]}: New package development command @code{ess-r-devtools-ask} bound to @kbd{C-c C-w C-a}. It asks with completion for any devtools command that takes @code{pkg} as argument. @item @ESS{[R]}: New command @kbd{C-c C-e C-r} to reload the inferior process. Currently only implemented for R. The R method runs @code{inferior-ess-r-reload-hook} on reloading. @item @ESS{[R]}: @code{ess-r-package-mode} is now activated in non-file buffers as well. @end itemize Bug fixes in 16.10: @itemize @bullet @item @ESS{[R]}: Fix broken (un)flagging for debugging inside packages @item @ESS{[R]}: Fixes (and improvements) in Package development @item @ESS{[R]}: Completion no longer produces @code{...=} inside @code{list( )}. @item @ESS{[R]}: Better debugging and tracing in packages. @item @ESS{[R]}: Better detection of symbols at point. @item @ESS{[R]}: No more spurious warnings on deletion of temporary files. @item @ESS{[julia]}: help and completion work (better) @item @ESS{[julia]}: available via @code{ess-remote} @end itemize Changes and New Features in 16.04: @itemize @bullet @item @ESS{[R]}: @code{developer} functionality has been refactored. The new user interface consists of a single command @code{ess-r-set-evaluation-env} bound by default to @kbd{C-c C-t C-s}. Once an evaluation environment has been set with, all subsequent ESS evaluation will source the code into that environment. By default, for file within R packages the evaluation environment is set to the package environment. Set @code{ess-r-package-auto-set-evaluation-env} to @code{nil} to disable this. @item @ESS{[R]}: New @code{ess-r-package-mode} This development mode provides features to make package development easier. Currently, most of the commands are based on the @code{devtools} packages and are accessible with @kbd{C-c C-w} prefix. See the documentation of @code{ess-r-package-mode} function for all available commands. With @kbd{C-u} prefix each command asks for extra arguments to the underlying devtools function. This mode is automatically enabled in all files within R packages and is indicated with @code{[pkg:NAME]} in the mode-line. @item @ESS{[R]}: Help lookup has been improved. It is now possible to get help for namespaced objects such as pkg::foobar. Furthermore, ESS recognizes more reliably when you change @code{options('html_type')}. @item @ESS{[R]}: New specialized breakpoints for debugging magrittr pipes @item @ESS{}: ESS now implements a simple message passing interface to communicate between ESS and inferior process. @end itemize Bug fixes in 16.04: @itemize @bullet @item @ESS{[R]}: Roxygen blocks with backtics are now correctly filled @item @ESS{[R]}: Don't skip breakpoints in magrittr's @code{debug_pipe} @item @ESS{[R]}: Error highlighting now understands `testthat` type errors @item @ESS{[Julia]}: Added getwd and setwd generic commands @end itemize ESS-24.01.1/doc/news.texi000066400000000000000000000000561455642170100147330ustar00rootroot00000000000000 @include ess-defs.texi @include newfeat.texi ESS-24.01.1/doc/onewfeat.texi000066400000000000000000002347541455642170100156050ustar00rootroot00000000000000@comment @itemize @w{} @comment @item Changes and New Features in 15.09: @itemize @bullet @item @ESS{[R]}: The indentation logic has been refactored. It should be faster, more consistent and more flexible. There are three types of indentation settings, those starting with @code{ess-offset-} give the actual offsets, those starting with @code{ess-indent-} are control (commonly Boolean) variables, and those starting with @code{ess-align-} are vertical alignment overrides which inhibit default offsets in specific situations. See @code{ess-style-alist} for detailed description of the new indentation system and provided default indentation styles. @item @ESS{[R]}: Deprecation of old indentation settings. As a consequence of the indentation re-factoring @code{ess-brace-imaginary-offset}, @code{ess-expression-offset} and all delimiter-specific offsets are deprecated. The settings for indentation of continued statements have been replaced by @code{ess-offset-continuations}. It can be set to either @code{cascade} or @code{straight} (the default). @code{ess-arg-function-offset} has been replaced by @code{ess-indent-from-lhs} and has been generalised to assignments. This setting now works with both statement blocks and expressions and only takes effect for offsets set to @code{prev-call} and @code{open-delim} in order to produce a consistent indentation. @item @ESS{}: A test framework has been set up. @item @ESS{[R]}: A new RStudio style is provided to mimic as closely as possible R files indented via RStudio. To reproduce the setup of some of the RStudio users, the RStudio- style with @code{ess-offset-arguments} set to @code{prev-line} is also provided. In addition, the new RRR+ style is equivalent to RRR except it indents blocks in function calls relatively to the opening delimiter. This style does not try to save horizontal space and produces more indentation. @item @ESS{[R]}: Roxygen fields will now be indented on paragraph refilling in order to make the documentation more readable. You can also refill commented lines in the @code{examples} field without squashing the surrounding code in the comments. @item @ESS{[R]}: ESS can now format your code! This is controlled through the settings @code{ess-fill-calls} and @code{ess-fill-continuations}. When activated, @code{(fill-paragraph)} formats your calls and your formulas/continuations while making sure they don't go past @code{fill-column}. Repeated refills cycle through different styles (see the docstrings for more details). By default, the refilled region blinks. Set @code{ess-blink-filling} to nil to prevent this. @item @ESS{[R]}: Fix occasional missing error location fontification in inferior buffers. @item @ESS{[R]}: ess-developer now correctly assigned the environment of new functions to the package namespace. @item @ESS{[Julia]}: ?[topic] now works in the *julia* buffer. Note that support for editing Julia code now depends on @file{julia-mode.el} from the Julia project. If you install ESS from the official tarball/zip file, @file{julia-mode.el} is already included. Otherwise, if you install ESS by running @code{make}, then the latest version of @file{julia-mode.el} is downloaded (and so you need an active internet connection to install) during the installation process. Alternatively, if you run ESS without running @code{make}, then ensure that you have the @code{julia-mode.el}, which you can get easily from MELPA for example. @item @iESS{}: For naming inferior processes, ESS can use @code{projectile}'s project root and it does so when @code{ess-gen-proc-buffer-name-function} is set to @code{ess-gen-proc-buffer-name:projectile-or-simple} as by default, or to another value beginning with @code{ess-gen-proc-buffer-name:projectile-*}. @end itemize Changes and New Features in 15.03-1: @itemize @bullet @item @ESS{[R]}: An indentation bug has been fixed (github issue 163) @item @ESS{[R]}: On windows, if `ess-prefer-higher-bit' is non-nil (the default), then R-newest will try to run a 64 bit (rather than 32 bit) version of R. @end itemize Changes and New Features in 15.03: @itemize @bullet @item @ESS{[R]}: Full native support for `company-mode`. @item @ESS{[R]}: More efficient caching algorithm for R completion. @item @ESS{}: New offset variable `ess-close-paren-offset` to control the indentation of the closing parentheses. @item @ESS{[R]}: Ask for CRAN mirror only once per emacs session. @item @ESS{[R]}: Detect @code{library} and @code{require} calls for better completion caching. @item Buffer display is now customizable (@code{ess-show-buffer-action}). @item Use @code{y-or-n-p} instead of @code{yes-or-no-p} throughout. @item More support for ODS in ess-sas-graph-view. @item Makefiles are now both UNIX and GNU friendly. @item @ESS{[R]}: Simplify directory lookup in @code{ess-developer} (#137). @item Make closed paren indentation consistent @end itemize Bug Fixes in 15.03: @itemize @bullet @item Fix open brace indentation bug (#27 in ess/R-ESS-bugs.R). @item Fix git version lookup @item Don't check directory modtime in R dialect. @item Declare all ess macros for edebug. @item Add @code{ess-smart-comma} to eldoc message functions. @item Inform users when retrieving RDA aliases. @item Line ending in '~' is also a continuation line. @item Filing roxy paragraphs works as expected now. @item In @code{ess-developer-add-package}, remove incorrect `wait` argument from @code{ess-get-words-from-vector} call. @item Fix #96, #117, #120, #125, #134, #137. @item Fix ess-quit-r. Call base::q() even if it is masked. @item Fix `ess-show-buffer` to always display the buffer in another window. @item Makefile: Fix cd bug for directories with spaces in them @item @code{ess-kill-buffer-and-go} modified to not restart R @end itemize Changes / Selected Bug Fixes in 14.09: @itemize @bullet @item @ESS{[Julia]}: Executable is changed to @code{julia}. @item @ESS{[Julia]}: Completion and help system was adjusted to Julia v.0.3.0. Julia v.0.2.x is no more supported. @item @ESS{[R]}: Running R with @code{gdb} debugger now works as expected @item @iESS{}: Inferior ESS buffers are now derived from @code{comint-mode} @item @ESS{[R]}: @code{ess-execute-screen-options} uses correct screen width in terminal sessions @item @ESS{}: @code{ess-build-tags-for-directory} works when no TAGS file name was provided @item @ESS{}: @code{ess-offset-statement-continued} is now respected everywhere except inside of the @code{if} test condition. @item @ESS{}: New variable @code{ess-offset-statement-first-continued} for indentation of the first line in multiline statements. @item @ESS{R}: Starting @kbd{,} in multiline statements indentation is now ignored to achieve a more pleasant alignment. @item @ESS{R}: Improved behavior of @kbd{RET} in roxygen blocks. @item @ESS{[R]}: command cleaning with @kbd{C-u C-u C-y} was broken with lines containing " + " @item @ESS{[R]}: fixed "empty watch window bug" @item @ESS{[R]}: don't ask for help location on ac-quick-help (request of github #81) @item @ESS{[R]}: "importClassesFrom" and "importMethodsFrom" were added to the list of two-parameter roxygen commands @item @ESS{[R]}: fix vignetes display and hyperlinks (were broken in 13.09-1) @item @ESS{[Julia]}: recognize function names ending with ! @item @ESS{[Julia]}: fix indentation of "for" comprehension syntax within brackets. @end itemize Changes / Selected Bug Fixes in 13.09-1: @itemize @bullet @item ess-remote and TRAMP: R support code is now downloaded in binary form instead of being injected from local machine. The R code is stored in @code{~/.config/ESSR/} directory on the remote machine @item TRAMP: PAGER environment variable is now correctly set to @code{inferior-ess-pager} @item retrieval of help topics on remote machines is fixed @item org-babel: source references of R code executed from org files correctly point to source references in original org files (version 8.2.1 or higher of org-mode is required for this feature) @item @code{ess-execute} is now bound to @kbd{C-c C-e C-e} in @code{ess-extra-map}. @item completion works again in @code{ess-execute} @item @ESS{[R]}: @code{head} and @code{tail} methods were replaced by @code{.ess_htsummary} in @code{ess-R-describe-object-at-point-commands} @item @ESS{[roxygen]}: evaluation commands now work in roxygen blocks. Leading comments are automatically removed before the evaluation @item @ESS{[transcript]}: 'Clean Region' now works with multiline statements; @code{ess-transcript-clean-region} etc. correctly treat multiline statements, i.e., no longer forgets the lines typically preceded by '+' @item @ESS{[SAS]}: Three features/fixes with special thanks to Matthew Fidler @uref{https://github.com/emacs-ess/ESS/pulls/mlf176f2, https://github.com/emacs-ess/ESS/pulls/mlf176f2}. Turn on SAS log mode when appropriate. Indent comments and CARDS statement more appropriately. @item @ESS{[SAS]}: @code{ess-sas-edit-keys-toggle} default returns to @code{nil} @item @ESS{[R]}: support for @code{prettify-symbols-mode}: contribution from Rudiger Sonderfeld @uref{https://github.com/emacs-ess/ESS/pull/65} @item @ESS{[SWV]}: knitr now evaluates in the current frame @item @ESS{[developer]}: ess-developer doesn't kill open DESCRIPTION files anymore @item @ESS{[roxygen]}: @code{ess-roxy-preview-HTML} is now on @kbd{C-c C-o C-w} and @code{ess-roxy-preview-text} is now on @code{C-c C-o C-t} @item @ESS{}: installation with @code{make install} was simplified and should work out of the box on most *nix systems @item @ESS{} installation instructions simplified @item fixed font-lock bug introduced in 13.09 that was causing very slow process output @end itemize Changes/New Features in 13.09: @itemize @bullet @item font-lock in process buffers doesn't "spill" over prompts. Missing closing string delimiters should not cause wrong fontification of the following command input. @item @ESS{[julia]}: full features M-TAB completion and auto-complete support, which now works for modules, structures and data types. @item @ESS{[julia]}: a much better eldoc showing arguments of methods and data type constructors @item ESS-developer: @itemize @minus @item ESS-developer work-flow pattern has been streamlined: ESS-developer is now automatically activated on per-file basis if the file is part of a developed package @code{ess-developer-packages}. The old behavior (activation on per-process basis) is still available on @code{M-x ess-developer} in a process buffer. @item integration with @code{devtools} package. New command @code{ess-developer-load-package} calls @code{load_all} on the package containing current file. @code{ess-developer-add-package} now offers IDO menu completions with available loading methods, currently @code{library}, and @code{load_all}. Loading command can be customized with @code{ess-developer-load-on-add-commands}. @end itemize @item @kbd{TAB} now indents region if region is active (a contribution of Matthew Fidler in pull #41) @item @code{M-x ess-version} now reports full loading path and recognizes git and ELPA versions. @item warning and error keyword are now highlighted with @code{font-lock-warning-face} as they should be, (for quite some time these keywords have been hijacked by compilation mode fontification). @item eldoc: Eldoc now recognizes multiple processes. If current process is busy, or current buffer is not associated with a process, eldoc picks its completions from the first available free process. @item org-babel: evaluation is now org-friendly @item help: new help buffers now try to reuse ess-help buffers. This behavior is controlled by @code{ess-help-reuse-window} custom variable. @item help: ?foo pops IDO menu on multiple help files (so far it worked only for @kbd{C-c C-v}) @item remote evaluation is considerably faster now on slow connections @item @ESS{[R]} tracebug R source references regular expressions are (mostly) language agnostic. @item @code{ess-function-call-face} inherits from @code{font-lock-function-name-face} rather than @code{font-lock-builtin-face}. @item @code{ess-inject-source} now accepts @code{function-and-buffer} option. @item Documentation: The ``New Features'' section (and @file{NEWS}) now represent recent changes: within the last year or so. All changes can be found in the new @uref{news.html, news.html} (or @file{NEWS} and @file{ONEWS}). @item @ESS{[R]} @code{ess-rep-regexp} should no longer inf.loop (rarely!), and hence @code{M-x ess-fix-miscellaneous} should neither. @end itemize Changes/New Features in 13.05: @itemize @bullet @item @ESS{[gretl]}: Support for @code{gretl} (both editing and sub-process interaction). A contribution of Ahmadou Dicko. @item @ESS{}: process output display is 4-10 times faster due to new caching and only occasional emacs re-display (for the moment this functionality is available only when @code{ess-tracebug} is active). @item @ESS{}: @kbd{C-c `} is now bound to @code{ess-show-traceback} and @kbd{C-c ~} is bound to @code{ess-show-call-stack}. @item @ESS{[R]}: ESS stores function in 'ESSR' environment to avoid kludging users' global environment and accidental deletion. @item @ESS{[R]}: new variable @code{ess-swv-processing-command} to control weaving and tangling. @item @ESS{[R]}: @code{ess-default-style} has been changed (from @code{DEFAULT}) to @code{RRR}. Use something like @code{(setq ess-default-style 'DEFAULT)} or @code{(setq ess-indent-level 2)} in your @file{~/.emacs} equivalent @emph{before} loading ESS, if you do not like this new ``incompatible'' default style. @item @ESS{[julia]}: ESS stores its functions in 'ESS' module. @item @ESS{[julia]}: Eldoc is now supported in julia modes @item @ESS{[julia]}: Adjusted error reference detection and interactive help to julia internal changes @item @ESS{[R]}: @code{ess-use-tracebug}'s default has been changed to @code{t}. Set it to nil if you want to keep the previous behavior. @item @ESS{[tracebug]}: Electric debug keys have been removed [breaking change] The functionality was replaced with @code{ess-debug-minor-mode} and @code{ess-debug-minor-mode-map}. @item @ESS{[tracebug]}: @code{ess-tracebug-map} is an alias to @code{ess-dev-map} @kbd{C-c C-t}. @item @ESS{[tracebug]}: @code{ess-bp-toggle-state} (@kbd{C-c C-t o}) can now be used during the debug session to toggle breakpoints on the fly (suggestion by Ross Boylan). @item @ESS{[tracebug]}: @code{ess-debug-flag-for-debugging} and @code{ess-debug-unflag-for-debugging} work correctly from the debugging contexts. These commands also recognize non-exported functions for the packages listed in @code{ess-developer-packages} (@kbd{C-c C-t C-a}). @item @ESS{[R]}: Eldoc (activated by @code{ess-use-eldoc}) has become more sophisticated, and hence also more intruding in the interface between the Statistics software, e.g., @R{}, and the user. Note that you can turn off ElDoc, by placing @code{(setq ess-use-eldoc nil)} in your @file{~/.emacs} file, prior to loading ESS, @item @ESS{[SAS]}: long over-looked @code{SAS-mode-hook} appears! @item @ESS{[SAS]}: @code{ess-sas-edit-keys-toggle} now defaults to @code{t} since @code{sas-indent-line} is still broken, i.e. @kbd{TAB} is now bound to @code{ess-sas-tab-to-tab-stop} by default @end itemize Changes/Bug Fixes in 12.09-2: @itemize @bullet @item @ESS{}: new @code{ess-switch-to-end-of-proc-buffer} variable that controls whether @kbd{C-c C-z} switches to the end of process buffer. The default is @code{t}. You can use prefix argument to @kbd{C-c C-z} to toggle this variable. @item @ESS{}: fix in @code{ess-eval-linewise} that was causing emacs to hang during R debugging with @code{ess-eval-visibly} equal to @code{t}. @item @ESS{}: fix in @code{ess-eval-linewise} that was causing emacs to recenter the prompt in visible window @item @ESS{[tracebug]}: A better handling of ``Selection'' prompts and debug related singlekey commands. @item @ESS{}: fix a bug in @code{ess-switch-process} that was causing @code{*new*} selection to fail. @item @ESS{[R]}: Solve missing @code{ess-local-process-name} bug in R-dired. @item @ESS{[SWV]}: @code{ess-swv-PDF} doesn't ask for a command to run if there is only one command in @code{ess-swv-pdflatex-commands}. @item @ESS{[SWV]}: @code{ess-swv-weave} gained an universal argument to allow for an interactive choice between available weavers (sweave, knitr). @item @ESS{}: @code{ess-eval-*-and-step} functions go to next empty line at eob, instead of staying at the last line. @end itemize Changes/New Features in 12.09-1: @itemize @bullet @item @ESS{} @emph{Breaking Changes in Keys}: @itemize @minus @item New keymaps: @code{ess-doc-map} bound to @kbd{C-c C-d}; @code{ess-extra-map} bound to @kbd{C-c C-e}; @code{ess-dump-object-into-edit-buffer} was moved on @kbd{C-c C-e C-d} @item roxygen map was moved on @kbd{C-c C-o} and @kbd{ess-roxy-update-entry} now resides on @kbd{C-c C-o C-o} @item ess-handy-commands is not bound anymore @item @code{ess-dev-map} (including @code{ess-tracebug} and @code{ess-developer}) moved on @kbd{C-c C-t} @item @code{C-c C-y} is deprecated in favor of @code{C-c C-z C-z} @end itemize @item @ESS{[R]} new command @code{ess-describe-object-at-point} bound to @kbd{C-c C-d C-e} (repeat @kbd{C-e} or @kbd{e} to cycle). It was inspired by Erik Iverson's @code{ess-R-object-tooltip}. Customize @code{ess-describe-at-point-method} to use tooltip instead of an electric buffer. @item @ESS{}: New command @code{ess-build-tags-for-directory} bound to @kbd{C-c C-e C-t} for building dialect specific tag tables. After building tags use @kbd{M-.} to navigate to function and objects definitions. By default @kbd{C-c C-e C-t} builds tags based on imenu regular expressions and also include other common languages @code{.c, .o, .cpp} etc. But it relies on external @code{find} and @code{etags} commands. If @code{ess-build-tags-command} is defined (for @code{R}), the inferior process is asked to build tags instead. @item @ESS{}: @code{ess-switch-process} offers @code{*new*} alternative to start a new process instead of switching to one of the currently running processes. @item @ESS{}: Switching between processes (@kbd{C-c C-s}) uses buffer names instead of the internal process names. Use @code{M-x rename-buffer} command to conveniently rename your process buffers. @item @ESS{}: Process buffers can be automatically named on process creation according to user specified scheme. Default schemes are *proc*, *proc:dir* and *proc:abbr-long-dir* where @code{proc} stands for the internal process name and @code{dir} stands for the directory where the process was started in. The default is *proc*. For customization see @code{ess-gen-proc-buffer-name-function}. @item @ESS{}: @code{ess-eval-visibly-p} is deprecated in favor of @code{ess-eval-visibly}. @item @ESS{}: New evaluation pattern @code{nowait}. In addition to old @code{nil} and @code{t} values, @code{ess-eval-visibly} accepts @code{nowait} for a visible evaluation with no waiting for the process. See @code{ess-eval-visibly} for details on evaluation patterns. @item @ESS{}: New ``Process'' menu entry with process related commands and configuration @item @iESS{}: Process buffer is now automatically shown on errors @item @ESS{}: New @code{ess-switch-to-inferior-or-script-buffer} command bound to @kbd{C-c C-z} in both script and process buffers. If invoked form process buffer it switches to the most recent buffer of the same dialect. It is a single key command. @item @ESS{R-help}: On multiple help pages with the same name, @kbd{C-c C-v} now asks for user resolution directly in emacs. @item @ESS{[R]} ess-roxy: new variable @code{ess-roxy-re} for fontification of cases where the number of leading @kbd{#} differs from @code{ess-roxy-str}. @item @ESS{[R]} Eldoc was considerably enhanced. It now finds hidden default S3 methods and displays non-default methods' arguments after trailing ||. @item @ESS{[R]}: New @code{ess-display-demos} command bound to @kbd{C-c C-d o} and @kbd{C-c C-d C-o} @item @ESS{}: New @code{ess-help-web-search} command bound to @kbd{C-c C-d w} and @kbd{C-c C-d C-w} to facilitate interactive search of web resources. Implemented for @code{R}, @code{Stata} and @code{Julia}. See also @code{ess-help-web-search-command}. @item @ESS{}: ess-pdf-viewer-pref accepts now command line arguments @item @ESS{[Rnw]}: Add knitr support. Customize @code{ess-swv-processor} for the default processor. @item @ESS{[Rnw]}: More thorough renaming of remaining @code{noweb-*} to @code{ess-noweb-*}. @item @ESS{[Rnw]} new commands @code{ess-eval-chunk-and-step} and @code{ess-eval-chunk} bound to @kbd{M-n C-c} and @kbd{M-n C-M-x} to mirror standard ess commands in C-c map. @item @ESS{[R]} Auto-completion: new variable @code{ess-ac-R-argument-suffix} to customize the insertion of trailing "=". Defaults to `` = ``. @item @ESS{[Julia]}: Added index, apropos and web-search to julia. @item @ESS{} help: More evaluation commands were added to ess-help mode (@kbd{C-c C-c}, @kbd{C-M-x} etc) @end itemize Bug Fixes in 12.09-1: @itemize @bullet @item @iESS{help}: Multiple help pages with the same name are properly handled on @kbd{C-c C-v} @item @iESS{remote}: Evaluation with ESS remote no longer freezes emacs. @item @iESS{}: @code{comint-previous-prompt} @kbd{C-c C-p} no longer stops on secondary prompt ``+''. @item @iESS{[R]}, @iESS{(Sqpe) [S]} on Windows: The @code{options("editor")} is now initialized to @code{emacsclient} instead of the previous @code{gnuclient}. The user may need to add the line @code{(server-start)} to the emacs initialization file. @code{emacsclient} has been included with emacs since GNU Emacs 22.1. @item @ESS{[Rnw]} Fixed ``connection to R'' bug (in 12.09 only). @item @ESS{[Rnw]} Explicit @code{ess-swv-stangle} and @code{ess-swv-sweave} functions. @item @ESS{[Rnw]} Fixed completion and smart underscore problems cause by unmatched ``\''' @item @ESS{[R]} is more careful with the @code{R} code injection. It now happens only once at the start of the session. @item @ESS{[R]}: Fixed auto-scrolling the comint buffer on evaluation. @item @ESS{[Julia]}: Solve several indentation and word navigation problems. @item @ESS{[Julia]}: Help system works again. @end itemize Changes/New Features in 12.09: @itemize @bullet @item @b{Due to XEmacs lacking some features that ESS requires, ESS support of XEmacs ends with ESS 12.04-4. This decision will be re-visited in the future as XEmacs continues to sync with GNU Emacs.} @item @ESS{[R]}: On Windows, there is now a new customizable variable (currently called @code{ess-directory-containing-R}) to tell ESS where to look for the @file{Rterm.exe} executables. The name of the variable and the values it can take are both in beta and subject to change. Prior to this variable, ESS searched only in the default installation directory. Setting this variable now tells ESS how to find @file{Rterm.exe} executables when they are installed somewhere else. @item @ESS{[julia]}: @emph{new} mode for editing julia code (@file{*.jl}). Start with @code{M-x julia}. Full interaction interface, imenu and basic error referencing are available. @item @ESS{[R]} noweb: @code{noweb-mode} and @code{noweb-font-lock-mode} have been renamed to @code{ess-noweb-mode} and @code{ess-noweb-font-lock-mode} to avoid conflicts with the ``real'' @code{noweb-mode}. @item @ESS{[R]} noweb: The long standing font-lock bug has been solved in @code{ess-noweb} interface. @item @ESS{}: Basic evaluation keys are now bound to @code{ess-eval-region-*-} functions: @itemize @minus @item @kbd{C-M-x} is bound to @code{ess-eval-region-or-function-or-paragraph} @item @kbd{C-c C-c} is bound to @code{ess-eval-region-or-function-or-paragraph-and-step} @item @kbd{C-RET} is bound to @code{ess-eval-region-or-line-and-step} @end itemize Each of these functions first evaluates the region whenever the region is active. @item @ESS{}: @kbd{C-M-a}/@kbd{C-M-e} now step to beginning/end of paragraph if no function has been detected. @item @ESS{}: @code{ess-eval-*-and-step} family of functions are now smarter, and don't step to end of buffer or end of chunk code (@code{@@}) when at the end of the code. @item @ESS{}: @code{ess-handy-commands} function is bound to @kbd{C-c h} @item @ESS{}: ESS is now @emph{blinking} the evaluated region. Set @code{ess-blink-region} to nil to deactivate; @code{ess-blink-delay} gives the duration of the blink. Evaluated region is ``blinked'' in @code{highlight} face. @item @ESS{[R-help]} New key @kbd{a} for ``apropos()'' in help buffers. Also available through @kbd{C-c h}. @item @ESS{[R-help]} All R commands of type foo?bar and foo??bar are recognized and redirected into appropriate *ESS-help* buffers. @item @ESS{[R]}: New customization interface for @emph{font-lock}. ESS font-lock operates with predefined keywords. Default keywords are listed in @code{ess-R-font-lock-keywords} and @code{inferior-R-font-lock-keywords}, which see. The user can easily customize those by adding new keywords. These variables can also be interactively accessed and saved through @kbd{ESS/Font-lock} submenu. Several new fontification keywords have been added. Most notably the keywords for highlighting of function calls, numbers and operators. @item @ESS{[R]}: auto-complete is now activated by default whenever auto-complete package is detected. Set @code{ess-use-auto-complete} to nil to deactivate. @item @ESS{[R]}: R AC sources are no longer auto-starting at 0 characters but at the default @code{ac-auto-start} characters. @item @ESS{} no longer redefines default ac-sources, but only appends @code{ac-source-filename} to it. @item @ESS{}: @code{ac-source-R} now concatenates `` = `` to function arguments. @item @ESS{}: Menus for ESS and iESS have been reorganized and enriched with @emph{Tracebug} and @emph{Developer} submenus. @item @ESS{[R]}: @code{ess-developer} and @code{ess-tracebug} commands are available by default in @code{ess-dev-map} which is bound to @kbd{C-c d} in ESS and iESS maps. @item @ESS{[R]}: @code{eldoc} truncates long lines whenever @code{eldoc-echo-area-use-multiline-p} is non-nil (the default). Set this variable to t if you insist on multiline eldoc. See also @code{ess-eldoc-abbreviation-style}. @item @ESS{[R]}: completion code pre-caches arguments of heavy generics such as @code{plot} and @code{print} to eliminated the undesirable delay on first request. @item @iESS{}: Prompts in inferior buffers are now highlighted uniformly with @code{comint-highlight-prompt} face. @item @ESS{[R]}: R process no longer wait for the completion of input in inferior buffer. Thus, long running commands like @code{Sys.sleep(5)} no longer stall emacs. @item @ESS{}: [R, S, Stata, Julia] have specialized @code{ess-X-post-run-hook}s, which are run at the end of subprocess initialization. @item @ESS{[Stata]}: All interactive evaluation commands work as expected. On-line comments are removed before the evaluation and multiline comments are skipped on @kbd{C-c C-c} and other interactive commands. @item @ESS{} no longer auto-connects to a subprocess with a different dialect than the current buffer's one. @item @ESS{}: @code{ess-arg-function-offset-new-line} is now a list for all the ESS indentation styles, which results in the following indentation after an open ``('': @verbatim a <- some.function(other.function( arg1, arg2) @end verbatim @item @ESS{[SAS]}: Improved MS RTF support for GNU Emacs; try @code{ess-sas-rtf-portrait} and @code{ess-sas-rtf-landscape}. @end itemize Changes/Bug Fixes in 12.04-3: @itemize @bullet @item @ESS{}: basic support for package.el compatibility @item @ESS{[R]}: correct indentation of & and | continuation lines @item @code{M-x ess-version} shows the svn revision even after @code{make install} @item @ESS{[SAS]}: improved XEmacs support @item @iESS{[R]}: better finding of previous prompt @item @ESS{[Stata]}: adjusted prompt for mata mode @item @ESS{[R]}: resolved name clashes with cl.el @item @ESS{[R]}: removed dependence on obsolete package assoc @item New @code{make} target @code{lisp}, to build the Lisp-only part, i.e., not building the docs. @end itemize Changes/New Features in 12.04-1: @itemize @bullet @item @iESS{[Stata]}: New interactive help invocation. @item @iESS{[Stata]}: New custom variable @code{inferior-STA-start-file}. @item @iESS{[Stata]}: @code{inferior-STA-program-name} is now ``stata'' and can be customized. @item @ESS{[Stata]} New sections in stata help files Syntax(@kbd{s-S}), Remarks(@kbd{r}), Title(@kbd{t}). @end itemize Bug Fixes in 12.04-1: @itemize @bullet @item @ESS{[R]}: Better @code{ess-tracebug} error handling. @item @ESS{[R]}: Corrected @code{ess-eldoc} help string filtering and improved argument caching. @item @ESS{[R]}: Indentation of non-block if/else/for/while lines fixed. @item @code{M-x ess-version} should work better. @item @ESS{}: Filename completion now again works inside strings. @item @iESS{[Stata]}: Fixed prompt detection issue. @item @ESS{[Rd]}: R is autostarted also from here, when needed. @end itemize Changes/New Features in 12.04: @itemize @bullet @item @ESS{}: Reverting new behavior of 12.03, @kbd{TAB} in @code{ess-mode} no longer completes by default. If you want smart @kbd{TAB} completion in R and S scripts, similarly to @iESS{} behavior, set the variable @code{ess-tab-complete-in-script} to @code{t}. Also see @code{ess-first-tab-never-complete} for how to customize where first @kbd{TAB} is allowed to complete. @item @ESS{}: completion is consistently bound to @kbd{M-TAB} (aka @kbd{M-C-i}) in both Emacs23 and Emacs24. @item @ESS{}: The variable @code{ess-arg-function-offset-new-line} introduced in @ESS{(12.03)} now accepts a list with the first element a number to indicate that the offset should be computed from the indent of the previous line. For example setting it to '(2) results in: @verbatim a <- some.function( arg1, arg2) @end verbatim @end itemize Changes/New Features in 12.03: @itemize @bullet @item @ESS{} indentation: new offset variable @code{ess-arg-function-offset-new-line} controlling for the indentation of lines immediately following open '('. This is useful to shift backwards function arguments after a long function call expression: @verbatim a <- some.function( arg1, arg2) @end verbatim instead of the old @verbatim a <- some.function( arg1, arg2) @end verbatim If '(' is not followed by new line the behavior is unchanged: @verbatim a <- some.function(arg1, arg2) @end verbatim This variable should be set as part of indentation style lists, or in ess-mode hook. @item @ESS{[R]}: @kbd{C-c .} sets (indentation) style. @item @ESS{}: In ESS buffers @code{yank}(@kbd{C-y}) command accepts double argument @kbd{C-u C-u} to paste commands only. It deletes any lines not beginning with a prompt, and then removes the prompt from those lines that remain. Useful to paste code from emails, documentation, inferior ESS buffers or transcript files. @item Documentation: ESS user manual has been rearranged and completed with several new chapters and sections to reflect newly added features (``Completion'', ``Developing with ESS'', ``ESS tracebug'', ``ESS developer'', ``ESS ElDoc'', ``IDO Completion'' and ``Evaluating Code'') @item RefCard: Reference card was updated to include new features. @item Eldoc: Eldoc was rewritten and is activated by default. See @code{ess-use-eldoc}, @code{ess-eldoc-show-on-symbol}, @code{ess-eldoc-abbreviation-style} variables for how to change the default behavior. @emph{Note:} @code{skeleton-pair-insert-maybe} prohibits eldoc display, on @kbd{(} insertion. @item @ESS{[R]}: Eldoc shows arguments of a generic function whenever found. @item @ESS{}: @kbd{TAB} in @code{ess-mode} now indents and completes, if there is nothing to indent. Set @code{ess-first-tab-never-completes-p} to @code{t} to make @kbd{TAB} never complete on first invocation. Completion mechanism is similar to the completion in the @code{inferior-ess-mode} -- a filename expansion is tried, if not found ESS completes the symbol by querying the process. @item @ESS{} for emacs version 24 or higher: ESS is fully compatible with the emacs 24 completion scheme, i.e. all the completion is done by @code{completion-at-point}. Also in accordance with emacs conventions, ESS doesn't bind @kbd{M-TAB} for emacs 24 or higher. @kbd{M-TAB} calls the default @code{complete-symbol}. @item @ESS{[R]}: Out of the box integration with @code{Auto Completion} mode @uref{http://cx4a.org/software/auto-complete,http://cx4a.org/software/auto-complete} . Three AC sources @code{ac-source-R-args}, @code{ac-source-R-objects} and @code{ac-source-R} are provided. The last one combines the previous two and makes them play nicely together. Set @code{ess-use-auto-complete} to @code{t} to start using it. Refer to documentation string of @code{ac-use-auto-complete} for further information. @item @ESS{[R]}: New unified and fast argument completion system, comprised of @code{ess-funname.start}, @code{ess-function-arguments}, @code{ess-get-object-at-point}. Eldoc and auto-completion integration are using this system. @item @ESS{}: @code{ess-switch-to-end-of-ESS}(@kbd{C-c C-z}), and @code{ess-switch-to-ESS}(@kbd{C-c C-y}): Automatically start the process whenever needed. @item @ESS{[R]}: @code{roxy} knows about previewing text version of the documentation. Bound to @kbd{C-c C-e t}. @item @ESS{[R]}: Solved the ``nil filename'' bug in roxygen support. @item @ESS{[R]}: @code{ess-tracebug} is now part of @ESS{}: New Features: @itemize @minus @item Source injection: Tracebug now can inject source references on the fly during code evaluation, i.e. you don't have to source your file, but just evaluate your code in normal fashion. Variable @code{ess-tracebug-inject-source-p} controls this behavior - if t, always inject source reference, if @code{'function}, inject only for functions (this is the default), if @code{nil}, never inject. During the source injection the value of @code{ess-eval-visibly} is ignored. @item Org-mode support: Visual debugger is now aware of the temporary org source editing buffer (@kbd{C-c '}) and jumps through this buffers if still alive, or in original org buffer otherwise. @item New keys in watch mode: @kbd{?} and @kbd{d} @item Two new hooks: ess-tracebug-enter-hook and ess-tracebug-exit-hook @end itemize @item @ESS{[R]}: New package @code{ess-developer} to evaluate @code{R} code directly in the package environment and namespace. It can be toggled on and off with @kbd{C-c d t}. When @code{ess-developer} is on all ESS evaluation commands are redefined to evaluate code in appropriate environments. Add package names to the list of your development packages with @kbd{C-d a}, and remove with @kbd{C-d r}. Source the current file with @kbd{C-d s}.Evaluation function which depend on @code{`ess-eval-region'} ask for the package to source the code into, @code{ess-eval-function} and alternatives search for the function name in the development packages' environment and namespace and insert the definition accordingly. See the documentation section ``Developing with ESS/ESS developer'' for more details. @item @ESS{[R]} help system: New Features: @itemize @minus @item @kbd{q} quits window instead of calling @code{ess-switch-to-end-of-ESS}. This is consistent with emacs behavior help and other special buffers (@emph{breaking change}). @item @kbd{k} kills window without asking for the name (pointed by Sam Steingold) @item Help map inherits from @code{special-mode-map} as suggested by Sam Steingold. @item Package index: new function @code{ess-display-index} bound to @kbd{i} in help mode map. @item Package vignettes: new function @code{ess-display-vignettes} bound to @kbd{v} in help mode map. @item Display help in HTML browser: new function @code{ess-display-help-in-browser} bound to @kbd{w} in help mode map. It depends on @code{R}'s @code{browser} option. @item New custom variable @code{ess-help-pop-to-buffer}: if non-nil @ESS{} help buffers are given focus on display. The default is @code{t} (@emph{breaking change}). @item New menu entries for the above functions. @item Bogus help buffers are no longer generated by default, i.e. buffers of the form ``No documentation for 'foo' in specified packages and libraries: you could try '??foo' ''. @code{ess-help-kill-bogus-buffers} now defaults to @code{t}. Beware, there may be instances where the default is unsatisfactory such as debugging and/or during R development. Thanks to Ross Boylan for making the suggestion, Sam Steingold for reminding us of this variable and Martin Maechler for the warning. @end itemize @item @ESS{} now uses @code{IDO} completing read functionality for all the interactive requests. It uses ido completion mechanism whenever available, and falls back on classical completing-read otherwise. You can set @code{ess-use-ido} to nil if you don't want the IDO completion. See the documentation string of @code{ess-use-ido} for more information about @code{IDO} and @ESS{} configuration. @item @ESS{[S]}: ``@kbd{,}`` is bound to ess-smart-comma: If comma is invoked at the process marker of an ESS inferior buffer, request and execute a command from @code{`ess-handy-commands'} list. If @code{ess-R-smart-operators} is t @code{`ess-smart-comma} also inserts `` `` after comma. @item @ESS{[S]}, notably @code{R}: Variable @code{`ess-handy-commands'} stores an alist of useful commands which are called by @code{ess-smart-comma} in the inferior buffer. Currently containing: @table @asis @item change-directory @code{ess-change-directory} @item help-index @code{ess-display-index} @item help-object @code{ess-display-help-on-object} @item vignettes @code{ess-display-vignettes} @item objects[ls] @code{ess-execute-objects} @item search @code{ess-execute-search} @item set-width @code{ess-execute-screen-options} @item install.packages @code{ess-install.packages} @item library @code{ess-library} @item setRepos @code{ess-setRepositories} @item sos @code{ess-sos} @end table Handy commands: @code{ess-library}, @code{ess-install.packages}, etc - ask for item with completion and execute the correspond command. @code{ess-sos} is a interface to @code{findFn} function in package @code{sos}. If package @code{sos} is not found, ask user for interactive install. @item @ESS{}: New dynamic mode line indicator: Process status is automatically reflected in all mode-lines of associated with the process buffers. Particularly useful for displaying debug status of @code{ess-tracebug} and developer status of @code{ess-developer} in all associated buffers. @item @ESS{}: New @code{ess-completing-read} mechanism: @ESS{} uses @code{ido} completions whenever possible. Variable @code{ess-use-ido} controls whether to use ido completion or not. Active by default. @item @ESS{} now supports comint fields for output and input detection. This feature is not used by default, but might be useful in the future. @item @ESS{[S]}: New custom variable @code{inferior-ess-S-prompt} to customize prompt detection regular expression in the inferior ESS buffers. You can customize this variable to enhance comint navigation (@code{comint-previous-prompt} and @code{comint-next-prompt}) the inferior buffers. @item @ESS{[R]}: Internal @code{R} completion retrieval (@code{ess-R-complete-object-name}) was rewritten and is faster now. @item @ESS{} is using process plist to store process specific variables, as opposed to buffer local variables as it was using before. The use of buffer local variables to store process variables is discouraged. @item @ESS{}: new functions to manipulate process plists: @code{ess-process-get} and @code{ess-process-set}. @item @ESS{}: Internal process waiting mechanism was completely rewritten. ESS no more relies on prompt regular expressions for the prompt detection. The only requirement on the primary process prompt is to end in @code{> }. This could be overwritten by setting @code{inferior-ess-primary-prompt}. @item @ESS{[S]}, notably @code{R}: Saved command history: @var{ess-history-file} now accepts @code{t} (default), @code{nil}, or a file name. By setting it to @code{nil} no command line history is saved anymore. @var{ess-history-directory} now allows to have the history all saved in one ``central'' file. @item @ESS{[R]}: more Roxygen improvements. @item @ESS{[R]}: @kbd{C-c .} to set (indentation) style. @item @ESS{[R]}: Functions with non-standard names (for example 'aaa-bbb:cc') are properly handled by font-lock and evaluation routines. @item @ESS{[R]}:Several regexp bugs (described in etc/R-ESS-bugs.el) were fixed in @code{ess-get-words-from-vector} and @code{ess-command}. @end itemize @comment @end itemize Changes/New Features in 5.14: @itemize @bullet @item @ESS{[BUGS/JAGS]}: Batch BUGS is back! For recent OpenBUGS versions, 3.0.8+, a batch BUGS script is once again available, but for Linux only. Therefore, since it seems that BUGS and JAGS must co-exist (rather than a transition from BUGS to JAGS), .bug files are now in @ESS{[BUGS]} mode and .jag files are in @ESS{[JAGS]} mode. @ESS{[BUGS]} now works like @ESS{[JAGS]} rather than the original mode @ESS{[BUGS]} mode which was difficult to maintain. Although, @ESS{[BUGS]} appears to work, there still may be some features missing as well as bugs. @item @ESS{[R]}: New customizable variable @code{ess-swv-plug-into-AUCTeX-p} Commands to Sweave current file and LaTeX the result are now available to AUCTeX users, if this variable is set to @code{t}. @item @ESS{[S]}: @kbd{C-c C-c} (@code{ess-eval-function-or-paragraph-and-step}) is now skipping over comments as the other paragraph functions do. It (and similar functions) should no longer wrongly find @samp{function()} beginnings inside comments or strings. @item @ESS{[SAS]}: improved by better support for GNU Emacs @end itemize Changes/New Features in 5.13: @itemize @bullet @item @ESS{[R]}: On Windows, for R 2.12.0 and later, the Rterm executables (in subdirectories i386 / x64) now are found as well as for earlier R versions. @item @ESS{[S+]}: on Windows, both 32- and 64-bit versions of S+ (``S-PLUS'') are found now and made available on the menu. @item @ESS{[R]}: When prompting for a starting directory, the R version is (always?) correct now. @item @ESS{[R]}: on non-Windows platforms, the @code{use-dialog-box} variable is no longer temporarily changed (to @code{nil} for R-x.y.z version functions and to @code{t} for @command{R} itself), but rather the user customization is obeyed. @item @ESS{[R]}: more Roxygen improvements. @item `Rd-preview-help' now generates preview buffers with navigation facilities the same as regular help buffers. @item @ESS{}: New functions and keys C-c [up] / [down] for evaluating the buffer ``from beginning till here''. @end itemize Changes/New Features in 5.12: @itemize @bullet @item @ESS{[SAS]} Font-locking: update of PROCs keywords (up to SAS 9.22); error/warnings. @item @ESS{[R]}: Roxygen improvements: S4 classes; also optionally keep spaces when filling arguments @item @ESS{[Rd]}: support new keywords: section-name \subsection plus a dozen ``new'' keywords; should match R 2.12.x now. @item @command{ess-display-help-on-object} (@kbd{C-c C-v}) now @emph{caches} the list of topics, thus speeding up the improvement feature introduced in 5.9. @end itemize Changes/New Features in 5.11: @itemize @bullet @item Filename completion within buffers now adds only trailing characters to complete the filename, rather than expanding to an absolute file path. This filename completion is bound to the TAB key. @item @kbd{M-n P} in Sweave buffers now prompts for the command to run instead of using @command{pdflatex} unconditionally, offering completion from customizable collection @code{ess-swv-pdflatex-commands}, the first of which is taken as default and that defaults to @command{texi2pdf}. @item @kbd{M-RET} is now also bound in S language (R and S+) buffers to @command{ess-use-this-dir}. It sends @code{setwd(..)} to the S process to set the working directory to the one of the source file. @end itemize Changes/New Features in 5.10: @itemize @bullet @item @kbd{M-RET} in *S* buffers is now bound to @code{ess-dirs}. This function will set Emacs's current directory to be the same as the *S* process. This is useful if you use @code{setwd()} within a *S* process. @end itemize Changes/New Features in 5.9: @itemize @bullet @item Toolbar: The toolbar now has an icon for starting Splus. @item Indentation: New documentation and code has been added to make it easier to change how ESS indents code. In particular, see @code{ess-default-style}, @code{ess-own-style-list} and the documentation subsection ``Changing indentation styles''. @item @command{ess-display-help-on-object} (@kbd{C-c C-v}) now offers completion candidates for help file aliases, in addition to object names. @item Font locking: is now turned on even without @command{window-system} is @code{nil}, whenever @var{ess-font-lock-mode} is non-nil, i.e., by default. @item @ESS{} script editing: ess-eval-deactivate-mark default is now t, as suggested by Leo Alekseyev and subsequent ``unanimous'' ESS-help discussion. @item @ESS{[R]}: Editing support for ``#!'' (Rscript / littler) editing, thanks to Jeffrey Arnold. @item @ESS{[R]}: Now finds all R versions, both 64-bit and 32-bit, on some 64-bit Windows machines. Please report back to ess-core success or failure on your 64-bit Windows machine. @item ESS Manual now more visually pleasing; @uref{https://ess.r-project.org/Manual/ess.html} @item @ESS{[R]}: Roxygen on XEmacs no longer font locks for now (as it required missing features and hence broke ESS startup, there). @item @ESS{[R]}: Roxygen has a sub-menu on the [ESS] menu. @item @ESS{[R]}: Function @command{ess-rutils-htmldocs} in @file{ess-rutils.el} offers an alternative to @code{help.start()} for navigating R documentation, using the @command{browse-url} Emacs function. @end itemize Changes/New Features in 5.8: @itemize @bullet @item @ESS{[R]}: New @file{ess-rutils.el} with utilities for listing, loading, installing, and updating packages, as well as object manipulation (listing, viewing, and deleting). It also provides an alternative to @code{RSiteSearch()} that uses the @command{browse-url} function, so results can be viewed in an Emacs web browser. @item @ESS{[R]}: much more extensive Roxygen interface, via ess-roxy.el from Henning Redestig. Ess-roxy supports filling of roxygen fields, generation and updating roxygen templates, completion of roxygen tags, basic navigation (marking and moving between entries), folding using hs-minor-mode and preview of the Rd file. @item Emacs Lisp files have got better names (partly, for now). @end itemize Changes/New Features in 5.7: @itemize @bullet @item @ESS{[R]}: loading a source file (@kbd{C-c C-l}) now works in Windows, similarly to other platforms; (further; it had accidentally been broken in ESS 5.6 on all platforms) @end itemize Changes/New Features in 5.6: @itemize @bullet @item @ESS{[R]}: help() calls have to differ from old default, with newer versions of R; currently via .help.ESS <- function(...) hack. @end itemize Changes/New Features in 5.4: @itemize @bullet @item @ESS{[SAS]}: The long overdue change from @code{make-regexp} to @code{regexp-opt} for font-locking is complete. The new @code{regexp-opt} is now the default since it is better than the old code in many ways (and especially more maintainable). However, there are certainly some special cases missed (bug reports and patches welcome!). Setting @code{ess-sas-run-regexp-opt} to @code{nil} will result in the old code being used. @item @ESS{[BUGS]} and @ESS{[JAGS]}: typing @code{=} now results in @code{<-}. @item @ESS{[R]} function arguments ``show'' @code{(ess-r-args-show)} now uses the new @code{(tooltip-show-at-point)} contributed by Erik Iverson. @item Toolbar icons now also work in (beta) Emacs 23. @item @ESS{[S]}: New function @code{ess-change-directory} for setting both emacs' current directory and the directory of an *R* or *S* buffer. @item @ESS{[S]} when transient-mark-mode is true, the mark is now kept, rather than deactivated, thanks to a patch from David Reitter. @end itemize Changes/New Features in 5.3.11: @itemize @bullet @item @ESS{[SAS]}: work around bug in Emacs 22.2 & 22.3 which fails to set case-fold fontification automatically. @item Rd mode: support new keyword 'Rdversion' @item @ESS{[R]}: now again works with Emacs 21.x @end itemize Changes/New Features in 5.3.10: @itemize @bullet @item Fixed noweb-mode bug accidentally introduced into 5.3.9 @item In noweb-mode, e.g., Rnw-mode, electric ``<'' also inserts closing ``@@". Further, the code chunk boundaries are better kept up-to-date, such that code[R] <-> text[LaTeX] minor mode switching should happen more reliably. @item In noweb-mode, fix a buglet in rare [Enter] or [Tab] behavior; further, by default disable the former `[[' .. `]]' code-protection-when-filling behavior which has been found to be buggy. @end itemize Changes/New Features in 5.3.9: @itemize @bullet @item @ESS{[SAS]}: evince PDF viewer now supported as well; search order: evince, Xpdf, Adobe/Acrobat Reader @item @ESS{[R]}: added support for Roxygen, potentially to be extended. @item @ESS{[S]} (and R): inferior (@code{*R*}) and transcript modes no longer fontify language keywords (such as @code{for}, @code{in}, etc). @item @iESS{[Stata]}: Customize the @code{ess-sta-delimiter-friendly} setting to @code{t} to convert embedded semi-colons to newlines for Stata processing. @item Sweave fix for embedded blanks in PDF reader and PDF files @item Several fixes for Major Mode Convention violations in @code{ess-mode} and @code{noweb-mode}. @item @ESS{[JAGS]}: @code{M-x comment-region} now available! @item @ESS{[S]} The @code{ess-swv-*} commands (and keybindings) are now in a submenu of the ``Noweb'' menu, when editing Sweave files. @end itemize Changes/New Features in 5.3.8: @itemize @bullet @item @ESS{[JAGS]}: more separation from @ESS{[BUGS]} (as much as is currently planned); now @kbd{C-c C-c} on an empty @file{.jmd} creates a template as it should; symbolic links are created for CODA output so BOA is happy: from @file{index.txt} to @file{.ind} and @file{chain#.txt} to @file{#.out} @item @ESS{[SAS]}: buffer-local @code{ess-sas-submit-command} and @code{ess-sas-submit-command-options} now recognized by @code{ess-sas-submit-region} @item @ESS{[S]}: When trying to evaluate code in an S language buffer and there is no associated process, now start R automatically instead of signalling an error. Also, restart R if there is an associated process which is not running. However, do not start R just via the ``electric'' @kbd{(} (@code{ess-r-args-auto-show}). @item @ESS{[S]}: For (one-line) functions withOUT '@{ .. @}' bodys, the end of function is now correctly found more often. This notably improves @kbd{C-c C-c} (@code{ess-eval-function-or-paragraph-and-step}). @item @ESS{[JAGS]}: cleanup/re-organization of Elisp code; symbolic links for CODA output are now only created by the new JAGS @code{system} command in version 1.0.3; specify whether this command is available via @code{ess-jags-system}; if not present, then no links are created so that the @code{*shell*} buffer does not become unresponsive during the batch run @end itemize Changes/New Features in 5.3.7: @itemize @bullet @item @ESS{}: @code{ess-default-style} now *is* customizable, i.e., changing its value in @file{~/.emacs} now does have the desired effect. @item @ESS{}: @code{ess-font-lock-mode} is a new variable (default: t) which controls whether font-locking is enabled in ESS buffers. @item @ESS{[R]}: for XEmacs on Windows; another tweak to find R versions @item @ESS{[SAS]}: font-locking updated for ODS and SAS Bayesian Procedures; a more consistent handling of SAS options by @code{ess-sas-submit-command-options} which is buffer-local; portable snooze for MS Windows via customize-able @code{ess-sleep-for} (floats welcome); Xpdf now supported as a PDF viewer @item @ESS{[Rnw]}: now also works with ``emacs -nw'' and Emacs 22. @item @ESS{[JAGS]}: now requires JAGS 1.0 (see the new ESS for JAGS help section for more information): both need work; suggestions welcome @item @ESS{[R]}: [TAB] completion now uses the R-internal completion mechanism (for R >= 2.5.0). @item @ESS{[R], [S]}: interpretation of ``_'' as assignment has been removed in @code{ess-continued-statement-p} for R and S. @item several internal code cleanups. @item @ESS{[R]}: An experimental version of a new command @code{Rgui} on MS Windows to send lines directly from emacs to @code{Rgui} is available in file @code{lisp/essd-rgui.el}. Preliminary documentation is in file @code{doc/rgui-doc.txt}. @end itemize Changes/New Features in 5.3.6: @itemize @bullet @item @ESS{}: for XEmacs, using ``gnuclient'' (without a ``-q'') works for things like fix() after M-x gnuserv-start has been done. @item @ESS{[R]}: M-x R-newest should now work in more situations on MS Windows, e.g., when R has been installed in a non-default "ProgramFiles" directory tree. In these cases, there's no need to specify the name (and full path) of the R program anymore. @item @ESS{[R]}: For XEmacs, startup (with new tooltip code) works again. @end itemize Changes/New Features in 5.3.5: @itemize @bullet @item @ESS{[R]} a new defun is available, @kbd{M-x R-newest}, which will start the newest version of R that it can find on your system. @item @ESS{[R]} add Sven Hartenstein's ``R function arguments tips'' functionality, via new file @file{../lisp/essd-r-args.el}. Note that this includes an ``electric "("'' behavior inside @code{R-mode} which is @emph{active by default} and can be customized via @code{ess-r-args-electric-paren}; i.e., use @code{(setq ess-r-args-electric-paren nil)} to turn it off. Further, @code{ess-r-args-show-as} allows to switch to the ``tooltip'' mode. @item @ESS{}: functions @code{ess-get-pdf-viewer} and *-ps-viewer; built on new customizable variables @code{ess-pdf-viewer-pref} and @code{ess-ps-viewer-pref}; currently used in @code{ess-swv-PDF} and @code{*-PS}. @item @ESS{[R]} Improved @code{ess-swv-PDF} to run pdf viewer only if pdflatex was ok @item @ESS{[R]} Improved @code{ess-swv-weave} to start R automatically if none is running. @item @ESS{}: Do no longer ask @emph{which} ESS process to use if there is only one. @end itemize Changes/New Features in 5.3.4: @itemize @bullet @item @ESS{[R]} now better work with options(error=recover); and the new default of CHM help files on windows. @item @ESS{[R]} some more cleanup in the ``sweave'' functions @item miscellaneous fixes @end itemize Changes/New Features in 5.3.3: @itemize @bullet @item @ESS{[S]} fix buglet (5.3.2 only) which left command prompt in ``execute buffer'' and hence help files. @item new customizable variable @code{ess-display-buffer-reuse-frames} set to true (which changes default behavior) such that execution or help *frames* are reused. @end itemize Changes/New Features in 5.3.2: @itemize @bullet @item Classic BUGS now supported by @code{(require 'essd-bugs)} with @ESS{[BUGS]} and JAGS by @code{(require 'essd-jags)} with @ESS{[JAGS]}. But, only one of them can be used at a time since they don't play nice together. Also, @kbd{C-c C-c} is now bound to the function @code{ess-bugs-next-action} (@kbd{F12} has been retired). And finally, note that @file{essl-bug.el} is deprecated and the replacement is @file{essl-bugs.el}. @item @ESS{[R]} Improved some of the ``Sweave-make'' functions (yet scarcely documented) in @file{ess-swv.el}. @item @ESS{[S]} No longer mess with .Last.value (nor in other ``languages''). @end itemize Changes/New Features in 5.3.1: @itemize @bullet @item See the docs for 2 ways to install @ESS{} for XEmacs @enumerate @item by uncommenting the XEmacs part of Section 1 of @file{Makeconf} and performing @code{make install} @item by unpacking either @file{ess-5.3.1.tgz} or @file{ess-5.3.1.zip} into @file{PREFIX/lib/xemacs/site-packages} on unix or @file{PREFIX\XEmacs\site-packages} on windows @end enumerate @item @ESS{[R]}: fixed bugs so that Rterm.exe can be found by XEmacs @item @ESS{[S]}: @kbd{ess-toggle-S-assign-key} is slightly changed; in particular, the default @code{ess-assign-key} is now @kbd{C-x =}. @item @ESS{[R]}: @kbd{M-x R-site-search} is a new (slightly experimental) utility similar to R's @code{RSiteSearch(..)} but with the advantage of using Emacs' preferred browser, see @code{browse-url-browser-function} @end itemize Changes/New Features in 5.3.0: @itemize @bullet @item @ESS{[BUGS]}: sanely re-format statistical output, @file{.bog}, from scientific notation to numbers rounded with 4 decimal places with @kbd{M-x ess-bugs-sci-round-to-4-dp}. @item The keys for navigating among section headings in help buffers worked, but only for one language per session; they should now work for multiple languages. (They were also broken on Windows machines.) @item @ESS{[S]} long standing buglets in the internal logic for loading Lisp code on Windows. Particularly fixed behavior in help mode with S-plus GUI. @item New variable, @code{ess-use-inferior-program-name-in-buffer-name}, which enables using the executable name instead of the dialect name for R. Feature request. @item @ESS{[S]} @kbd{ess-execute-screen-options} now also works correctly when there is more than one window *side-by-side* in the same frame and runs in the correct buffer also when there is more than one S buffer. @item @iESS{[S]} new functions @code{ess-eval-paragraph-and-step} and @code{ess-eval-function-or-paragraph-and-step} are bound to keys @kbd{C-c C-p} and @kbd{C-c C-c} respectively and to the menu in @ESS{}-mode; also bound in the help mode (for evaluating examples). @item @ESS{[S]} new function @code{ess-toggle-S-assign-key} allows to assign the `` <- '' insertion to an arbitrary key. @end itemize Changes/New Features in 5.2.12: @itemize @bullet @item @ESS{[SAS]}: @kbd{M-;} fixed, but the XEmacs function @code{comment-dwim} may be broken, if so, use @kbd{M-x comment-region} and @kbd{M-x uncomment-region} instead; only valid PROCs are fontified which is very helpful finding syntax errors (currently supported: BASE, ETS, FSP, GRAPH, IML, INSIGHT and STAT); the ``feature'' where @kbd{F}-keys take you to an empty buffer when the requested destination is a file that does not exist has been fixed, now the request results in a no-op. Further, sas-mode now also works in simple terminals. @item Rterm/Cygwin combination works under Microsoft Windows. @item @ESS{[R]}: internal calls use baseenv() instead of NULL and define 'baseenv' where needed. @item New experimental support for installing ESS. See the file @file{lisp/ess-install.el}. @end itemize Changes/New Features in 5.2.11: @itemize @bullet @item ESS Info entry and @file{dir} handled more effectively for GNU Emacs users @item @ESS{[SAS]}: temporary files created for batch submission of a region are now named based on the current file; see @code{ess-sas-file-root} for details; all @code{lag} and @code{dif} functions now fontified correctly @item iESS[SAS]: fixed a few nagging bugs, however, still does not appear to work at this time; please let us know if you have any ideas. @item @ESS{[S]}: Support for running other versions of Splus has been added for unix. Two new variables, @code{ess-s-versions} and @code{ess-s-versions-list}, are used to tell ESS what other versions of Splus you would like to run. @end itemize Changes/New Features in 5.2.10: @itemize @bullet @item @ESS{[R]}: ess-r-versions can no longer be customized (since the customization was not taking effect unless customizations were loaded before ESS). Its value has been changed so that it will also find R executables beginning ``R-devel'' and ``R-patched''. If you wish to change this variable, it must be set in your @file{.emacs} before ESS is loaded. @item Installation with GNU Make enhanced: unix and unix-like operating systems will now be able to install @ESS{} for all users in either a GNU Emacs site-lisp or an XEmacs package configuration by editing @file{lisp/ess-site.el} and @file{Makeconf} accordingly, then issuing @code{make install} @item @ESS{[S]}: Filename completion (inside strings) now also works in XEmacs for R and S-plus. @c working around a bug in XEmacs @end itemize Changes/New Features in 5.2.9: @itemize @bullet @item @ESS{[R]} for Windows: the \ directory character bug with respect to ess-load-file has been eradicated. @item @iESS{[SAS]}: @kbd{C-c C-r} and @kbd{C-c C-b} once again work as intended and documented. @item @ESS{[S]}: M-x ess-fix-EQ-assign is a bit more aggressive. @item @ESS{[S]}: Imenu now also shows setAs(), etc. @item @ESS{[R]}: R function pattern enhanced with underlying code such that @kbd{M-C-a} (@code{ess-beginning-of-function}) etc now work for many more cases, including S4 method definitions. @item @iESS{[R]}: myOwnhelp(1) no longer wrongly triggers help(1). @item @ESS{[R]}: Improved detection of bogus help buffers: valid help buffers containing with the string ``no documentation''(e.g. contour) were being treated as bogus. @item @ESS{[R]}: In R help buffers, if @code{options("help.try.all.packages" = TRUE)} then @code{?rlm} will list which packages rlm is defined in. This help buffer is not bogus, but instead is now relabelled ``*help[R](rlm in packages)*''. @item @ESS{[STA]}: add ``//'' as comment starting character to syntax-table. @end itemize Changes/New Features in 5.2.8: @itemize @bullet @item iESS: [Tab] completes @strong{file} names ``inside string'' as in earlier (<= 5.2.3) ESS versions. @end itemize Changes/New Features in 5.2.7: @itemize @bullet @item If you use Custom to change the variable ess-toolbar-items, the new toolbar is used in all subsequent ESS buffers. @item @ESS{[SAS]}: new feature: if ess-sas-log-max >0 and your .log grows to more than ess-sas-log-max bytes, just the first ess-sas-log-max bytes are refreshed; this is helpful when your .sas program generates lots of error messages and gets too big for emacs to display @item @ESS{[R/S]}: @kbd{M-;} in R/S editing modes will now indent with either one or two hashes depending on context. @item @ESS{[R]}: David Whiting's Sweave extensions (to 'noweb') are now available (from ess-swv.el loaded by default). @end itemize Changes/New Features in 5.2.6: @itemize @bullet @item Removed non-ASCII characters in a few files. @item @ESS{[R]}: now works better when UTF-8 locale is active; in particular, you get correct directional quotes in R's startup message for R-devel (unstable development version of R 2.1.0) when using environment variables LANGUAGE=en@@quot LC_ALL=en_US.UTF-8 @item @ESS{[SAS]}: toggling of .log mode improved (@kbd{F10}); toggling of .lst mode now also available (@kbd{C-F10}); killing all buffers associated with .sas program no longer bound to @kbd{C-F10} since its a bit overzealous. @item S-Plus 7 for Windows is now recognized. @item @ESS{[S]} (incl.@: R): in auto-fill mode, strings are not wrapped anymore. @item @ESS{[S]} (incl.@: R): font-lock now correctly differs between R and S, e.g., for "_"; both now fontify warning(.) and S does terminate() additionally. @item Support for `bell' aka `beep' aka `ding' aka `alarm' in all inferior modes: When \a is output ``to the the console'' at the beginning of a line, the bell is rung. @end itemize Changes/New Features in 5.2.5: @itemize @bullet @item @ESS{[R]}: @kbd{C-c C-q} or @samp{Quit S} from the menu now should work (again and less klunkily) and do not append @samp{-exited} to the buffer name. Further, the behavior of @code{(ess-cleanup)}, called from ess-quit, now depends on the new customizable variable @code{ess-S-quit-kill-buffers-p} which defaults to @code{nil}. Consequently, the question @emph{``Delete all buffers associated with ..?''} will not be asked anymore by default. @item @ESS{[SAS]} -- ess-ebcdic-to-ascii-search-and-replace will now work with the @code{recode} application as well which is available on many platforms @item @ESS{[S]} (incl.@: R): Name completion for slots of S4 objects now works! @end itemize Changes/New Features in 5.2.4: @itemize @bullet @item The documentation now includes an overview of how to use the emacs TAGS facility for S functions. (The distribution also used to contain a directory @file{etc/other/Tags} where a ~1990 version of @file{etags.c} was distributed; this is no longer relevant and so has been deleted.) @item @ESS{[SAS]} -- When you are working with EBCDIC files on an ASCII platform, .log NOTEs may display as gibberish since the EBCDIC characters are not converted to ASCII prior to their display. So, the function ess-ebcdic-to-ascii-search-and-replace is provided for convenience and is bound to @kbd{C-F11}. This function requires the @code{dd} command (only available on unix or unix-like platforms). @item ESS: Completion of object names is now always done dynamically rather than allowing the option of using a pre-computed database (by @code{ess-create-object-name-db}) since modern computers seem fast enough for dynamic completion. (We expect few users, if any, have been using the pre-computed database method.) @item ESS: object completion in iESS buffers running on Windows was very slow (for GNU Emacs, but not XEmacs) and has now been fixed. Further, it was more or less broken for all versions of S-plus 6.x, and has been fixed to work everywhere but with the Windows' GUI of S-plus. The list of objects now shows unique names also when an object appears more than once in the search path. @item @ESS{[R]}: Completion of object names now also includes those starting with ``.''. @end itemize Changes/New Features in 5.2.3: @itemize @bullet @item ESS: When new inferior ESS processes are created, by default they will replace the current buffer (this restores behavior from pre 5.2.0). If you wish new ESS processes to start in another window of the current frame, set inferior-ess-same-window to nil. @item New variables inferior-Splus-args and inferior-R-args provide a way to pass command line arguments to starting S and R processes. @end itemize Changes/New Features in 5.2.2: @itemize @bullet @item bug-fixes for 5.2.1 (require 'executable), html docs, etc. @item ess-lisp-directory/../doc/info added to Info-directory-list if ess-info not found by info @item @ESS{[R]}: If you have other versions of R on your exec-path, such as "R-1.8.1" with Unix or "rw1081" with Windows, ESS will find them and create appropriate functions, such as @kbd{M-x R-1.8.1} or @kbd{M-x rw1081}, for calling them. By default only Unix programs beginning "R-1" and "R-2" and Windows programs parallel to the version of R in your exec-path will be found, but see ess-r-versions and ess-rterm-versions for ways to find other versions of R. @item @ESS{[R]}: Other versions of R, such as "R-1.8.1" on Unix and "rw1081" on Windows, are added to the "ESS / Start Process / Other" menu. @item @ESS{[S]}: If you have other versions of S-Plus on your Windows computer, such as S-Plus 6.1 or S-Plus 4.5, ESS will find them and create appropriate functions, such as @kbd{M-x splus61}, for calling the console version (Sqpe) inside an emacs buffer. By default only programs installed in the default location will be found, but see ess-SHOME-versions for ways to find other versions of S-Plus. @item @ESS{[S]}: Other versions of Sqpe on Windows, such as "splus61", are added to the "ESS / Start Process / Other" menu. @item @ESS{[R]}: (bug fix) ess-quit (bound to @kbd{C-c C-q}) should now quit the inferior R process, when issued from either the inferior buffer, or from a .R buffer. @end itemize Changes/New Features in 5.2.1: @itemize @bullet @item @ESS{[S]} (R and S-plus): now have toolbar support with icons to evaluate code in the inferior process or to switch there. This code is experimental and likely to change as XEmacs/Emacs issues get resolved. The toolbar should be enabled if your Emacs displays images, but can be disabled with the variable ess-use-toolbar. Thanks to David Smith from Insightful for the S-plus logo. @item @ESS{[SAS]}: ess-sas-graph-view (@kbd{F12}) enhanced; you can specify external file viewers for each graphics file type via the alist ess-sas-graph-view-viewer-alist; also .jpg/.gif are now handled by image-mode on XEmacs, if available, otherwise by graphics primitives as before @end itemize Changes/New Features in 5.2.0: @itemize @bullet @item @ESS{[BUGS]}: new info documentation! now supports interactive processing thanks to @uref{mailto:Aki.Vehtari@@hut.fi, Aki Vehtari}; new architecture-independent unix support as well as support for BUGS v. 0.5 @item @ESS{[SAS]}: convert .log to .sas with ess-sas-transcript; info documentation improved; Local Variable bug fixes; SAS/IML statements/functions now highlighted; files edited remotely by ange-ftp/EFS/tramp are recognized and pressing SUBMIT opens a buffer on the remote host via the local variable ess-sas-shell-buffer-remote-init which defaults to "ssh"; changed the definition of the variable ess-sas-edit-keys-toggle to boolean rather than 0/1; added the function ess-electric-run-semicolon which automatically reverse indents lines containing only "run;"; @kbd{C-F1} creates MS RTF portrait from the current buffer; @kbd{C-F2} creates MS RTF landscape from the current buffer; @kbd{C-F9} opens a SAS DATASET with PROC INSIGHT rather than PROC FSVIEW; "inferior" aliases for SAS batch: @kbd{C-c C-r} for submit region, @kbd{C-c C-b} for submit buffer, @kbd{C-c C-x} for goto .log; @kbd{C-c C-y} for goto .lst @item @ESS{[S]}: Pressing underscore ("_") once inserts " <- " (as before); pressing underscore twice inserts a literal underscore. To stop this smart behaviour, add "(ess-toggle-underscore nil)" to your .emacs after ess-site has been loaded; ess-dump-filename-template-proto (new name!) now can be customized successfully (for S language dialects); Support for Imenu has been improved; set ess-imenu-use-S to non-nil to get an "Imenu-S" item on your menubar; ess-help: Now using nice underlines (instead of `nuke-* ^H_') @item @ESS{[R]}: After (require 'essa-r), @kbd{M-x ess-r-var} allows to load numbers from any Emacs buffer into an existing *R* process; @kbd{M-x ess-rdired} gives a ``directory editor'' of R objects; fixed ess-retr-lastvalue-command, i.e. .Last.value bug (thanks to David Brahm) @item ESS: Support for creating new window frames has been added to ESS. Inferior ESS processes can be created in dedicated frames by setting inferior-ess-own-frame to t. ESS help buffers can also open in new frames; see the documentation for ess-help-own-frame for details. (Thanks to Kevin Rodgers for contributing code.) @end itemize Changes/New Features in 5.1.24: @itemize @bullet @item The version number is now correct even inside ESS/Emacs @end itemize Changes/New Features in 5.1.23: @itemize @bullet @item Minor more Makefile clean up. @end itemize Changes/New Features in 5.1.22: @itemize @bullet @item Besides info documentation, PDF and HTML documentation are also provided (instead of built using "make") and available on the web as well; see @uref{https://ess.r-project.org/, ESS web page} and @uref{http://lib.stat.cmu.edu/general/ESS/doc, StatLib} @item Now that info documentation is available, the README.* files are no longer supported. However, they are still distributed for what it's worth. @item ESS is now an XEmacs package! See @uref{https://www.xemacs.org/Install/index.html, XEmacs Installation HOWTO} for details (specifically, items 10-15). @item @ESS{[SAS]}: more user-friendly enhancements for remote SAS batch jobs with Kermit file transfers (LOG and OUTPUT function key features now supported). Multiple shells now supported so you can run SAS on different computers from different buffers by setting the buffer-local variable ess-sas-shell-buffer to unique buffer names. @item Major re-vamping of Makefile/Makeconf. @end itemize Changes/New Features in 5.1.21: @itemize @bullet @item @ESS{[SAS]}: info documentation now available!, see ESS->Help for SAS; @kbd{F12} opens GSASFILE nearest point for viewing either within emacs, when available, or via an external viewer; more syntax highlighting keywords; more enhancements for remote SAS batch jobs with Kermit; new framework for remote SAS interactive jobs, see ess-remote @item @ESS{[S]}: info documentation now available!, see ESS->Help for the S family @item Makefile: tag now independent of rel; info files made by doc/Makefile and installed in new info sub-directory @end itemize Changes/New Features in 5.1.20: @itemize @bullet @item New `options()$STERM' in the S dialects (S, S-Plus, R). The S program can determine the environment in which it is currently running. ESS sets the option to `iESS' or `ddeESS' when it starts an S language process. We recommend other specific values for S language processes that ESS does not start. @item New `ess-mouse-me' function, assigned to S-mouse-3 by default. User may click on a word or region and then choose from the menu to display the item, or a summary, or a plot, etc. This feature is still under development. @item GNU Emacs 21.1 is now supported (fixed for S dialects, SAS & BUGS), (some from Stephen Eglen). @item XEmacs 21.x is now supported (fixed w32-using-nt bug) @item XEmacs on Win (NT) is better supported. @item Workaround for bug in Sqpe+6 (S-PLUS 6 for Win). @item should now work even when imenu is not available (for old XEmacsen). @item @ESS{[SAS]}: XEmacs-Imenu fix; @kbd{C-TAB} is globalized along with your function-key definitions, if specified; you can specify your SAS library definitions outside of autoexec.sas for ess-sas-data-view with SAS code placed in the variable ess-sas-data-view-libname, also the dataset name is defaulted to the nearest permanent dataset to point; Speedbar support now works for permanent datasets, please ignore first./last.; new font-locking is now the default with more improvements for font-locking PROCs, macro statements, * ; and %* ; comments; you can toggle sas-log-mode with @kbd{F10} which will font-lock your .log (if it isn't too big); submit remote .sas files accessed with ange-ftp, EFS or Tramp (Kermit is experimental) by setting ess-sas-submit-method to 'sh; ess-sas-submit-command and ess-sas-submit-command-options are buffer-local so you can have local file variable sections at the end of your .sas files to request different executables or specify special options and the local file variables are re-read at submit instead of only at file open so that if you make a change it is picked up immediately; @item @ESS{[BUGS]}: font-lock with `in' fixed. @item for STATA: font-lock bug fixed. @item for Rd mode: @kbd{C-c C-v} and `switch-process' in menu. further, @kbd{C-c C-f} prefix (Rd-font) for inserting or surrounding a word by things such as \code@{.@}, \code@{\link@{.@}@}, \emph@{.@} etc. @item new functions (ess-directory-function) and (ess-narrow-to-defun) ess-directory <-> default-directory logic (Jeff Mincy). @item Re-organized Makefile and fixed a few bugs. @end itemize Changes/New Features in 5.1.19: @itemize @bullet @item S+6 now supported (Tony Rossini (Unix) and Rich Heiberger (Windows)) @item New BUGS support through @ESS{[BUGS]} mode (Rodney Sparapani) Templates assist you in writing .bug and .cmd code (.cmd and .log are replaced by .bmd and .bog to avoid emacs extension collisions). Substitution" parameters facilitate "automagic" generation of data...in" and "init...in" filenames, "const N=" from your data file and "monitor()/stats()" commands. Activated by pressing @kbd{F12}. @item Fixes for `ess-smart-underscore' SAS breakage (Rich Heiberger) @item You can change between PC and Unix, local and global SAS function-key definitions interactively (Rich Heiberger) @item @kbd{C-Submit} a highlighted region to SAS batch (Rodney Sparapani) @item New and improved SAS syntax highlighting (Rodney Sparapani) To get the new functionality, set ess-sas-run-make-regexp to nil. Also available in .log files via @kbd{F10}. @item Open a permanent SAS dataset for viewing via @kbd{F9} (Rodney Sparapani) You must have the library defined in autoexec.sas for it to work. @item User-friendly defaults for `sas-program', `ess-sas-batch-pre-command' and `ess-sas-batch-post-command' as well Customize support for these and other @ESS{[SAS]} variables (Rodney Sparapani) @item `ess-sas-suffix-2' now defaults to .dat via @kbd{F11} (Rodney Sparapani) @item Emacs/XEmacs, Unix/Windows issues collectively handled in ess-emcs.el @item defadvice solves problem of missing *ESS* (thanks to Jeff Mincy) @item Improved manual a bit by including things that were only in `README'. @end itemize Changes/New Features in 5.1.18: @itemize @bullet @item New `ess-smart-underscore' function, now assigned to "_" by default. Inserts `ess-S-assign' (customizable " <- "), unless inside string and comments where plain "_" is used instead. (MM) @item Fixes for longstanding interactive SAS breakage (RMH) @end itemize Changes/New Features in 5.1.17: @itemize @bullet @item Documentation for Windows Installation (Rich Heiberger) @item removal of ess-vars, finalization of customize support (in the sense that there is no more use of ess-vars, but that we need to fix ess-cust) (AJ Rossini) @item Many small (and large) fixes/contributions (MMaechler) @item addition of the "S-equal" variable and provide @kbd{M-x ess-add-MM-keys} a way to remap "_" to `ess-S-assign', typically " <- ", but customizable. (MMaechler) @end itemize Changes/New Features in 5.1.16: @itemize @bullet @item BUG FIXES @item Better SAS support @end itemize Changes/New Features in 5.1.15: @itemize @bullet @item BUG FIXES @end itemize Changes/New Features in 5.1.14: @itemize @bullet @item Yet more fixes to SAS mode, (Rich Heiberger and Rodney Sparapani) @item Customize support (for most Emacsen which support it) (AJRossini) @item ARC and ViSta support out of the box, and fixes for XLispStat (AJRossini) @end itemize Changes/New Features in 5.1.13: @itemize @bullet @item Version numbering finally all depending on the ./VERSION file, thanks to Martin Maechler. @item Yet more fixes to SAS mode, thanks to Rich Heiberger. @end itemize Changes/New Features in 5.1.12: @itemize @bullet @item Splus 5.1 stabilized, thanks to Martin Maechler, Bill Venables, Chuck Taylor, and others. @item More fixes to SAS mode, thanks to Rodney Sparapani and Rich Heiberger. @end itemize Changes/New Features in 5.1.11: @itemize @bullet @item More fixes to Stata mode, thanks to @uref{mailto:brendan@@essex.ac.uk, Brendan Halpin}. @item fixed bugs in ESS-elsewhere, thanks to many testers @item README.SPLUS4WIN has DETAILED instructions for S-PLUS 2000, thanks to @uref{mailto:brahm@@alum.mit.edu, David Brahm}. @item Fixes to SAS mode, thanks to Rodney Sparapani @end itemize Changes/New Features in 5.1.10: @itemize @bullet @item More fixes to Stata mode @item primitive generic version of ESS-elsewhere @item Small fixes to SAS/Stata. @end itemize Changes/New Features in 5.1.9: @itemize @bullet @item Stata mode works @item Literate Data Analysis using Noweb works @end itemize Changes/New Features in 5.1.8: @itemize @bullet @item Bug fixes @item R documentation mode defaults changed @end itemize Changes/New Features in 5.1.2: @itemize @bullet @item able to use inferior iESS mode to communicate directly with a running S-Plus 4.x process using the Microsoft DDE protocol. We use the familiar (from Unix ESS) @kbd{C-c C-n} and related key sequences to send lines from the S-mode file to the inferior S process. We continue to edit S input files in @ESS{[S]} mode and transcripts of previous S sessions in ESS Transcript mode. All three modes know the S language, syntax, and indentation patterns and provide the syntactic highlighting that eases the programming tasks. @end itemize @comment @end itemize ESS-24.01.1/doc/onews.texi000066400000000000000000000000571455642170100151130ustar00rootroot00000000000000 @include ess-defs.texi @include onewfeat.texi ESS-24.01.1/doc/readme.texi000066400000000000000000000066421455642170100152230ustar00rootroot00000000000000\input texinfo @c -*-texinfo-*- @comment %**start of header @setfilename readme.info @settitle ESS - Emacs Speaks Statistics @comment %**end of header @include ess-defs.texi @node General Information @chapter General Information: README @cindex README This is the README file for the distribution of ESS version @include ../VERSION ESS is a GNU Emacs package for interactive statistical programming and data analysis. Languages supported: the S family (S, S-PLUS and R), SAS, BUGS/JAGS and Stata. ESS grew out of the desire for bug fixes and extensions to S-mode and SAS-mode as well as a consistent union of their features in one package. Installation instructions are provided in sections for both Unix and Windows; see below. The current development team is led by Martin Maechler since August 2004. Former project leader A.J. (Tony) Rossini (@email{rossini@@blindglobe.net}) did the initial port to XEmacs and has been the primary coder. Martin Maechler (@email{maechler@@stat.math.ethz.ch}) and Kurt Hornik (@email{Kurt.Hornik@@R-project.org}) have assisted with the S family and XLispStat. Stephen Eglen (@email{stephen@@gnu.org}) has worked mostly on R support. Richard M. Heiberger (@email{rmh@@temple.edu}) has assisted with S/S-PLUS development for Windows. Richard and Rodney A. Sparapani (@email{rsparapa@@mcw.edu}) have done much of the work improving SAS batch and interactive support. Rodney has also extended ESS to support BUGS/JAGS and has an interest in improving Stata support. We are grateful to the previous developers of S-mode (Doug Bates, Ed Kademan, Frank Ritter, David M. Smith), SAS-mode (Tom Cook) and Stata-mode (Thomas Lumley). @c The name is ESS. Not ESS-mode. @ifplaintext Table of Contents @itemize @bullet @item License @item Stability @item Requirements @item Latest Version @item Installation @item Starting an ESS Process @item New Features @item Current Features @item Reporting Bugs @item Mailing Lists @item Authors @end itemize @end ifplaintext @menu * License:: * Installation:: * Starting up:: * Current Features:: * New Features:: * Reporting Bugs:: * Mailing Lists:: * Authors:: @end menu @node License, Installation, General Information, General Information @section License @include license.texi @node Installation, Starting up, License, General Information @section Installation @include installation.texi @node Starting up, Current Features, Installation, General Information @section Starting an ESS process To start an @Sl{} session on Unix or on Windows when you use the Cygwin bash shell, simply type @kbd{M-x S RET}. To start an @Sl{} session on Windows when you use the MSDOS prompt shell, simply type @kbd{M-x S+6-msdos RET}. @node Current Features, New Features, Starting up, General Information @section Current Features @include currfeat.texi @node New Features, Reporting Bugs, Current Features, General Information @section New Features @include newfeat.texi @node Reporting Bugs, Mailing Lists, New Features, General Information @section Reporting Bugs @include bugrept.texi @node Mailing Lists, Authors, Reporting Bugs, General Information @section Mailing Lists @include mailing.texi @node Authors, , Mailing Lists, General Information @section Authors @include authors.texi @bye @c Remember to delete these lines before creating the info file. @iftex @lucidbook @bindingoffset = 0.5in @parindent = 0pt @end iftex @comment Local Variables: @comment TeX-master: "readme.texi" @comment End: ESS-24.01.1/doc/refcard/000077500000000000000000000000001455642170100144715ustar00rootroot00000000000000ESS-24.01.1/doc/refcard/refcard.tex000066400000000000000000000306111455642170100166220ustar00rootroot00000000000000\documentclass[a4paper]{article} \usepackage{multicol} \usepackage{parskip} \usepackage{verbatim} \usepackage{fullpage}% +- ok for paper 'A4' as well \usepackage{textcomp}% added from \textasciigrave %\usepackage{svn}% and {fullpage} are both in debian/ubuntu pkg 'texlive-latex-extra' \addtolength{\textheight}{20mm} \addtolength{\topmargin}{-16mm} \newenvironment{tabI}{\begin{tabular}{p{18mm}l}}{\end{tabular}} \newenvironment{tabTit}[1]{\underline{\textbf{#1}}\\ \begin{tabI}}{\end{tabI}} % \newcommand{\Sect}[1]{\par\noindent\medskip\fbox{\large\textbf{#1}} \vskip -.2ex plus 1ex minus 1ex} \newcommand*{\Ecmd}[1]{$\left\langle \textrm{#1} \right\rangle$} \newcommand*{\sEcmd}[1]{{\small\Ecmd{#1}}} \newcommand*{\RET}[0]{\Ecmd{\textsc{ret}}} \newcommand*{\TAB}[0]{\Ecmd{\textsc{tab}}} \raggedcolumns%\raggedbottom \setlength{\columnseprule}{.4pt}% default 0 \setlength{\columnsep}{22pt}% default is less (18 pt?) \pagestyle{empty} \begin{document} %\SVN $Date$ %\begin{multicols}{1} \begin{center} {\LARGE ESS \ \ \ \ {\large [\textbf{E}macs \textbf{S}peaks \textbf{Statistics}]} \\[.5ex] Reference Card for S and R} \smallskip {\small updated for ESS 18.10-3}% {\footnotesize --- needs \em{more} updating!}} \\[1ex] {\tiny June 2019} % \footnotesize --- as of \today \end{center} % takes a lot of space % \begin{enumerate} % \item \textsc{Nota Bene:} S is the \emph{language}, % R is one \emph{dialect}! % \item This is a list of the more widely used \textbf{key - shortcuts}. % Many more are available, and most are accessible from the Emacs % \textbf{Menus} such as \texttt{iESS}, \texttt{ESS}, etc. % %NN \vspace*{-3ex} % \end{enumerate} %\end{multicols} %NN \rule{\textwidth}{.2pt}%---------------------------------------------------- \begin{multicols}{2} \Sect{Interacting with the process} %% ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ For use in a process buffer ({\texttt{inferior-ess-mode}}): \begin{tabI} \texttt{\RET } & Send a command\\ \texttt{C-c \RET} & Copy old input\\ \texttt{\TAB}& Complete object or file name\\ %& Also bound to \texttt{M-\TAB}, \texttt{M-C-i}.\\ % seems to be obsolete \texttt{C-c C-c }& Break \\ \texttt{C-g} & interrupt Emacs' waiting for S\\ %% SfS-only (others need C-u C-a for comint-bol ! \texttt{C-a} / \texttt{C-e} & Beginning / End of command \\ \texttt{C-c C-u }& Delete this command \\ \texttt{C-c C-w }& Delete last word \\ % \texttt{M-C-r }& String search \texttt{C-c C-r }& Top of last output \\ \texttt{C-c C-o }& Delete last output \\ \texttt{C-c C-n}& Next \hspace{1.4em} prompt \\ % moved from Transcript section \texttt{C-c C-p}& Previous prompt \\ % moved from Transcript section \end{tabI} \begin{tabTit}{Command history (part of Menu `\texttt{In/Out}')} \texttt{M-p }& Previous command \\ \texttt{M-n }& Next \hspace{1.4em} command \\ \texttt{C-c C-l}& List command history (\& choose!)\\ %% MM has these on the arrow keys: \texttt{C-c M-r}& Previous similar command \\ \texttt{C-c M-s}& Next \hspace{1.4em} similar command \\ %% MM-only: %%- \texttt{$\uparrow$ / \Ecmd{up}} %%- & Previous similar command \\ %%- \texttt{\hbox{$\downarrow$ / \sEcmd{down}}} %%- & Next \hspace{1.4em} similar command \\ \end{tabTit} %% == ESS-transcript mode ?? --- %\begin{tabTit}{Viewing the transcript} % \texttt{M-P }& Move to last command \\ % \texttt{M-N }& Move to next command \\ % \texttt{C-c C-b }& String search and move \\ % \texttt{C-c C-v }& Prompt at bottom of screen \\ %\end{tabTit} \begin{tabTit}{Others} \texttt{C-c C-v }& Help for object \\ \texttt{C-c M-l }& \textbf{L}oad source file \\%{\small ($+$ error check!)} \texttt{C-c C-x }& List objects \\ \texttt{C-c C-s }& Display \texttt{\textbf{s}earch} list \\ % \texttt{C-c C-a }& \textbf{A}ttach a directory \\ % \texttt{C-c C-d }& Edit an object {\small (\textbf{d}ump to file)}\\ % \texttt{C-c ` }& Jump to error after \texttt{C-c C-l}\\ % &\hspace{-1.5cm}In tracebug works for all errors (aka \texttt{C-x `})\\ % \texttt{C-c C-t }& Toggle Tek mode \\ \texttt{C-c C-q }& Quit from S \\ \texttt{C-c C-z }& Switch to most recent script buffer % \texttt{C-c C-z }& Kill the S process \end{tabTit}\\[0.5cm] \Sect{Inside ESS Transcripts (I + O)} %% ~~~~~~~~~~~~~~~~ Inside \texttt{*.Rout} files: \begin{tabI} \texttt{M-\RET} & Send current line \\ \texttt{\RET} & Send and move to next line \\ \texttt{C-\RET} & Copy current line into ESS buffer \\ \texttt{C-c C-w}& Clean Region ($\mapsto$ input only) \end{tabI}\\[0.5cm] \Sect{Sweave} \begin{tabI} \texttt{M-n s} & Sweave the file\\ \texttt{M-n l} & Run latex\\ \texttt{M-n p} & Postscript file\\ \texttt{M-n P} & PDF file\\ \end{tabI} \columnbreak %%%%%%%%%%================================================================ \Sect{Editing source files} %% ~~~~~~~~~~~~~~~~ For use in \texttt{ess-mode} edit buffers, (\texttt{*.R} files): \begin{tabI} \texttt{\TAB} & Indent this line \\ \texttt{M-\TAB} & Complete filename/object\\ \texttt{M-C-/} & Indent region\\ \texttt{M-C-q} & Indent this expression (use at `\texttt{\{}')\\ % \texttt{C-c\TAB}& Complete S object name \\ % \texttt{M-\TAB} & Complete file- / path- name \\ \texttt{M-C-a} & Beginning of function \\ \texttt{M-C-e} & End of function \\ \texttt{M-C-h} & Mark this function\\ \texttt{\scriptsize C-u C-u} \texttt{C-y}& Yank striped commands\\ \end{tabI} \begin{tabTit}{Evaluation commands (Prefix \texttt{C-u}: \emph{in/visibly})} \texttt{M-C-x} & Evaluate region or function or para \\ \texttt{C-c C-c} & Evaluate region or para.\ or function \&\emph{ step}\\ \texttt{C-\RET} & Evaluate region or line \&\emph{ step} \\ \texttt{C-c C-l} & Load this buffer's source file\\ \texttt{C-c C-j} & Evaluate this line \\ \texttt{C-c M-j} & Evaluate this line and go \\ \texttt{C-c C-f} & Evaluate this function \\ \texttt{C-c M-f} & Evaluate this function and go \\ \texttt{C-c C-p} & Evaluate this paragraph and step \\ \texttt{C-c C-r} & Evaluate this region \\ \texttt{C-c M-r} & Evaluate this region and go \\ \texttt{C-c C-b} & Evaluate this buffer \\ \texttt{C-c M-b} & Evaluate this buffer and go \\ \end{tabTit} \begin{tabTit}{Others} %%-SfS-deleted: \texttt{M-\TAB} & Complete S object name \\ \texttt{C-c C-v }& Help for object \\ % \texttt{C-c h }& Handy commands \\ % \texttt{C-c C-d }& ``\texttt{dump}'' -- Edit another object \\ %%\texttt{C-c C-y} & Return to S process \\ \texttt{C-c C-z} & Switch to process buffer \end{tabTit}\\[0.5cm] %% Is it worth putting here for one line? Autoyas is a much more general snippet %% generator. % \begin{tabTit}{At SfS, or activated by \texttt{M-x ess-add-MM-keys}}%-SfS-added % \texttt{C-c f} & insert function() definition outline%-SfS-added % \end{tabTit}\\[-1mm]%\\[0.5cm] %-SfS-added \Sect{General Commands} \texttt{ess-doc-map} (prefix \texttt{C-c C-d}): \begin{tabI} \texttt{C-a, a} & \textbf{A}propos \\ \texttt{C-d, d} & \textbf{D}oc on object\\ \texttt{C-e, e} & D\textbf{e}scribe object at point (\texttt{C-e} or \texttt{e} to cycle) \\ \texttt{C-i, i} & \textbf{I}ndex\\ \texttt{C-v, v} & \textbf{V}ignettes \\ \texttt{C-o, o} & Dem\textbf{o}s\\ \texttt{C-w, w} & \textbf{W}eb search (dialect dependent) \\ \end{tabI} \texttt{ess-extra-map} (prefix \texttt{C-c C-e}): \begin{tabI} \texttt{C-d, d} & Dump object into edit buffer \\ \texttt{C-e, e} & Evaluate expression (\texttt{C-u} in temp buf) \\ \texttt{C-i, i} & Install package (in R) or library \\ \texttt{C-l, l} & Load package (in R) or library \\ \texttt{C-s, s} & Set indentation style \\ \texttt{C-t, t} & Build tags for directory \\ \end{tabI} %% ~~~~~~~~~~~~~~~~~~ \end{multicols} \pagebreak \begin{multicols}{2} \Sect{Reading help files} %% ~~~~~~~~~~~~~~~~~~ For use in `\texttt{*help[R]($\ldots$)*}' help buffers: \begin{tabI} \texttt{SPC} & Next page \\ \texttt{DEL} & Previous page\\ \texttt{n} & \textbf{N}ext section \\ \texttt{p} & \textbf{P}revious section \\ \texttt{s} & \textbf{S}kip (`jump') to a named section \\ \texttt{s e} & e.g., \textbf{s}kip to ``\texttt{\textbf{E}xamples:}'' \\ \texttt{l} & \underline{Evaluate one `Example' \textbf{l}ine} \\ \texttt{r} & Evaluate current \textbf{r}egion \\ \texttt{q} & \textbf{Q}uit window \\ \texttt{k} & \textbf{K}ill this buffer\\ \texttt{x} & Kill this buffer and return to ESS\\ \texttt{h} &\textbf{H}elp on another object \rule{0pt}{3ex}\\ \texttt{?} & Help for this mode \\ \texttt{a} & Display \textbf{a}propos\\ \texttt{i} & Display \textbf{i}ndex\\ \texttt{v} & Display \textbf{v}ignettes\\ \texttt{w} & Display this help in \textbf{w}eb bro\textbf{w}ser\\ \texttt{/} & Search (also on \texttt{C-s})\\ \end{tabI}\\[0.5cm] \Sect{ESS tracebug} %% ~~~~~~~~~~~~~~~~ Commands in \texttt{ess-dev-map} (prefix \texttt{C-c C-t}): \begin{tabular}{p{20mm}l} \texttt{?} & Show key help \\ \texttt{b}& Set BP (repeat to cycle)\\ \texttt{C-b, B}& Set conditional BP\\ \texttt{C-k, k}& Kill BP\\ \texttt{C-K, K}& Kill all BPs\\ \texttt{C-n, n}& Goto next BP\\ \texttt{C-p, p}& Goto previous BP\\ \texttt{\textasciigrave} & Show R traceback (also on \texttt{C-c \textasciigrave})\\ \texttt{\textasciitilde} & Show R call stack (also on \texttt{C-c \textasciitilde})\\ \texttt{C-e, e}& Toggle error action (cycle)\\ \texttt{C-d, d}& Flag for debugging\\ \texttt{C-u, u}& Un-flag debugged objects\\ \texttt{C-w, w} & Watch window\\ %\texttt{0..9, q}& Recover commands\\ % seems to be obsolete \end{tabular} Commands in \texttt{ess-debug-mode-map}\\ (active during debugging): \begin{tabular}{p{20mm}l} \texttt{M-C}& Continue \\ \texttt{M-N}& Next line\\ \texttt{M-Q}& Quit\\ \texttt{M-U}& Up frame\\ \texttt{C-M-S-c}& Continue Multiple\\ \texttt{C-M-S-n}& Next Multiple\\ \end{tabular} \underline{\textbf{Others}} \begin{tabular}{p{20mm}l} \texttt{\small{C-x `, M-g n}} & `next-error' (emacs)\\ \texttt{M-g p} & `previous-error'(emacs)\\ \end{tabular} \columnbreak %% ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \Sect{Package development} %% ~~~~~~~~~~~~~~~~ Evaluate your code into a given package (in \texttt{ess-dev-map}, prefix \texttt{C-c C-t}): \begin{tabI} \texttt{C-s, s} & Select package for namespaced evaluation\\ \end{tabI} Keybindings in \texttt{ess-r-package-mode} (\texttt{C-c C-w})\\ (call to \texttt{devtools} functions): \begin{tabI} \texttt{C-b, b} & Build package (\texttt{devtools::build()})\\ \texttt{C-c c} & Check package (\texttt{devtools::check()})\\ \texttt{C-c w} & Check and build package with winbuilder \\ & (\texttt{devtools::check\_win\_devel()})\\ \texttt{C-c h} & Check and build package with R-hub \\ & (\texttt{devtools::check\_rhub()})\\ \texttt{C-d, d} & Document package (\texttt{devtools::document()})\\ \texttt{C-i, i} & Install package (\texttt{devtools::install()})\\ \texttt{C-t, t} & Run all tests (\texttt{devtools::test()})\\ \end{tabI} %% All these commands seems to be obsolete: %% \begin{tabI} %% \texttt{C-t, t} & Toggle developer on/off\\ %% \texttt{C-a, a} & Add package to the dev list\\ %% \texttt{C-r, r} & Remove package from dev list\\ %% \end{tabI} \Sect{Editing documentation} Inside \texttt{*.Rd} files: \begin{tabular}{p{25mm}l} \texttt{C-c C-e} & Insert a template of help file\\ \texttt{\TAB} & Indent current line\\ \texttt{C-c C-f} & Prefix for font specifiers\\ \texttt{C-c C-f \TAB} & Display list of font specifiers\\ \texttt{C-c C-j} & Insert an `\texttt{\textbackslash item}' on next line\\ \texttt{C-c C-n} & (in example section) \\ & send current line to ESS process \\ \texttt{C-c C-p} & Preview help file in plain text \\ \end{tabular} For \texttt{Roxygen} users, inside \texttt{*.R} files \\ (prefix \texttt{C-c C-o}): \begin{tabI} \texttt{C-o} & Insert an Roxygen template\\ \texttt{C-c} & Add \texttt{\#\#\rq} prefix at the beginning \\ & of all selected lines\\ \texttt{C-r} & Parse R file and get Rd code\\ \texttt{C-t} & Parse R file and preview help file \\ \end{tabI} \end{multicols} \end{document} ESS-24.01.1/doc/requires.texi000066400000000000000000000004411455642170100156140ustar00rootroot00000000000000ESS supports GNU Emacs versions 25.1 and newer. ESS is most likely to work with current/recent versions of the following statistical packages: R/S-PLUS, SAS, Stata, OpenBUGS and JAGS. To build the PDF documentation, you will need a version of TeX Live or texinfo that includes texi2dvi. ESS-24.01.1/etc/000077500000000000000000000000001455642170100130715ustar00rootroot00000000000000ESS-24.01.1/etc/ESSR.rds000066400000000000000000002330441455642170100143650ustar00rootroot00000000000000‹ě} GupĎν÷ĄÓ’=’­Ë¶FŇJ˛-ů”eÉ–-˲Vň%›qďLďîXs©gvĄ5Ě’@ÂťÎp†„pßgŕĎ„HÂe I8l ď_Őu˝Ş®ľV+yř3ű©ÔÓUŐŻŞ^˝zőęŐ«Wwu†7 ôý4’ÇŽîß|ú‘0Čß/čł Ĺdq†™VąŇd/;ň;ň[ŃŹ'PAáZôazĆh†ĽŐl&˵Rar¦Vl˘ä8JťW˛Ĺ­Ú,zźą/WŮsĐŘHZŐFkNd¸v^S†#ă-¸„JąĹßĹ/ˇ«¤˙’öZeś5ÉëKk{g‘ĹĂţ3Ś@ĎË«Tß˝r¸”~°ĎgÓÎÇń"j$Ľ$ńTµŃs”«ű7íîVŰÖtć2ôµÄż·)ÜP'A@>Ń«hŞ0p śř<`B,ܬkYŞϤeHmże>|·+ vÍÎOUĚ!Žno Â|Č—Wy k·ŽÜ5őܥٲgŠ­Č6ç)@ÔĹŽĂŠ–kOÎÔ[’şT×4ějŹ&öe-0wçD&Ă\Z¸x†ŇÚ’łdŢŮťS2k1›‚“”Vő›˛ĺÚląYž¨°~™%”/ÁŠŤ|­Y(ך–ÝşŐjM×K^š°LËD÷1u&íđ‰)MÖjŐš†¤CóŐSdHm¬’®iĹiÓF2#ž(íßá‘Á"23/”Jăôw÷<Ě|Ô›” é Ňßw€GéďaH-†7mŽ2%Ů{t#`Đ× ÖdąV¦şPćSč7÷FůVGţ˝U—Ę““–­Őv]§T’Sjţ´Z“ˇŢŻÔĘôW2=Žr·^«Zµ–ü=:đčýÂŕ8§‘h±ZžŞ‰>… Ž*ź˛ZÝj·B‰»+Ő<ňkąIˇaOSVÁlµĚâ4ÄZn’Ĺů 5˛.öŕ ŇŞDZÓČňUŐluëďTĂl¶¬­rĘĐZŇe¬ĺ…ĺTÓ2m¶2¤6ő9@-Xł¸¦z6ŠÓýŰÍz*ˇĂE?Â…›”`ăűĆÇŹ¸)TŻwZ#"g;Óżk9›c$OčŠLTĘÍ–Ŕ+%›ĹâDňń3¨¬ ´3îÜçĄĎ•Ę!Ćâ—:ý} S_Á:ݰŃâLaŘéâŚ]ÚS‚ľ|Ă´Q§ĽJ˝$ť+ś·NßŇ‚UŃR¦eĎíőŘ 2ľTM& ±u&-Űv4 ŠŇE 8B]<Ça-†{đĄöa°»5źÄ."‘ąQV1#P„(I—:¶“>eÚµ˛Ómžm9ĺnËÓ´R*…eä§ÓŚĎ¤ĎgĚG¨i(.”vôFM—âßý~$ÓoČ HŻ!‡ A]Ő=ša‚°iž“ ü`YęÜwףĄ!ă„óvŹ:»·şóe>7{ĚLi4­ 51ÁIľKâCv¶93–ŽeĆižĂŔ:ťi?w]Nę`żé\é$&§ţ†vöۨ‰ěZsµR-XT/+jÂlBF>fË-ĚľĆë3vŃ«+“ĺ íą‹ČşnN“”âXMIŕąIŚ“Ş±˛őLš'¬|“V×5ŻzČ17§•‡Í¦3§˘JP>úB T>uŢđćf‰bÝѧA†í< VQÇÜÍV˝ˇ‰Ď ĄXË:ÝšÔĐĹîĂ™ąµëšksĺf®Voĺ ś3k%‘«±ç&ë3(j˛nçĘ-wëE§–ęUÓ١uĐţ°@»†iĹĹtÍ:•wlXdŔDPHđ`lW¨ŔĄÁ§$tH )Ľ2Ňzv÷n6;‚ *¤čÁ¦ŐÚ‹ńw[m*źPjŁSÍxÎ2Ő2ĂÎó•J>H?yÁĽ7·…`ŮrőůÚiTUSĐŹ¶ZýŘKľ"Ë<>ř觲 S©;l–Iżż3Oţý»ó$Čú„e5Ü:¦r«Şy:_˛ˇ4­Ľbžb‚P˘óĹ‹ćImf¨P“Gbń¤ł'-uEÓŮőŐ ¤äńuÍűr !iFôKş^¦ëíjÍ–Ń(CĽ4gÚS3x˝´;—›Â#ł–«O<`[ąúdÎŮôu®›îe©lKôă!…`Śü_Ś<,ĄI¤ě˝šDő.L[•†—yJ74,›łáçń.-żK×-˛ á,YÓ {-oť.EŔ›i9o ł¸IMNÍXM°ţŇńě7*#ň¸®ç9$6ŽqΗ»db.(Göç÷Ö«ŤŠ…ŰMôq Úo ÓŚlR¸ÇžşÉé4–M;ŹĹQ/‰Î{ĂĽá»ŰËJ‚«k7Ma.Đ´€ěüwhâ]’H­éH?,'Ë-« pönÝ KŕLzĽľ‡>ß Úř~€Ľ÷q–_Ż÷k{ďWż÷kxáY§JÍÔ¨ŇĘ•R欰|í€ď˛đrČkŽ~ČclłßńëVżxmřnn’ÎëÔ¬¦faŕ)fűbu˛ÜŇPÓčóó §ŠŹ)T—:jůXаái×RZHtާ~ކPC–Ú°ł LŻđ'˰WŔtZą‡5k®gŞ“’R)ݵÚCß­Ńŕö’nŁ˙ăAŇ—’_?i5ęA\.]˛&Í™JK)US{Cú8[ˇ!ÁŹkâ>†ÉBB±±y€CŚéť~0Ľi/v í đî›úŚnoŁďP=‡Ĺ›©D“§¦Ë ‡Ä´Im‰Ž¨ĐgişőSęĎ|ş*ßuĐAňŇp†Đ0NčŢO Ë_ŠPŕhí"şş»5]Řk6óp Ͱţ„W;ëVQÝdŹĆ2g=ŐžĹzµj2…NzţĽˇ1q°jĹz‰¨XaAr[¦X-šsŐ M »%hą5ö>­ˇ>­#‰Ĺ]¦W…Čž¨•[5flťŇ5M—ň$éłšÂDVŰ:9SćV=Ľ\ Ţö&°šÔIéI$öź*ą?‹¶ŤMš%|AS׿Ő}”.•íß µ H*;iłťŔŘÁgÁăA]}R̤‰ĄH<:ŻtÍôĺyMýź‹Ůż÷)úKóra VP Ö$ö™ ňźp§Ežsşn¦F$jýŔCÉţáZs?I?’?2kŮM±,‚Ă!5–ß¶#żMnąďxM VĐđč®.—Ú2sىĆVâłV [CÝ|Z9ěŃ„ů&P˝7Ďű+^ŕŔI*ßqXp|Łđušöôů 珎Uëř6­gťű˛_ ËÍz°•·třęmJ˝ý-§š «X†ŰLźÓÍ2©ă»/şîř}Ţuc€?čA~UúűŰQ*—B C¤ČÁÖ'_ŐŐ1“禯)©–e—ęů˘YŃÍ ˝xî©Íťš¶ ˇ&ŰeüÇ€^×qż*HĐ!ďZîwt¨ hăWumôd“ŐŠN v|±¤úĐă1¨‚bVÂ¶ŠżëỺ‘’B"¦ń±µšČ®{× ˙¬ĂYě^íg÷ŠĎţR©©×*=ĚęÝŤÜeSÖ«ĽNWŃ䆍뚛D&­áB×FÚŢďiA¬ÍĺskÜJźŻÝä=ę´+w~Ü4¨ˇi4,e˝#ýoĎ+UVÖÚnKć®˝:w­&Á$“ňÓż2n»Ç†ÚM-K2<:Ä/ÖęźáíűZrHoŘ·j4ńýyŹľŠŻu:?ToakeI$ÔÎZ˝hÖjŘĺjąUžĄyĄi –ž ¦*Ś`ĆwH*r‹wM¦]WSŰ…Óa®çHáĆJ}¬ť  ÚĎ wá7uŇđF<°Éfřş&ú·©[.á_`w{­?U©’xűŇC¤ěĘëáwĺ'EěŤ6Ą‹rłĐ˛gt˝—ššßÓ˙C×)iŮtU·PfőRĐĚt< üjDr^Ě29%kÖŮĚ(°Q¤ď »Ş«ý ] *ƲäÂJu7Ao5čT Ďf„§B\Á 2SŠr­ŮBŚÔRt>/Ő_?>ÁV‚•fä÷rÔYĐ˙ĹZQÍ»ÁŽrşQ·µ'éFĐ’ăuź”mˇĄőˇ~oH‘đEż–2±]5ź€Ř…o,L–íf«@vˇi>8¬¦Ł-Ę'”öß˙DŻö(ˇšŻÂy~ň\ˇ–ç12ß +/ Eeśľh@ąŃ<ż ĎoůŕůćÝß±¸ÇuT'EKĄ¸Z^ĆΉ&˘wüŹ żrˇdś±}¤4Ö:ÝňâŇ6´Ţň ¸Ęd«Ö÷¨MI±rüfG¸Đݎ'ω;…XŮ"W ÓşĹ µeâ‹ĐřCɉ™rEçľ$M9ś®¶…–‘¶=<çŇ!“5BšZČ# ’OĐ3.)ł±6° #•Žé ýµŕâúĄÎčFj·đ7ĄŰ´[“Ď ź®ÖěşůIÄË.ˇI°ä?™jÜęé@*áé4 şVĄ5˙ˇ†ŘĂzr ¬ţčˇ:5•jćZőÜlŮ:µFi$ÔÖŚ])^ćÉZţ¸ ¬˝Ôü}X‰;.đËú°Ř!cŔ‹PÓfúĺ©ĎR_É4Ń,?hůÔ&ĺeD„:ÇpÍ«ëtއôcž—sŐ, Ź sÍ )b˝aZ›ť5íĽ2] rTëŕëëuÄktV˝éAă. ł—  bę/@«Ł˘żĚY4Ć<ĚS1z&KÎ+•żÖł)±đi ŔđVŰ+čę,ąE»’X [ÚĄ:rPyłs ž‡ËŁIÔŮra^Ą_b€« 7…źŁ Őz%YŞML&+&úŻnŁuŰÄĚ”ł»¨ťˇ““áćg@fđ8ŤfŞŽ%EĎĹ–PŻn†“kl}şřIČ™Ç]ýjHÍZĂj41ńE.1­ĎmX×Üćr»üËŽ-ź(pĺ~ÔYSV‰•bçśN›b&ĺZ,B}އĂ`Nęu§A@‘7ů=š7­k^šś\ËąęČO¬=CŦ׬Şr3,^'3 r]€8ó«cg„Źťc5={”ÍÇ!F‚-Ó˛ Śe¨UëmŮfőî8H÷9V öăbÔŔ?¶Ęg.ç5tűηkHZűčM kUzC¬eĎi˘Wüâö[·ŮѤEçS,;Ç `§z)˙a–°pďÓ)~VěqqÂA=¶đ»0Î qŻÁq’,<^is¦eU“Âfh˘ißř¸¨ő«`?ĄĽUilGëU ŮëhńU0ŘŽ÷×tŁ51–ß¶]†=«ë H§CsíĽ@‹z*ć•´ěçĎű.Á¨~ÍĽŔŃ«ćĹŮ/׌R'çĺ†U°ë§šxą ©AňĹčx¨şş-Oż…ILx'†JZTI˘Üć‰rc/šh…GV˙=!ĚVwjE´uď/kÎř«_zŮ}čH zű2ř=ˇźcÖcĹňl™_ë@]40 _6&CH ĐBëLąÁ«@˝HóÝ«5đ_‹ăAʱ6üšł·)—ב㚫}ęßžß!ńuµ¸=&X>;ť¦*±KüË_! §Ęí(‹=őP©,9ÇčŠ$¶`őFá'B•ËĽZ#ľ-¨LMoz1DľHןŽ<–Ç“a޶ŞőYť5ťŐ»ŘŘĹĘÄ!şŰ*N×Ĺ$' ˇqqNR™€N1kš1ͦŚÉWkÄ(Ý׋”1Ľźą®IlÓă„ëšt?óµ ť:Ü@!îé*žř$„:pšÜ=[â“ä »Ţ0§ńđG˛šp KHYżY®:;OűjłQÜtőëµ–Y®5osP4ŰO(˝B[áGŮo‡űĘ,˛.k˙±CîˇHG®ˇß”ťXW®­#UŮŇ©‚1v…®»<Č.ŰúĺćĹ.„T˘ŠS&î±yiiÇók4ôµ:qˇ“zdm˝8“IÔĐ÷›n ÓtěJ5ÎŹîz)s¨•śžJĹ]lÔ.ÚŘŕ-އް{ú](ŕ”§dŕfÉ3ýľ¬6 }MĄđEÔŢČVÜ>y›ňů-üŞĆ–JyÂ6íą-Î!Ń-G¶x¤Ő›ů# «„»"u»ĂÜhȤ€†út˝~Â±Ô "V3X‚2ÉĹ.ÄDŠÂ2JnŤqúÄMYOŽĂÍ[ŠÂ(. 3EáÝKÉ÷±3KatÓo{(ÜQúűj Íp·Ű`UhÜ54űn–=HŰˤĺ Óü+é7Ł4»ďÚ@ë§yoéh˝—Óvß ŇpŢîy4m…;JńĆ~ź~_Ę^Eaĺ@›r´ěµ(ŕ>ą…+QXGë‰qh{äĹőśĄuÚ@ĂFŠŰÚž‹iŢ .Ąđ®ýól¦őßBź[iľĽ¦žŘJ| Ôs­çNŢä‘ÖçrPź]4«nĎ› ŇĎją¸¬«@ąř›»PŔ›šňČ{7MÇő»…ĎĐľ»Îtűć"0ţ®§őř,¨G-íEáW÷7¤Ź÷Ńoqy7R ™Ţp[x7‚ntyF)Ü5—·ŇţşŤö×!ŻŔ=li[‡[ĚŞÇnŹQÜŢŽ†óGŢ»IşÓţ;Pľói[ďTĘ_Gëp7©CěĄ8ćŘ{}ŠÖŃPN_ý”ÄÁô5=&§sŘG.Ę9PŰÎŻL±›çĄw0;#¦Jl› C–z~j Š~u… %vPywJQář55.§§”Z>¤ćOx4=Y=!7BפOagÚHVY]ą)˙FŠiď„5§|šö­šĐ몦«J&dU–».YĂź,»ĄôŘ:Ąn‡ĽĐÓ#Ă}şî;]3–9eŮ·8őTáŞĺéĘí ‹‹q żí3ôt8P1ś;X7K7\?i ?…´J·y6tÍjz7>U„]Irë= ń@P#ű}©k@7u)̨{Ŕđ'‹A9˝Ş¦ÉéĎRÓ‡ _ň¸Ý §±+ÎYn?j+ÂCŹÝá……|fś ôĽIgÔ V[ŹÉ˝‚ó/Y v2řúrm â'Lo/5ü{{™áßŰË ˙Ţ^±Ŕöt›­–]ž!ća0˝Ň32b÷(%zbćĽH5'pĂÔs•áŹńŐrú}júů†Ź\`ř÷H.R»Ű,7Çw„hcśâvk ýčÉćPëoĺµô4­ÖřŽŰÓ(ĂÝ˙°˝Ş‡]|pU.4Ľű9ę´ę'r]dxÓ˝A\ÝIů×Éůoó¨×O©ć–}wËUWšpTy×Nj:”­—«pŻZő †3­š'¬h¦Vňo”óRám2|ÉŐ[RÁRTt¬)Ä0PŕĆî÷@]]w±Śźcjú%rą~ĂËPXź×ÂżÔđg]› Ö•7üY×ĂźumőÇ«·čP©O8˘VP+#0/3ym3ü©yĚĐSó®í>—÷÷ ~ĹţüšgtzĚ9V{ŹQXÁ˘1^¦ańz”W•,őbt‰Âň÷QĄpâa‘ě¨ţ1Î;š:<ި•¬Ó´!Ę=x6Ę}Ś–óĹ+‡µ=oeĺ&ü‡Ř{ś>•U©?Źç׫iÉ‹[ŐĆĹR"[áÇĆć5čŞfyëW8MEx5¨DÉ…ß»é3KźDý;Lż»ŤĺË÷#콏ĽŹÓ|Géó}ŢÎňőŇç0‰żĹŃç }ô;Yú}öóN§űbés•Ě™b–^/ApÄĘĐŕZů.VňűŐń.Ź uÚDŤë{€~ÓEßô›%?čy÷Ľ!=ý0ů $ŕo‘› ňQcqŰ Ň¶{üĺôąŚ>—ŇçJCé[±×‘6ľ€ĺ»|W`ďëI:źésÉw?Ą“c,ýbĐ·)CŢ2YŻô1Î yź€t–˘}¬ů‹Ü×čs3}n%ő5Y}·Đgž>/%é,}}މúĹ.¤őë I҆Đñ1„.Ť…n%ô‚ĐCC  0X콄!A`ůŮűK|ÂR†iX‚š¶„UgÖ€Ła-v×Ѱ]^–¶Q ›h¸Ä#l!"°˛·€M©vа]ŢËh¸Â#°ôť°®o+]CĂntyYÚµ ě ®U‚-íáöp 7ÓŔhęná&Ź<7)áGPó±°W _G@8jm nA——ĄÝÂ]á%ô…'bËGVc»ď?!ńθżPłUľ{÷Ž1ýQ}áV±ëÔęZI`EcŃ:S+‰Řžy#ćśçqw]lž§Ö"fĄl6Ý$2H]c—źt­ B×>ŘF¨ŇˇéŠs€¦ÍAhj’r 6YotiPuůŽs€ŞK‚Pe[fÉą‹łM嬗…C®É^ gfě¤8ŇĆNŽ™‘ń?†cżĘuś}Î3óţýç7Sj2e&Y®ęßçÜÂ+źž©ť¨ŐOŐ<ľH•›Ô-ľĆÇ–Đq·ĘU«Ů2±łÂx?NŘóHÖęţî¶wztTúđmăî*¶X)Îk+á폌s ß(‹ęŔ$:MŠÚô9N÷Y§ŘŤŢš&Z<ôPâ,ÖsQču×öpôzF{CŕěZ¬×fŰh`ű ěň]ça‡á†Ó­VŁÍp¦#°s1Ń^„Żj˝Tžś;Xn¶Úc:lť ęÚ„-ꊟťi7‘7Ä˝â\¬‡člyކoUk3üiđuŮąX2¬Â×4bim‚+ ޶í8‚‹Öę‘ŰÂV.ô„f€đµdÉa$3†Żđ%o¶lŕM7üŹo1ŚŹ_üPţ|EŠířn ׆ř»¦Ń÷źŇ«Tnĺ«fËĆ×§€ď}ęK˘_ŕ^ʦ“3őć v„$Ůűł§j÷ßŐ :V¶ˇ¤nóIŤ×šPžAZ‚”T*WycD Ô Ż´­)„mË.Śo/[ %«bÎQĎL±çÍ«€‰O4ő M|ʪ颋•¦vÜkÁS˝´Š» y›f©h°Ç,ńă Žť6H‚¸4Ťc§Ř ĚQ°Ú«>»)\^žćéŁyčs>‡č«ÖđVĂ…ŃOŃşĹVĘË aáż”>—ŃüKh{ ­ ëeĹľ$ö"Ý»Aß!ś?śëŢupşüáĽD÷®`Şü6Ý»ŽbÂě2ŠđÚ*‹»Q±…©j ŞE¤_GĄ< dăi|;Mţ‰"[fő{©Ţ^OXoņYĚ6M«u“s·‡énF3ăj”âŕ? ݤ±Ţ N†Âńů‹7Ć}@Ć~ŹŐ;ÚÉ6›U<­5Äą:Ö®¤!ŚrĽßŹŠŻě"âkĐđ⬬„î`L.Łj‹7V0óŚU¶­7$ FśÂÔô@Ü'LWSĚ3[m,‡Ą qň4f¸ć©ąęĚfŤ|iF€śŃĐŕÓŹ3Ć“ĂĎmą‚3žŤrŁpFZNdθv’g›32ř~×ÂC¤ňaŰŽÚg—‚kXż¸!ÖŹ,03%hŠÄL–2 ¨ćI:3Ąţ†^%ř™ŽĐŃô,Ç'Ë5˘0ýŤŠ]äů#~ŃU›}ĆŽźŃŹřq©ëřńż‰oŔď[ÍÖ4+ě¶FÓý3=>S­š6Ű»’oI<;qüŽŠŤ˘çŹÁb˝V*cwś·ROŽ ‹Ď”ĘUâĘ ÎĹK­3}«Xµ)Ž^ż·xŐ<Íz¤j™5–©j•Ęü-^-łźIXYźÇ©Ń˙§/™“3f­…UĂ=Í–đs¦ĘóQźÉë°]1kS…bët »FŞŐgjr >|«¤,#)“ć K—śˇúŃć±ŇIŮ˝{7H…údS>ŘL »x…v“ÇgŹ)O&ćZ®ZŽRŤł€Îŕ:,¤PĄŢĘ«»L˙ü=sÎĺ1$ŞŹDU%FE#O™v ű'] ’ŐdwżťQ}Ľ‘,Íç8ŤÖňsB?Qűţ,TęŚÇw??Q?](Ők|‚±ÍFĄ\´ëIi§Tć¦>4f®V0mŰś‹Bd­^B’+fu˘dňű¦’˛$ňAł±Ŕ^?3®Üť‹=tF/Ę{R%OÓ´fKóęŁ^$ýćb[Šă<‹©x«Žç‘“=žWĆŕqµ ŁÇ}Ú{Ü»ř^–úωSz°÷¸»ŮÝÇŐz-9îS ‘¨đ<Ń ń}Ç5Őę;®©×2'Ňł0Y‡ĽfPÚŐ JT?ŽrŐg€.'”ĚŁp ¤-—ŇÜĂ`Ą&]şňhX¦äPj=HW$*"łE•îŠj–ޢ›~V©ËM«Î÷Č#·Ě+—ÜşóŘňĆ»S‡ÉĘES‘Q)E.^ţ ňů+ą:CĄŢR$猤*,UÓ$©`9LŐTvPJÂ)^‘¤ŹŔ ’⮆ ^x;fŇË#0‹LçRŮĚĄod*€IB®ŕÍSY [ÎŞśĚĐNÁQžHď©{ýhŐę.t-]ËÓÓ”SÂ˙9IĆśňÄťň]G<é'ń¤#žtÄ“ŽxŇO:âI›Š'xOýužťç“űÄÇ*^@Íśí{ě9 ©lg‹ŤMbjÄLpťĽ$ŹáńĚ`ű\çâďŢ.ďß~«cĹŰ<ŠŹúŁ«5_RMok®ađŕ/•''ńSCw @lß<Ű~ß~ß~ăóŘ8˙•Q7«¶U;ŚŽ÷~vf ă˝żă˝÷ÍEFÇ{˙¸ń˙“÷~â?Ř]*Žú‰ËĂ<×Ňf®ů‰ßCCäwŐż=˝ńÇ\N_Ď­ ~ŮGĽćüĘ“ävź¸mtăůLÝěËnRqţ>)żęWXőˇż0g°Ľ~źúzÓѿހáß_rúYö‡/{¬÷ÂĂBáÁzŤČřş3Ląř»Qů»»ÔöFópOÜ^Şĺż6íĂű…ďřŻ?ţëő>ćŐvť)?ĐşWŰu¦đ`ý¶ţô9&§O„ĺ/ěĎŻFÇĽoąě|8}¦ţă]îÝKşőIÇM|T7ńÄ•;ŔOÇ%üŻĄKxâ¶ôGÇý»Ńq˙®†Žű÷ŽűwVö6Łăţ˝ăţ˝˝Ýż¤żA7™‰ĺË·‚ďAźĚ·_ŇŮîe/ŰňŰň[A üâ’±Ôçě˙Ä˝–θłóî|xöęJ‘Ö]=opoqęĺ †w‘˛âÉÂuď%w ÄĘŁ «łR/·ĆÝ[vyÖlY[ZŐĆ–#čż»o?şłRŢr$ŕĐřŃ=^±sëŘöm[wl»|‹Ę-G¶śśY çäˇZ§őŠ=˝Ör˙0/Řx—ŢĂË ŐŤří çw—Á­ÖPëú:ÖÄŮÜήc­yčŰú»żqŰs•A´hľ­Żpanúž;o­MliśÚ\)OlźĽâňíWc;wMňŢVđ·ŢžŃ4śőĹÂW{~Η§‹=ĄPŰš$9ř0ĹL?Nź7‘ßřyÝűH Ă4öşůHPo¤Pńó: =Ż{? Ń Şąy®žSÓőŠ5Nł˛ÂŮš(v“řÍzĺşD-®ůLÁÂ›Ű ĚßM†@FeěSt÷nň,4§ÍÉ–&ź8;ĘĚP|—™žŕu‰˝a^pĚĚ":ÄM†”CLHW­I§ĎI­hV*fńjE\L!Ľ1ę±@}‚RÎ}~…/·ýÔašćb¸ôýc™ź6€Bě5´ ×lžPşd%x˛đEŘú“HlÂ6ČJ ?űéoüü;µL!áç6ú?˙ž„B}€BbVhL{÷%˘AUrÇ^?ďć_śü ëbů‡,Iĺ_|—†×RÝúÁ]Śď¨9ű¨oŢ=HÄťŞ‰Śuâ`ٶCb^*"öV…C„â-Ô/őVăě~O‡ńĵ*öŢ}doĹl6Źa_ŢOްxĂ]ˇBŰ#c<„řŘýy<Á>lś{ńqÍž×ßy¶ÄÇ›|5Š  FBm%Pş§pş.ÝĆÉVLůçzŐŮx'†‘O® çLt¸aA˘óÜLÝ˙Úůx:dƇCô7z^˙|ŘÄőÎHSä;ý¦Č4řMÇÉőżµ$uŠ^ĄŽ$ŐÂLÓ*+ĺđóĽVŽ˝eţŚŢđ3~ě™îźLGD*oI.ö§ŕ›s/´m3b>ŻIfSÉŻžéŰŤ'ŞĂ'qČp¦ödáîGI8gSÍU šjśăxżvSLâ6řt>A'Ď»3Ś{Ä8z$>¨R¨řÉN› ç=C$,jŤBĹĎ*zŢ3LB4¨Jn-wIÔ ×txĎHÔ’<¸ PMµ¦­ŞE‚¦ËSÓZâWŃ\Ł'©täZńdw$ DůaRJâ¨!mßýSţ{ÁPď PďV ţ…_-ę=ę} T”çžŘ‚ˇ(Ôd¨÷ â»§˙¬ťfJ‹>U˘ëżůýµfÁ:ݨۭfaÚdĘK3Nä45şŻÔZĺZÁˇ\OŽ~K ‡–¶‰' -ýtÁý7!ÓôąüĆĎ»FÂYčź#” úDńw˙|Ń™BažŁ—u _W3‚.ň킺 7±WU®•ę§€ş/Yá®Zi¸Î#:]ő÷ &\Jš>o żŃóć/‘°@¨ŁŇ2CśEáf$ÝüµłBVË —ž˙ćGť¬â3vEÓ“;§[­Fs÷–-SĺÖôĚDľXŻnyŔŞŐć&Š[NM›­Í­ikn3Z3MŐ[[ĘÍćŚŐÜrŮL6+h wRŐÇët$łá0âgM+7Ó(!fś[×̵ę9ťśi‡J·W-áŮSnfĆźËéoô} ď]ŮhŚđă~®˘żŃsôĹ$,ę'(¤OŇőąŁ/!aP˙‚Bú ęKIUÉ­gÚźżéâ~ôeQKň`ÚPţ袗:Ćž€B‡*†ř~^'´„řîWór^ĺlĐ÷]1żďC §'_pĘt§Žŕô$ N2Ŕέۍł?ź.lŰ®I.h“éÔńçłVqsÍ:Ő&ÔI »¶žä-LtGlÄyRŢą0É\ňę´ ň´Tw.Ś×-x aNÔívYDxŇ^ű'4[fŰśmÓRßŘ9@ÝÂĚŚđ%m‚9OÂ;f{„˝ZÓÚ\˛&gšíbۡĄľs!ď-ĚŐ36ÜlU*ĺFłÜ.¶ ždx.¬0÷.x ™6kĄŠŐ6VŔ:BĽl«Pr¸ô\ČÔ×/»V­ť\Ĺz"¸ÍŃǰ¸šO–n!áśiwŢńtòM:>Ľj%†Ą5l»´Ź˘7NžK·˘p­P:^I˝yˇŹjĹąKą…­„ë Ë6[ő¶9ŕÉ(wO Łäő¨× ôŽBĄnęnÝLL9×§»dŇd~ŻYaͰČAĚVń…rł0mŮ!^5"Ú©ăÓ?18“é:ŕY¬‹Q9năűśćdÚw›ČűTLżç“w äýŁ€ĽŰEŢg|%żĘ'ď‘÷iyöxĺÝ)ň>ýYy/yźM†^ě“÷r‘÷™¨›b|ň^!ň>ë#yw‰ĽżuJ~a ą`lýůżŹ’oôÉ úóąß Č úó·ßŤžßňÉ úóy/Č úóO?„žżë“ôç ·ĆŞçűäýů|4ŚăźđĚ;¶Uŕ,}ěvĂąđ[ ôűăo7bďţľLŰô]—’Q®… čăĎ0ţźéSôAú,—˝Ę& Ł?ű âi˙צč«ôť/$0=óŠľJß'´yźĽ˘ŻŇw_Jpę™÷2÷ŻňŠ>Hßű ôüźĽ·éăx+ö>yw¸É«Ăí0ľľů?˝îăë/nEôú;>yÁřúč ˝~Ü'/_ß“ŕżűäăëۇQ >yEźużńă›>yEźużOUßóÉ‹ú¬‹Zło>ôJ”mśĆÇDü‡˙=ľJŕR§ýdĄ\łŔĽČ3tń‘Ľkßbͱ÷ŠůŕzĄßxVPJ÷Çđ`yÔ'Ż ”îŹ=>oh™óŻkÚL.}sJü?†‘Ľ¤›ĂhVAňńź7ô¬źfźxĘz“ˇGVAđ‰Ą§ ßAyćfRŻŐă"ţ‹ź˘qń`W2Ţ Ĺđ‰˙QIüĂ> ÁpŻ}=Ą)FYbóI´ú'€+Tßj¸9)hâR$lä0ŹÚ^obř$–ˇn\ň·> Á~˛Ç»ÇĹ(KÜ÷˛€S}ýĂŹÍďÓG¦aäSsřóžîv€é#căřWŽ*0“$ö zP Í*0q5băáYcÓó"­†QĎno0`ŐđŕôćďŰv‰ÚĄő2Ń’¨#|Ŷű€"ѡ7y’ü/Ćí¶H Ýţ @JC %•zBŘý>0€tř:Ă-UŃj ĘIĹ‹(Ő›"·í‚Ňáoz–JügH OŤż %«KF RĐaŞűż<čŹbבӆźč·m»Ć—äb×14ťÇâ>yŘuôÝÚqű3љݟGâ¬ńm‘öîy—hć&TĚunŃâóřüËĂçJ´ ý±Mh÷'-ř?ĺťUĐaüYeT¸TA_ÝďĽÓ0˛űFž%°)z·˙ČŚ €ř—âㇽłŠţŹ}–ÉzgÝ˙4^q×;«čýřߣĹGl@îý˛ Đ_Äżx­o€ú"ůo×ĆĘ5ŢYlŇ8aÄ6č źhVĐm_ý±osî"ţC4“Ç|ę d‰o˘ĄŔŔE˘‡ż zřk_DO!ÄiŹŕń$XJ¬ŇľŽĆGüŢĹŽůńv1äž!”˛Šť˘§S˙óۆßÔ˝m§čęÔü‘¸˘ŻSOäŕny?L±ç~âöť€»*Ľ…˛m;Ű6~°ířű GĚôĚ Řv×o´ °ířů†×jy;"2EĚú^ë s;2Ąb@^ >OÝ’»|ňąx/2^瓼“o Č $ŮiĽ"Ň |–¨(9íŤŰËÎŇÉ'tŁ… DŮň%ţtp˝ď1ܢ DŢň˙ € dŻäm>0h\y‹o_m» Čb™óüéő20ľR˙ćOŻ—ń•~V@^0ľşľăö20ľ˛ËđĆWöÝyÁřZň1”'gDć——:ęąI8żé“ĐÇ ŢęńÖ(m»ôűyˉ$ę™ôçŠoľbăĺ ?W>5 /čĎU+Đók>yA^‰Í ÷É úsŐO ٵO^Đź—ôäýą ŤŐ®Ë˘÷ç ?oz‡á§ůÜvčĎ«î5ŚÔĹ>yA^˙Ü€Ľ ?oţV@}Ař3˙1wčĎ›÷äýy+»ʏôç-߀ úóŕL@^Đź·í18ŹŇźŰD¦ľ|·yŰ€<óĺGňyćkňÇXs¤ľú[pw¸kňŠţL}ýG†/«Ô#XFńá‹`’úú‘€Ľ`uý͵uËćřˇá9—4săßúöďv föż=˙Ŕ'/gnÜí‘—ć@¤J}ň5(Ë‹<@±çć!Źi—‚ÔőŮ2Y3kAéč¦/zé‚DřL čQČŘ,Pâ|ć >0€pu )ďjţÜk<[ş ¬*SßřMz2Ř-#¤Š^E!ńWeOŰŔ*5őíq’˘Ú-oó/ڰĎ%|Šťö-:µE‰îĐo,z ěçqţŹGŃ€}ëCd.±ü5ę4ăĺ0@ç~wš𱇌Ď_îôŇ?Ţnř2`2úÇäxř§×)wmëň#Xaňß0Cű.^Pţ®gyŰÁ""s+ţ¨˛kł[_ćüaU„˘/ĂqńŰgI_¦m ŕÂ˙4Đ@Ŕ]oýwŃŔí™wŕ=ÔźúŔ\÷đ§ČŞ ĂŘ `˙?čů €Íކ‰îŐƵ†‰4ŹůŔ|őđ:Ăm@¬2¶núływÝJk|=îQ`·ă iäv0Zo@Ď˙ň€ŘííečĺtRcŃźÝ_FUjťDŔEŹL^v ŰŔ>dęźßořÎľ`µ•9vJîö€ Ří÷^@s€ďĹ|ôµ0ýç‹}an[›©`IŇGZ{–©y/zě÷É Ůż>0˛źÜ’>y#űá5čámÓ° ě ¦~üWľy·Őjćč|p xÄc-Ăosa;XŐfî|J>Ď'/ŕw2ô6(dNUM˝ćŇ˝Z€5ÜńC€ _óO> §¸űű­§ ľ«r~â°„»Ţhř u A©×ŐĐăR€CÜ˝_«‰řőčđ„{ńý{z-Ř6°‹šzôʱF«†Äźľ‚Č‰Ú˘ë¸O-z1hŘ•M=ú}˙˘Á{â\Ř‹¶hŔaŽ?ۧhĐą˙ýn”Üë]4°˛Ńłčm`s8őÓSčqľ7H0®ß…ĺż7y€üęçż'ŚťtđgH¨ëú© Điżü‰á»Š6I©_|Üđ]ˇÂíÜ_Ţ´÷Wk ßyhi2O9†’ł0{ü?}Ëß´9™ű0Ó͸,/ŕc÷}Ŕ#/éFPŐÔŰ_ęŮŰŇ's˙Ë<ş€‚z§O|Ţ0ލ»Ô $ŕc…§PtŽ=PĆ{MďŐ(Đe ż0ôâ7­ í÷l6 3_ęŃĎ$ őŹbńWżVÚU™‰KýA‚ń>„ËřÝ ß±âľĘĐ Ô?D@zeăćÓ[|ć ©Ź ­F%Úv DËlú±Żč˛(Ń2?â?ä€-łéX@^0>.˝ÔAÓD¸™Ĺ2şŹ¤ tm™‹5Ľ Żŕ6g÷ ÁpąäůŢ ÁĚŇó3ôüG`¸lFS ŢÖŁo/‘~â —-{!ę@‚Ń×űe”úH0\ňŢ–L@•ę˙ó`¸ä˝-™€b*µěEd.đ  HJ ťFŁĘ{BŠźÔčsüł‚QµSđź„UđPȶ™€Ľ`TmÝë?R࡭^ęxRu ŔH˝čµD9ˇ ßö·ŁäŚ7H0ZV"QäĘ= ÁŕĂę oąhR+®GĎox€oű?H0ZŽ|j ßΑ®H0Z^‚wżă ľ^šx Ś–Wc{ů_z€oç`´Ľě-(Ë×=@‚ÁwĹ&CRó= d‡—"Q%6ę]FŻx)Î++FŻm¸‡ąĂł8—ý—˙Đ€gq.Q@^0ŚvO~;°ŰáYś]GżĆ'/ ü]źČ (úŞ·{Ěí,/ Ő+±~ç >y ^ŐCňęäg`ćťúÖ™xëM¶Ă36×ü‡á¶ťd0ř›Ďô Â«ßkx꬀ˇwę %_Ű€węď.őĄ­mŔ4;őĹ_Ŕőo˝dP–ŚÂ/Ýë‹×mŔ:ő÷ŔĂíď?Ś·Ż<ßpÇÓ>€gq®9bř®‹ŕYś=;üExçÚ˙DĎ?öÉ Ć×u/ Č Ć×Ţ–µŻîĽ`|]Źq§›1X^0ľ®˙ŠoŢ1h‘uŽ÷°.ëăĚľ7ůŇÁ´ÜZŹ {ě–ut憖/ ŚA Ż•5`îë € új–ľĺ“ôŐůxń¶–`«ţĹđŰé–`«źôAnŹÇŞŚĺ¸˝` gĽEä đ,űe1Ëöżń!ôđ>űµ,şú˙í/ żýť`ŃŐ˙ŘĹľ8ß ]Ř‘Ţ4óĚ+úrŕkoôw;Á2iđüq_śďëźÁ Đ"qHĚk±8ÜŽ•?ißiĄ~{C;ÁRcč†)1×űőĎüˇ/Ţ-á<ö#‘6<‚ç‚˙ň.ëĂcřů¨O^ŃĂ/F}~Ţ->yE ż˙öć-;ä<˛˙—r[ţC´eäwžg8»^,í'"m´;ďOw@HÝÜWôÇčoĎ şóé Ž~îÚrá’#ř¬§÷ůŕť@.\r˙¨?]ąpŮľ^Ę{\ŕnEęyeŠţYůôKňŠń˛ňŮź yu<á[;ă?WĂłyk–źđĐÝk°íđ4Ý…¸ź˝- ·ĂcrëžP_0W\t{@Ŕ\qŃżűćÚĄôx%ę1_Âp>hřퟍőRúÁoúŔsĎúß ¨§čôCřvśozŔsÔ†\L`•řöY”ěͧƠUţźLFÜŰ{ Zĺ?í¨atßď“X%ţć{ kĄ<ó«Ä—ý¶aô豼Ŕ*ńµ #»Ę'ŻŔYúĎę¤m(_WżĎ=żÄVk?]Ă"­wčEäE]KAÚć-ä]+AÚ˝Řrđ—"í6…‹ýÂłÎ;€ěÔŰŔÇuĹ<Ů•pćđI‡ź{ÂVóď¦P];ڧ]křÍacĐJţťÓS‘v]`Ľ «Y˝çĚ1h˙®áVł˛v‹ľęý“Gęčű=ŘâÂG‡Vńď~ą˙¸VńďŮĐ÷űhzćôýŢOŔôýľűňúţŕfc!V·cĐ*ţý¸˝Ť¶Ć Uü^ôű‡'}eĚ1h˙!ĽÎ÷^·ŽA«ř}6 /čĎŹľŇđőĎ­â?2Đ6ĐźŤäýůńĎŕôçÇţČ\‡č`@«řŹď𧸏:ü7čů>y¬0ň'†ßYé1¸A:Š óţŃ'/–ľÜWo6w8—L´ Č Kćň`ůýe¸Ů¸ěŐpÁś˝üň…ő'ŘĐK?ĺsţ4 Ö–éű~Ďź.ÁÚ2ý”­RŢŘ/?ľäĺQ`Üâ$Đ/)`ôĄ g ˇ…ĆsáŻ|ëĽČ«}=řDž^É>Ö¬éű- fW7¨W?ţFo8Ö˛éâNąm˝Ćx;Ho :6ďŇćĽ\ŹAŁŽ×†ŹyŔücâeŁĆ[^ďcŔW¬áAş9ČĚÝófĂHýŤ(k9ĐqlúcĎ6ď2r÷w±ď2áţ®k€±ëÇžý·ČÄÝßA29XCu]`ĽáAĂ˝!Ę`lőŔ'^)čű1p€ţ{'%ř±ź‚´~šĺŘĎ@Ú÷Q»şĽ×ôc`Ë0]Â4ţ*㿌Áîô|d'°•.ý-‡ŃŐ`üŰ;ŃgźđĆůÔkÓĆ‘l×eúŔă|ŃŹĎşŚôT: /§ĺ/ľĽ l不_mřň6°o—.ď Č ĆW%kříŤ]Gúˇ×í:ŕň'Ą>íZŇţă/ĐCNﺤýřł†´ÖŘ Ň}z€±xHűy =Š´k@ÚĎl‰~»®iż@s¸Ö¤Ť¶čdŇ'j˘­7˙ýĂo-3t5éÚUŰ·čşŔxÉñúŔô[í6řä0€ń«‡Ńg_ôč·úzš{~éź>'“Ç€®'] 3 ëI׿ĐŻŤőŃ>>ÝŔ^^úäl@ŰýÚ—±W\ÎFŹ«8ŚŘŰÁZąë9äEÚ{@Zěw$úŤ˝¤%ŤĆż+Ň>Ň CŇa~¤e÷ŁÇ˝"íoAÚŔű ?˝äŘ K·ľex·î˛|Ď’Cţă왥›X·Myúßz­Üę/?‚˝´tkŹá鳬z.Ŕcßgż칥O-5|×Ă`Ď-=ó=z{né٧äô=·/ €ľOŹŔô}Ú˙ÔěŘűJ?;đŃďĺík¤žë°ýč=aîk¤žk_`ř:Ţk¤ÇG”wźík¤ěăŃGGş¬‘z^ńi ű& ˝×cý©ŕ±ď€´wľY˘íŘ?´Ź?Mţîß@Ú×NřŽł`ŤÓóGŤ…č v@ŁEŐÓgżv4Zśy®á·µ-¶n0üĽWě€F‹­Č Ö¬§ĐŘŚ%}ň‚5ë,Ö ľŢ'/Xłžş$ /Xł>6|ť±A‹żÓXnŃŤdyÁšu®*ň‚ţ‹Ť«‡ßvn9Ö´ěć–Ją^ł*[Žl9Xž°M{nËŽüŽÍ¦i§/ŰÁ]Ö;ĎĽ]šP*®š 銧حxüĆŤŘ+MaÝiśÖŻléwžAv´Ň©·al ůđ™Íµ($h\’ćĹř˘zsď<ýî J놔nü>LÇŔMµô]Lú®k˙<Í˙„ň}Í»¤łgŚ–Łß?Fóö)ß=&`9nÄű6\q%xüánpą´N7l«ŮD]Úę5ŕ{öŚŃzÄhylŽQ¸1 OĄ‰‘‡ éOť}}f`Ýß‚é%Ą(zcRů~[dIÍ ÂDÜé@Fi-c»©$±Wt/´»:8X7K7\oť¶°+;Ńä+Đ5oS»ŠAIˇfµ,›Ć>źxXÔ…†¨ČsJM:#‰´˙ýR¤ˇřÄ%ęr˛ ˰{ËR,] °„kt€¶ C_Jź %ťÝ.ł”>q:6PĎи,ŤĂCł‡~‹ó©,s”ć]ŕłß}†`«ý4mPîµdŔM)lôĆ€!űt9âRÝ÷†!AŻË·ü®cjůńHĺ“ďýĘ—Vµ|~Ďź”óßÓ+<˘ŕáň>®ĽUŢčę­«Đ´©B?üŞý­¶ßŤ_˝đÉž1š_°Xź±Vü$Ü…Ôă1 ű1 r/`ńDL őĚŕSjq;Ǹřa.âXH€ŔŇ“ ¤AČĐĐ Bď↜ŚđÓEaűśń–&ČlÂ×9Iç3|‘™SäĹ´HíĺexM~!}Ţ@ß`đëÄîľĆy÷ި“›6>W+nŮÓhTĘEł…Ńłe_Ő,˘˙ÇÇ·X­"~‘ 70çQç_ËíGSh®9mÚBH­‰oŽĂ·ĆYvţ͵ĺ:lÚ­\}2ך¶rGrôząKsÓ­VŁą{Ë–S§NĺŹlnŘő¬b+_·§v!ýq1‚±·ŢłËSÓ­ÜĆ˝›rŰvíÚąylë¶±ÜQćŢşmĺŽZfUýôFôéŃér3‡ŔOŮf5‡~NÚŞt}˛u ŐűĘÜ\}&W4k9Ű*•›-»<1Ó˛rĺVά•¶Ôí\µ^*OÎp(iŃ’í4Í´Ő&kŰŤ‡Žĺn´j–mVr‡g&nsËE«Ö´r&ŞŽiN[ĄÜw‡?ÜŹk4Nk”Ű_Gđť^ą2g•Qşť›E]‡Ţsc¬( ÷Ň\ݦ°Ö#XÍnŽť«7đç›Pćrł% äU]ŻAŔC)W®9ĺMר±Ó>jţ©rĄ’›°r3Mkr¦r)…´ABßäîîy$k}ďNwiî M#ň=pW‘MĘymÉLčşuAó–x€+0Łi1›'\­ëˇ7źâÄ,]†Şťş]W5Ň™/ňµ¨¸ľ/Rˇ' k0Â˙taĚ{”ŤËpążKSZgŻlűŐ4±y1č!áqĺjüŢ őWH üm"Ü’xeĘŘź­˘Ů] »¶+˛Ś•Čχ¦IĄ#.Uőxť…ngˇŰYčvşOŇB7¤J’¨őDź'6)} |$+[Ö‡‹§n\ŚsxnžŘ2żxłYH]đĹmx)üŹS?ÁśÉòżů?†ăĆč⌉1$ÂtrÔp±V*L[Žz dMš3$ă&’t\_Ň@éqĚ‚Kr•6h6 s- Ż^Ş–].–Őű®O˘ĎQ[ĹË)N›¶YttďA%˝óH¸’\Ąm8´‘¬X°l»n¨NĄ€–a…I¬>Fěä=h˝Îż î×[Qşďŕpk¸†j<â§…Ö\Ă*4gŞůĚ–X첿üF8útÇ{ÓÁ®ó3¸;ß3† lY@qK•ÖŐmÔ±Vpď-ű">×ńŹzo÷ŢD˝4ľď®ůR¸ľómQŘŇ–}毫˙ďh”â‰×j-Ě–™ź´ť•TPE>ýj'±ŮK”'#¨3‚e_xcp?ú¶TĹ7S%–ü?şŔ!Ż”k(× úąźmĄ˛Qöť#}ď¬Ć>çÓ/7˝Ťbłb* ëx6ѶćB3°qću•/ç§J ‡QjőKÝ`4hágJĺÉÉV™'§(5ÓĚŚIyĎ^3°ŹőâRŢsŹ·PqŞô™hüÇX Żńg‰Tg«¦Ę¸÷`,ţÓG§gÚµgđúýť»'^Đ8Kâ>Ęţ±š'Iâ_Žă™VłúA'MŢŚPź™ŞŐš*JC3E¤¦¬ÚäLMżp‹}Ť”ű–AÖ'#äyüW†qoś/Üb˙váć¨,ˇA$_Ąh»±Š ŻŔ–Ń×dU¶Ţj8Ľ”_Nó¤@üĚŇĽx‰Źi`µsŤcj𫴠¦BűOŃr†c ' 8DÇúiI웆dLuĺą·+*T%wěőpéMMÂx_i.¨C+{ÔtYąűĽ˛^–Km”+Ó¦)P-ć×WŹĐľzDé«'HX`_}ťPśó\F©=ŹĎ“púę aZGŐ>řĚŘ"öTĚjŻ_WűĆÝ/şÔ —­ÜýfĐ1o€ďÂö+ĆG·x˛€q/ę7hż~RJ’<pú•ŤvŘŻ‘G»oż* o!{¬iÝŠ&zÉđtŞ€ěî,őŁĂśč8;,Îe(.‘é›c”l™Ţąďl aW] Ů3-÷Ă[ˇHµßŁó ˙Ů«íb©U8@ď®…ÓKj!Á`şţľł5 9äóܵ”‚×®€.t{„…júŐ:ꬪŐY`č!l/á|;™Š)ĺvEd쪌Q Ś'˙ĐłgĽšÖ.j#ÖWę•^ÇÉ1y ôN˙,ÂßböOşdUĚ9Ľ®tôq†f˝‡˙Îöz/é\Úhúđkc'śŐ wL­ŢrXp» Ü˙ĹŠ˝Žůé ę"afV5l\‰NŚľöaëŮ´Y+U,›iäzŹ_µ9r¦Ţś±ą–niÍ:U¨”›­B}˛P¬×JeǸ›¦ö”›…ć\u˘^áżzŤëݰi)“2JVË*¶ ĺZłeV*BĄfJˇe›E G´Ĺ•eÓfłŕĚ$źËő™¦S. ąĄPnY¶PŢ ĚZĹ *Áž)¶P#¸˘ż^)ĚY•Jý‹A­,4OÎÍi¦´jł¨rÓhZj5 S•ú„YˇIŁĹi«x•];a• Ôě™! TGŮgÍĘ ÇX7iLăÄ‹ŔXBí0mYC_, —{]9Y·«f‹Ş.M{Ş0]žš®` u¨f/@uă jB­…m[i·1‹[Ó¨ź`ďø'Ę5Óž++0稨[a1Ý2ÇÉ0iIË.W zJ§ů§íîźâŚ]™…NĚŘě=‹ E˝]g2¦bg´žŞšö‰ÂI6¨1QR‡Be1€µŤJs8a4B ¨M–OđT3‰$ťĹÓ®mĎpjNc* %ëÔ¤8k Ă‚” ˇŁ^tŁ6Uł¦€|ä` p:ďj™“ĚPFiďâQ÷ăc\< Ϩ§ômq ź˛ÎGv?"14ˢŠ8Đq#.DGJMŚ„[9B•Óď¬?đ¬…k9SaÓyw}â‚ŮÂÇĘŮŕá<Ć&$ú˛ß=NÖR ką`Ţí’()gpxď_>(žEňĚT~uDY!Á.ˇ9hň´–…j˝ÂFI3-Éd,˘Ç-¸Ž áşŽÂSÄ0źgťŁ 7{ťyYžbHÇ“ć@nÖ,˘aP‚Ł ’¤Üd ţ•#8ă Š5”v#šFQ§1źőÄ Ëb3J uŁ_zšŰ1ý žŕLj¤‚čµ8‡IMĺ_}N(§ĺ |ĺ&¬fyŞfb˧ˇ%XT7±t¬’PśčGoŮł§Đ\ÄeÄë'«g…Ă$íŠŮbËF Ű U˛]A‡.šśŔš'ëĐ1dúĚ $¶(ëśR9uaDRžXŘ"j¶^.€eŠöuőďĺb•Ľ—Еڎ=hŠjµ,G%$@‡ŮĘsý01 dŰN2Y/2~=ŕ,Ą ćL«[ŕđx¨ö$ÓőLŤ3HĆ1 łQ4aňĹ ^rşt× É56ĂŮ~±'NŁLÄÂMz˛P™nrM̲ăxs„ęŻ[§[ ľ2Ž )„Ě,}ç‚$ĄÉŞ·č^NfśąF3Î(.6*’šń4Bڤ—MuK-Űâ#ú¶FSá´)TŢ Çô2ĽüE R„B˘čž©•·lNVô;ł­*8{á6d&:Śé,]1ď@Ť¨s†K€<Ó‘âmµJebeÝÂł¬„$Á×’P€$DŚ1Ĺ”î´ ®§Ń$TnAÁ“T©ĹĹ˝%BĘ)לň Ő&KÄ«ă‰:ă¤Ă`·ÄŮj©0™¨ż†ÚUŲ Ü%ÉŇ•'Y6u ĄD’ŞŃYTQÂĆ|“ŹŁ·“„÷eƬٍ{quĐŔFŐiâŠ2ĂR§Ă/Ĺţb±nŮx1T1ą¤Ůc:ŠL¸˝rž¤DsX*Y&šuÁ˙puµKŁťô3\*©Ň3â±ÖItDl{d° đŃ,ˇ»R™ďL5NL±Ai#ނ֊ŕ}š(ŞŕxEz&˘@§˘;×'Q˝ %L«¦ŞďĆ“ĺŇ>g'ĹŮ9=!¶ đŕ’–2}f©$dbŢAîuü2U%ÜD˘CŤ2B?©ŕŔ*I (ÚŹÓBëasPÍö1ôAíěÖŘ9„8i—ŃZ…ëNƢśÔ—^Ä™łf2!˛;Y"śĘĎM‘ÝF«K6F“m4Ę\Ąç&ŔŠŃ`*ČZ,ë¶uŇXe!XfVťÝłEUÖ-«s}/$A˙ô°m8A´+]‹•őBXpĆŃ.9mÔ¤'Ë6®& Ľ™Ęň:ëÁßUⲀĽ¬$jF,0É:BBÄ…‹L•k@ţéĆx%űápŇC2#ô©¬"ś™FRţ÷TËhĺä¬ĺŮ^çŢö®źBmQ•ŕŔÝŽîŠÉu×­ădÖǰ`ËR2źäŰŇxô™Ő‰CK†ć8 şÁ̏`ÉCpb…˛hďq÷.hν°Ą¬Y^ÚâQ‡¤9‰ÝśŽÉž´kÓK€F—‚9Č­žîÇôë’ćúŠu5Y“‹^&Y¨\Śg3®ÚĂ:ąi˛Záb)ç uĆZ“Žf‰aRĽdůÖ›zýNWuă©Ŕé]Ö)ËLpĘÍŤű%„¦ÉĄNO,§B˝‘ÓHeß,tÇ@(ć ub+áҧ‘E.,[âŠFZA ¸§†PpöťXM0) ęc‡pMtĚ6Ë­{@ 9N»ąJ’ˇŤ)׺F˘Ü˘`‹běćŇLTŇ:=mÎ ĺ»¶ÎŚ~ʬśpöáXiB(fŔ Sú2plk`B \„şş–¶Á ővă-3‰Ń8UT6&{đöGYÚÉĚŞ[f‰iar4ýŃemAć}”uLb°(Ěč‚ę YaiSWëgˇ ŚĹ7ŇXÎy~ĆÇO7›@xŚÜhČq†čÂśńIŃ=D*|8E2˛9€^h­!«¦ůž8Dě ÓYNÚÖI€·4ăŰÓőj˝6‡•ÚüDô’ăÇ˝—c)«ve{(ż’ű łŔQ·îŮş·<É«"irť;ú†+ŤČŔ,s”cĘ@ –  GʦSgM1WkaŮ·X¨8FlĽ1ž©ť˛9'Ká‰V 9×6tZu`®|ˇ`Ë*.vć3(ş íC8+‘!KčEŚťA\ßí(©»7ÖNg_Ććj—pB‡"˘'±|g»ř-[°:¶vAň5«ZËž+LZBaÜCm* ™ł¤ě;ŐČÇXfň^˘u’ÚU蔝es«ĹS„Ý8ކbÉ[XY_?íh•řň‡ {TjQlß1ÍM'`ĺ’-+Ü!íéń`7&-IO‘–uR-ŲWż#yCqŘNĹr\.(oÎ4fÄö j4FlkňŠB}¦%Rëzhk݉ÉÜ*aďż|館%ł‡Ź9–*Ő’d´l•[BmNvŐÁ˛Â‘ćesN'ÜMHÎÔăBs°J–;đňŮ%¬äśĹK;/Љxş^?l§Ö¬YĂńáhyČö#&5CAÂ˙Ŕy/“‚u;F4p1›Á‹Y ‚e–XŮ:<Đř¨‡` z"îcë¸×źaó{Ç}†ˇ)] ¤kg±b;kč> Á0„Ć…7âčgťmĚ)0{d«Žďǎұv±‡-®…Ő™ÉIŽĘ~$tY¦kËŠ˛#ĹpŹę±ÁF<ߥ•îˇ)IÝŔŁÓŢ<_ˇI”® ůĚ׍w»$!+‰Äę™/Äd-<ń÷Ëą°ŻŤ‹®čˇ ČQ´ŢGzÉč•,:Ď'['#Ą›kŘ.3ŞósżÖĆłßaćŘţ˛ –8iÎL4ů|…ąMרř(oŹJ‚żĽDe;š\nű(h‚BŁQ˛„KwźŞ5ˇĽq#ďSĄ&k’@yb o<&fXďŹŔy߸Wc3Ó-TsĘÄ*¶GłÎęîź:€Đä9«°żTQĘ ˇř:>'d‹Óĺ ´.JSŁČܨÓŔnŃt†¦ dÖ(A:íâŚ6^˛XŇ>śô ţ„ű8ş|.`áÝ7lËÂĹ gL@ŮisÖ’v(”€ݰ ÷ŕô´”Ř ~*;Ť@°Áś—Ąşl.^v;§ŕ.ä°˛Ď"Östźź­ńUEĎpÓá>“ŘţĹ+ů†« ŹlwŞNĽöł.§ň7łËëĆúLI(%‹ˇ¸H9s6ÇńquGYŔB+,_tó®á l„Jó5ĚĠñXâĂ­XśÁËK.¬Lµ”Ľŕî™®•Ô łtaó+“ Ů{ě©BŻë¨z¦*B:ÇŘp›GpIŃN­ŘTlőIŞMΙƹ€ďb ´Mp47éňiMó9®°2gđˇ‰DRI2E)×HśDäź‚‹ô8kł(“E +á™&ĎądÚaĘĹĘL ŹXĺda›ÉtăH,•Qµ1ëB"ʼnU`Ëja±•çđ!!IăÇ[ZenE2*3`iü`=ü”mqÁĘ9§¤śŞÉňĂ,ŚöDá%››;vOŕČ)4ěűéÁŰrTďEîS~)iŘKdhyaTI†X«‚ÍŃd±Ů‚c^!-Ű"jśŕ jŻ2Ó( žÝÝܮڰÖđÖž7‚»‚..ń»˘—™Ŕ4§6{9o»wĚŢGŮ."§ÚÜqĘC̉;úç SE†śţŞyÚ-ŔŽ: sŞ÷RŽZöÓö”äůŽ5śĄ-—ěŤÝâp·sâMŇ`˝2U[X5í6vLÜť…VŁfÍ”t.rHč]kő0Á"|áÜçčm™3 †…‹Ľą‘łşś#ălČŠ…Á_Ý(ríKĐůaI€.‡±ß5CŚnÂ+éěwń©ĹŮk&š 4NTK 蝯Á0$ťT?€fR$ś—Ôó}Ď‚MA,ł;z3S˛­śÉumĺŇ5[z#|†`ú$ÂcŚ›ét©Znń4ľ‡îĎĂ9NžmÁŔ!8–L8ČÉy›ĎŮĀǯřQ(4¸tBŤĆÄa^Ę †Ń‘­ Úc5Ô9ÉHşăľŞ97a)ž‰búÍ’ŁŁe>ëöĐ9˲:ăۉ†ŘnRŽjHó!Z4rĘ]®l+©™]ŽMńpF,‹3`:‰řâăbŞě.š5™Gw;ę[iiă´Xđ÷űIrj‘óq4UŇe¶!Ś«»Ř)#D‚âWĺßđ´cö®9#ŇíĎ-ösTh÷źž,ŘŔ(«›Űń BÓu`.ăhw…őkßqÍVęyx`ú;Ťěcz^H“δ8a×Oq< Ń9ŢĹn»]F}B}+,„úńŇ›Hö–Ě–ŕë}lŤO4\îägńäÝdöCb ?\K*Ł;ťĐĂV@ÝO%b“mĐŢÝÖĎýh¤—Íš˛ŘČâá,)Kq:Ś•mqúą-Ü©tLU‘¬ÄU–xYĘmĆXW˘ŃâLŞ>ć˘důĹ^WĂě^š¬ĺ0G}¶Łzë§Q˙•™›‹aef9 ÎŞ{ĘúLMYµ¤¬Ú” Ç>¦gÇV5`ňÂ>Ô ľ4•ö †Éa M ‡\®uŘ…Ú­Ń8âôçZ‰1ú©n»ťOp®†‚~ ¦ô1d;Ók'[Ĺ4ĐäҧŰÖ6ď`÷hnéC¶OF|ASPťé¬ĂË\EŁV:?Ŕ=×L}p'‡ŰŚJĆ Â>4K•€s˝ÇÝ™FńşŔCú kk«5ÓKë8°­a'Đá8Wĺ˛<Î|ělAłÚÍduă\xłH=Şť}Z>ŕ5äx)@<ËşrgČĎ9Jş˘¬C&'É^nđäK“nk©ňĺ2â·ŻĐś6'[Ő4µ±#Śź›ŠŃŐ$«ĹLÍmçÝK¬l 6ŮĂPm)MßŮŇ ąOS(WŻcâßÝ'QÎé-•öÜđ”O21“%!p^WX I6Ý@đCk1«Ô”m ¸ĺP|J÷KŁą…âSbEŐCĎJ‚C{˝tKj'śĂvE ‘‚3Ě@—ó¦ł Ţ©ëy -«S“ŇZY:qjşÎçË•±QV*9:A!0 ]±Ş#îvq·^Gç'«Äáâ‰)ů0ŃPžűŤŘ‹±%4V Řt ĆÍqL&&¨SČßBBOßă>pÝçlѲőĂ4ŰŞäŇfąőÝ.é‹d¸îę.Ćogô§h˝\oČ‹3`ŞV\ _d03GW[«Đ$Żň¨…4ŤŕŤś‚U±ŞŔ+Í×v’SmxX1*a~‚dm1>Ó¨zÂđw™Ţ[?Wó8ú`­ˇęś3ŽćQ,ş’˘OFšřĐbf©Ć¬4ĆIŞŽţá©'3%sóez'! T°Á“9µ'âťŰ­2JplĘť“őÍb]h){ťňAí§îÄÁV-«öfř*FĹV Ű–đ­!aćw łTĚ×)žž­ M#oĂőU–žâk©Ň~®Ž‚Ą  îăs: ă(Ă×2äŘ łůÝrŐâ\u/ٱ9€b ›ś‹Ł‚\rU®¬-p,p.‘Wő2ÇĆJHG1‚Đ*ÍźK9˙ÔrOIÓ'qź%’ rĐ~[٧špU|ŠĽń6×ůuľPĚŔŮ衝R|ŹŹÇj LÄCĎĆk,}ËÁĄęqků±RzˇÂUTĹ«:ľĐÍ‘2‹N”„AbJ¶ËSgż¶Oű5‚łŁm[ĐÔ«9“&GűP3…ľi‰ó`I8É ©]ĚE|NË%č8Nž ű¦«ŠM¶÷ \lČŁ„®vă.„HŕÎG±Ľ…#3(€Ä!¦[Á'[ŕŘJäŮĽŹŇ­|ܲ'şŇf(ÚŞCkI ËŤhí"m·¦ě±™Äí9|”ŁŠŃâFvwĂ,ÉrҲ L¦#ÔPëŇOË–r&Îş!g|ÄŚëśhł„Éʰđz‡° •-2ľäGŹUďč•PËi~Ô…ÄE‘ry…ŠěZ“ UW Ľ#Ŕ&@Ů´‹  Źˇ»I’Ů{SŢÔŰ÷Ňęś81Á9ąăô˘Ž:¬ ÎĹ8E@ ýt«Z^íôr/”B©4¨úâlŤí|đů žPdą·7± M:‚0«<îCp›ZtJ˘+–ŔŕX.şlzÓĺř[3‰Á8LWĄhZ˛Q'ËşÓÚ˛Ć>=))´3Ťr¶…ś°!:*>â™˝¸Ę”1` 3“.ß;#Dý€)Š ‹ˇČĚ“Dođr[V-×§E°ýăč€Ü»B=lé)8däŁđŔü!E<Ţ0’rşÚe1ŽGˇä~ ®xi”, Â-‘8 ˘2Ó¶Mnr©\mÖÇXĚä$÷m×î«y/“­:úz,ŤTRućËĄ iĚúřö3wČ ˇŁGb3%ëtČx\ăp6]*#dÚ˘—A>ďË8âđň&č¤ng9 9Áyn"a2ÉA'QV*fC,wyUV¦¤$?„O {ő4µbcm­š§é°ŰPŽTµeÎ7± rć ¸X§*hX“e›đl~Ă )aEę%Ä‘49Á×ĺ`sqĚ/’Ěpž[SEŹ®đ‰lek GU‡ öő wĄđ°“ĂÖAźôŇŐśŚ–Ş˘4>Ó˛}-ť8řfy~<J2Ć56˘Ű!ÉIg9Ęf ˇ—ÄŚAz’Ăĺ¤Ě1¶ç—L;ć‚Áů}’ďLBG4ĐšÇ:;bDúç’”b]Ovô-ĽmÁml´ĄjD„E•´Ł0"™%HËŞcÖźGSôH† YĎ€©5ĘHÇYj·Ě7pFâ pnÄŁeŠÔMË´‹ÓPOŢ#ŚÂůjžKË: ęĎËlBw ŁŔ:`˛\“vĐٱ¸ÚČŞÎŹ\~¨ »=6%rJNăť?1Ks ͢»ľe¨Epjť J’ L ´`_Ă!9Ęn.ÁaÎ$oq«ŮGP†ygś@ ö„BhńřDÁ¶ 2ÄrK)iÂ1™m*łbG(dK芌’Ŕ^3X‹‘üŕÎáX8Ş"Y/=É [ŃMÝčCjj {śĹ¬äj8ĂTZlŃŽĹÄ ěäÓ~rË1®´´ůšXwŐćuĽš*űÄ"Ú$–Fůg“+°hˇ.”ăâ'šgÜ?źsú‹Ż×Ůé gjyźÖĘůBaoˇ Ú@”ĺ÷´âŚ™Kł1UŚX§‹•™¦@˘Ď‘µCx7ŮÄFjŠŚ?"mFIĆ{ŔLhŰşKu˛}$P§^ęN‘@‡ťtŠ>CĹ&~zVÚŚRÄĄaęËŮžpŐČ21çĆŔĺžďE•)Äî…YpoŐríč2•rrł[pX…‰©`€Eă‡|82ŘI/ áňľrt™‡[7Ö3|cPRC'đŚ]8wâĽĂŇ<]VěuNĚÓ»j¸~Śl9ĺ–‹'8Ňe˘´î˛YOŇm1­‡M`)«ź·Ž:§ľ´ăF¦·R™żki0äňłÂd!ɵŃt¶w…Ó{^ĽjŮOĽÉIbLß©érE= :L˝š¸ŤFútlý´W¦Ń.Ě‹RŽ&l¬tkBí;zN+-{Ö{zŕÖ€"X«öÓJËňpóöůHOµŰŔ„3Ëö§yVp\QŢţZÂĽ 4g#Ţh;Ŕ6–&ĄYĘ:đđNZÎĐO]$ÉýŃĂŹČÁÔňt6µ8gU}„p)ć»®7ć@ďő:ä/}Ę+eLŐâ°ÚEšAÔc­{OĎâę~u%÷]lAV}ůAJ ©­·ŕ%=ޱŹäU€oŢŹŔęé`şeĂČgďÁ…ńc‡ßvähᦻď;rđŔˇ[XÇ“iś9„k70{žÄƇ _\µşJ[^áđž#{ngUDÍÚś$6Ŕć ä’î«©cObŢ'ťVĺ rjxpVő Y“iäö>îUĄĐä¶ŽÔŻp‡ Ži|ČĹ%EEí‚$xö*â„ĂNĂ*^H°†·F|s)ů‚˘„snĘąV,ö4.v‘çŹřE\ŕ×˙Ś?ŁńăR×ńă%Ž‹Ż=ß*–0ńŰř ŕgšú<ĺlŐ-ä,v\š:leĄJÚﱢçUMéö9ŕö íŽTŤźaF l.‘č~Áo’®Îď-^5Ů4–ŔŇ3—^ëXž©Ě~&ae}^ €ů˙ŰK†]fĹŘŚö,z;ÄĆ…ˇš×Ož7Ý”ů™Ľ{NĂžšúeVGŠ0ż"V;ÉWĚ€ˇĐn—Ák·K™Ł–ŁTă, 3¸ )T©·ňę.Ó?ŹfU¬S‡ôél^‚uM9˛:0°ş*@wO§ee…˙몫§3B‰wż…Űăöůç„„Ł’ßY¨Ôł~­ůĘ ÇNR Ű&”ú][7Őj¨! ŐKü¶hĎ’˛Ş=^`Ż'Ŕ-^iŮGQ·KĄ ÁŚb™’\/¦•ëß´Lz3@0Ý,öőŰŚń; h¬;¶íorěď7Ś3%—ŻŰ݇߱'?Źýş#+:§ş;iÝÎ,|ťú:DvöĄ=/¨5]đpnHgQ­ńÓ®7 ô¸>ĂĎ—QĐIÔ`sĘŕC NT˝®ńVú{]Dâs,ÄígŮeóŞsÂďĺJßű6"o×T•ąa,ýĂťIwih“ŢnBýn6őö¨ęwĺ §‰Ů™›¨‡sZ¦wç ŰÓźvŐo-©ü‚†:ĄöÚ2í%’úT~öżţ9AVd^†´ľćp^‡"==g‡ş’'„MśŹ_O·>÷dxŚđ2]đşéŰç˛UĎ’›Šţ;ħ^|ťműß˙«9|äWŤţNN˝SÁđ§‘}:řZřÜŮé{š¤#8vÇŽŕŘ;‚cGpěŽÁ±#8vÇÁMQóčŻóě<˙w=]Fěř˝lcT@!Iâ_ŽăGhü:id Ď ľEXĘä[É~)ö úŻ›ë„'+Hť":Žt4;ŇYMwVÓťŐtg5ÝYM»ľę¬¦;«éÎjşłšî¬¦•Ő´$Xĺ™Ű¤ńíUÇá!Ę7bĎ›W2¦§¬@'IúÜOË˝‘–{-÷&PîM´¸Ni?ߌÂ7)ŢoůÖĐrnŁđo§Ď#†L›‡iŢ‹”°ú| Í‹ÇgŚŻź+ř2iţ"}–čӢ홤ďSJű& ÂĘďw żäĽ!t?%q0=Ó p(|MAmVů:&ÝŁBď’Ó«jz\NżHMOř×î™jţ¤śżß«5ůµú©Úřv~|ćKÜ:Oó?áó„ĺ¦är_¬«§úť_ݤđš‘ÓźĄ¦g}ń–¸VÍß-ç§ň¦¬ÖV nج„żí‘ľŤSÚžŤŠË^ą./UëÚ'§żLíăAP˙íÄ˝vnĂşć†ZÁĺś\ź?o¶rř4·ç¸ëU'źľą ü Ő®dE9÷Zĺib·AƆA2ýŢ<ŚŘŕ^8č7üű@NżOM4ôý9š/7©ćʨɭâôm5Ź: ř}X†ůu1ŻPŢź˘Ły•ö CîŻ)2÷3©ŢM#F42•óßď—UęJ?Ň…p—ţݵTN˙ˇšľĚĐwWŠúNr×ŇŤX‘ićW\_áĺr:DčŠňďőfÓ:ÄĆÍ>gbđ”®+0¶Ňđgpçľ•Ä;„üń*ůă+”ÖßćGˇŁůB;9?ęřg(°Qď×h?nżÚ·1‰;ÔüçËůźĄs®ŤýbĐ:0N#yţ€qí $]űĂ’zΧ®g §*.ÂÔsŤ/NŤ‡Tś®•óĎ©éú·ď…uśŻŚ §2Ľ_$ĂYżë˘őÂŹkŰŻŹu†˙€[ořĎ(ät—$·Ńđ°h—Wý6ŔżXNnP^"ç?®ô×!(ĹĄż±|©Ž1Ą‹řVéZKů|łüůTđyĂŹqëѬVĂŮ"ĂáŐŠ_uŐfŹgńµě§lěEK†µU†µ_Aő=j¶ÉůW¨écuËšÍ<ő¨č;ÖXÁw…éSr¶{T Ź¸şÓĆ÷Ť–4•Đ`Ęő*ťŽł2ńé™ZŚ.‡3Č2 ?“ŢáyňĽ•<Éň§'čł‹>)ă1KǍ²JÍ‹EíQŢHR„—"yăNţ‡E>°×ꨳA;ĹŹÍŽ#eÖžÄí nw¨zö±ü‹UV.Sž-ŁpVSĽ­ő`řěqŢÉŇ&ţ˛óŕ»ĹŞ7“ˇp|ţ"ö ©oŚŠ}¸ŢYúĚĐgšä{)KďxčUđ¸–âq5ĹÇjŠ+×…ÓGŢ_Ćę ë»ŔĄ[˛ę[Äî A/<ĺ28˝ű„ţ/ęđ=‚óvň*6FW·¸]$ß8{'pÉJżînNÍwS“ÔUn҇B!XĐďĐ""X­•f‰Š‹ě§ĎQú!źeUZ¦k»X¤á,Kés ©ĺűtyÄÖ/_ÄÖŁôc”;ÜĆŕôąJÓ$/Q>Fg9üÝyôą’>Wzý>K?źäżrŰ”!oulPÚŹż»Ŕy'KÖţmżć/*—üVżŐô™3$ĹWQY”˛äé2bc:©Ŕ»ś…-­ĽĘ‰ŃĄnßZ€˙CĐĆyŤ~YÁ˝´ü@ź°™óBCô}ŚJI¬ozů™˛ŚýuŃţÎoĺ0zÁK±âľ#?Ă­¶…öӆ wß,îrŽá).ă) Ć ŠÓ]ĆĆh»0×ĐçzúÜHźHľç˛|“÷ăěýMixÚ!˙NŐŮłQnŘĺ++Ň…˘Ć9kńĆň Ţ›čsI˙Ăăfca’7™;Č\˘ß8]ćŤ_É›,Qq}/%őÚĎŢ·†j/Y[łü‹=> yÎe[đP˘ÇőXCë–4Ķ7+?Më·ŤĽŻ ˛çcˇÚIć –e›»ŕ|4ř°Ü™qŹŕóµ|Ţ[Čű˝ě}{DĽl_DĽDáËç¶\Á—ł\”~_8ţ"dŘĹ,źÂ‰1ţÂdź ö’4°÷4 ] dhČ‚ĐăXzČŔäĄQŠ/–- ,QÂůJXB. \čŚő l a# ë•p±O¸„†KiŘ ÂŹŔҷѰ„1v€°“ö~9 WÄ”‡…+#„kA¸Ś†ëh¸V6{gyv)á†á7Âśç 7pH‡ şouá( ¬Ěc ÜéîáŢ€p? Ç”0qć! _Ayťů»TĆ®cQ†Áe:śĎ=Іq”®…pÚ!đű>ńŰmš¤đ±®—B®Ăqq7„©ţËiúĚĐ'n#^Űc™“mSĹ —ˇHDÓ&ˇˇ‡ď†áŢůĂąO÷®Ó%Á‰ý©˛Uë7˘laąËeôŃM¶-ňŰĄ×nvÁYÝ0Ĭ(öHŤŁĐCĚÖŁ0˙bK ŞŢ™­"ŢůĂ[ďLëw<ä¬Ďń? íđ)÷ľłQ.“˘Î•â8ŠT·t‚ҟ۹\%&&M%@HEąsěfĆŤq} „»nĄ;öýľăżăżăßč8Áwú¬ăżăżăżăżăżăżăżă˙Ěg€ŽüŽ÷•Ž÷•Ž÷•Ž÷•Ž÷ď+”uĽŻtĽŻtĽŻ´‡÷•'ۧdçŮy¶Ť/SĽ=E¶Č™Ľq>h-§¤3x Ů‚9č`ŠîŔŰęĺ¨ihOA>]ŮĘćRxĎ ßë¬?QÁ†Ëú… ŘÜ·^¤}Bś7A{-Űł„ŚłDÖŐ5 Őç€ ŰtŽŰ·řHR‹‘n®q˛RÁC7«Şá|ń"@á˝r“˝ŽTrCßc”‹GNąQQbĎQuĘâö2ŇžžŇHłÚMRřR_jŻâÔ‡¶ťÔ‰R›°Oi™ĺJž:jH ěÜ0ϡϰÖ¸lđż‘Ür˝ó;6NŇbGéó€úZ~´ čTDďńkźĄĽnŤRD˙Sş“ě_™Ľ(UĂ%ę1Ë-u»żě ĺ°X1ŚÎhöÍZJž©5[fńD”q±ěßQ|ňůFřˇ×ă ˝ÉpĚŁ˙ąw ˝%řÁČMXň ?łÝż W9}¤üHiPC~ż4¸7˙°-G›ČVŞÍÚŚCP6d6ó ËnÖkˇ ÉěŮjçp\ťŔ"đG›U5[vůtp«V®@ŃŚÚIÎL2[žŞY­Vy‹pńýá[%¶„Łń`”ţĘÜ÷.ô8±e̵H ćľđm4č&"Й݉zjńg÷ngŕ„zÖŐ’UĎ"häôíßG,¤w@Ą>u°|BšŇĹó—d-řüyC &HÜďhâ~—Mt†f ÉŕR3DL§‰¸‘%¬=ö"ś—úˇ}1řýńŰxýÍ…„^ —Íđ›[Jź,.MăŇ4›ů:ŞJ\Áf˝Ý†8›7Ľ}Ňâç}Ä4xÄ>j1N¶˛ßÍQš)}.ŁůŮ4żÂ8ăs‚cőÝ0˘źÇ^¬{×Áéň‡óÝ»Nܡ ő]'!ĂqůŁ’=yĆ^_~ý‘’á˝,Ź/ńh÷z©xčTż—ęçő„ő“=zĆ~O­VN˙}z’ĹĽšDęfÉŁdĹ÷§z„ýFÖÝv/Ś/¦Šá.ŹxőŁpġ‡w–D=Ľ„˝~Mę'ĸSL±!Žlľć_,ý1ZfŚâű1#¬ł§äęÜnx=·ĺŠţ;ĺF9ÚNť*9řŹB7éE¬÷Ů;ÚnP§R1î(ÚŮí§µ´˝_IC8ĄŠQÎ_ŮEÄ× áĹYY ÝÁ\FĂ84ÁXetăţŤŞśFŹńĂý°â†8ÜżÚňđHÁ2Sšö ĺ„Ęś$ťůś«ČB‘fČ >ý8Ła<9śńÜ–+8ăŮ(7 g¤ĺD挱E¬÷ŮćŚ ţ …ßµđđ¤9bpv)¸†őÓ­cN ŕń9ćČ B·G衡W Ş3MzĽďčĽëy4ë3›n+”đ‘Ř*U‘yDdPQ¦Ň­äâD™ÝĹ‹3̶%ŤYŘ$čs,S.YµVy’™&Ą*ć„UiF~KVĘ5+ÄKŐ˛ą™ 8FhTę­˙ĄżźüSkť—ÎK{ĽtťäÇmk–ý‡ń$âŻĹ+hzŚá(ngOc^>S1*[–]e,µ«ĹŹ·µš',»fU\)Ýů—ěúš‚Dł>۰ëđÉN6)ŞçS ?„­ä“ŢüŠi>Ц‹•žć†żěŞTu¸H•›uŰšâ8nYŤIn{®~ë}%«XŻ6ęM«”÷C%Ši–[¬+V±4©mRĎMőJëN4,[_aŃŞlŐ*5ę•rSŇćińFŃJŞaă˛ţÇ# Ľ÷ žÄf¸5>}'𠫍G"A7á¨$•9:sš»iü7¶’f­>kňř:ŐŇŔ1ţ.“U>ąÇ.WŮ)żl Ťd@ Ý%4”ć źŪ2 b  hŘ3ĽŤdÖLÖ°Ô¤Y-Wřč”Ç›L§ń)Ţý›śnY˘ürm’•—ĹŮPű¸´L ©Ř‚źq^`†úŰBWÉĽÚaë"ˇTUj… Šţ†Y¶O•›VÖ¶§Q?eŮRThĘëkVëőÖt›Řs|ozËŚ·ě™bëč8+š *Q K{Y4čZţµč§nĹcúx @`?‹¬BZćđĆx”@˙VBĚ •ÔítEł ¨Ž¬<>ŰÂź,÷8˙ ÔiTš›–ÜĚă=Žá`#Ň8`Ň™JŘ…ŚM 84Ąy•ňHMĎ >–=ž—GúxöEâ8 đo©?RřÜOÇçń\8]"­óňD<*'JŚGI“ÓĎyŔE¬i€­.ĺ茳ČŐďGëLwýÓxÉ)2őĐ#P Ř>%—ÉV y‰i‘奻– ŕfi§^ű§×Y‡ć%vÚGâdZÉHŢAgÍę®H źbŻčą ;ď:Ia€¦(ŕzY4βNäaN„„¨A'Ę=Ŭ˛ŕăDq,ő;Żęt@"FyăŽŔ•_Ť’Fŕ ŤTE Ň& o†+}@ă*RÍĹřˇŻŇ#‘ »Ě’łH˘_zh`5,gi}<ú˘‘¶  +˝, Yča(Ww÷ńxĐßÝ4ŚTŁŠ2KÔx(ĐP0€nč±8E¸ée±@ġő’YËÇ-Ĺš`ń4“<ŠIśŽ:If EĐZ‰b€ĹČ"-H"m'‰G´Ç˝“wYTęa±b&ęeQ€‘Ňş¨Ł…f­j0#Hž?ÔŠSCnˇŠBŹ%ŤĽ~' =zdO'lŃî•G[–EVd°ŠřE«ę–¸1ˉ€(x‚’ĺ?˘Ä.•“$QB)Gô‹’ P­@“PľTMS¸ž“ęă(FîDiNS”hĹ\ËŢ%^G©Qň†@´$áĐ‚ Ŕ—O×9µgŽť Ž9Ž1„˝ď “Fř‰áń‡ŮY<·Í{ĹĽAlńßO(L?¶Üđ>“™5íüÜ)$ ÉçîůáĽ}ó˘€ýŕ÷Ťŕ÷Mŕ7>ŢÍŃĆ;÷@cí1|‹‘ź±63Ęf7DáCkě]ÍGAđí4ذňCܢÂÖ±uřŰ w”ţľšÂŞÄxr#€Uˇq×â°ţn–=HŰˤĺ Óü+é7Ł4nŤAngbë8ďM ý­÷rÚî›AλŔ=ʦ­0ÄMu«ÁďóÁď @Ů«(¬hSŽ–ŤŹ)ŕ>Á·ᛕÖâŘ‚í‘×s–Ö Ţ>u5Ĺ1nĎĹ4/>_{)…w čśg3­˙úÜJóĺ5őÜf›ĄX=wĐzâŰťŢä‘ÖçrPź]4«nĎ› qhÂÂe]ĘĹßÜ…Ân>ä‘÷nšŽëw- źˇ}wť!č÷ÍE4`ü]OëńYPŹ ZÚ‹ÂŻ(îo0HďŁßâňn¤02˝±«Ľ› A7ş<ŁîŠË[iÝFűëČ×ŕ6“Óáö ă·Ç(noGĂyČ#ďÝ$Ýi˙(ßů´­w*寣u¸›Ô!vRśóŚăF¤ĂŻ®ĂťňAŽŘ-0Ý |Ľś§0ŐŁ‹ĘˇÖ+tß©pU8~í8ěúš_>Ô»–§«ż|ČU†¦í2ŔíĂjąňaX×aŕCj»”Ă®J}o*ŻúčĘ—»şĘżM-?křÓ“|„5¶N×]=zd¸O÷Ăz?¬Çł _WŽrS™ÚŢŰŐöôÉí9⇻ŕďG•÷Aőë÷©¨Ç1ýëŕ ţý5(§WŐô!9ýYjú°áŰo·+ďwčÚŻÖ{ˇđ`˝Fd|ݦ\üݨüÝ]j{—D«ßÝQůÁRĂżż–ţýµÜđďŻŃęOXĽ­4BŃí=aéöĽłTĎUř]-§ß§¦źořă˙Ă˙ąhí:ľČăE ÖoŤ/vŻZ˙µrú}şţďˇn?j.÷BûߢÎ7~rĆE†7Łż¨ů×Éůoó¨—:op´ë./8ŔĹG‚¶ß#KtodŢ`Ž« ü$ël˛ŢQyźąĐQľţÁś~>Łü;FůvŚŽ“Çhâç0‰ç·ŘŃç }ô;Yú}ö“xk^ĆŹĄ' žŻ–ľôßŨ<Śă1M2:M˛Ł±ô›.úÎś ,¸QŮŃnúaň ” Ŕßb;Xx¶c1ÇĎ Ň¶{üĺôąŚ>—ŇçJ’oRéÇÉ ~ϧĎU$ťßĽ†>×Ňç…ôąŽŕë,ßEä»{_OŇů¸ŰHź›Hľű)Mcé~L˛Î:Ş`|çň>i*EűSóą_7ĐçfúÜJęk˛únˇĎ<}^JŇ'Xú6úő‹]Hë×’ 0ç ĐasŇăü5ôĐĐGĂ {ďa†AX~ö>‚ź‡Ą Ó° 5m%«Î0¬!GĂZ0í®Ła=şĽ,mŁ6Ńp‰GŘB>D`eoa»AöpŘ ‚.ďe4\áXúNXW‚€÷%®ˇa7şĽ,íZö„×*ÁŹ–ö‚p űA¸‰†›i`4u 7p“Gž›”pČ#¨ůXŘ«†Ż# 5Č>· ËËŇîᮀp‡zDęTĹ‘Á4·N=áč›®—Áo߬Öp=®SëĽ.źßÂ˙5íâ–JyÂ6íą-Í–Ůjn9˛Ĺ¬ĎćŹ,¬@Včž Áy÷ŞĽ~˱¦e7Q˝ę5«˛e|®VÜrŘ®?`ťęŮ›‹uŰBŹćlmËÄLąRr·B*ÁŔ^pI˛}íá UŮH|g‡ó;ČnĚVkśž©ť¨ŐOŐälMś jrh| ĹÇIuĎ#YkĺŰß˙ …şşXů–§”óÚŠĐŐű#cRĄ› ˇ… XϸšÜş[)ë á ‚Dą »żîĄYÍJŮlj?GźĹ7ź‹Q¶1h”ťüÖfyM[ĚáäN{ˇ&ţŰmz™n{ Łĺ–s–| ĹTđ­,v;MÜx8˝®-h†ś˝h´0şąő\ fK ÝŘe«TEŞŤ‡ačP[ĎLŁd¶Ú‰+ »ţĺ\ é’@ľ\ݵ¦ťăąí)Ś™÷¶µÚplu}żM¦^j'ě`PÖë©VłMPÂć_Űb-U3'kí‚ ęÝmÁaČQÖ6A #k‚É·ÍPÂXyS[h±ŠőÚ$>,ŢxˇźĆʶ…R{ćh3ÄÜŃDCŹŔ· nđ`zK[ě(ď m‚n¶-4'ě™ć łŇfb^צ¶Řßs`o›ŕ„áĺOÚ/>ř`›ŕăä—mÁO4Űm mvŠmA?sŞŤđ´»-V Őz ;Ěk´ÄźŇĐ ÓnU¬V[jiΉ."p»·öBMÜl ÔL”ŰHĺÉŔ=Ôró¤µŮ,•Ú A]‡¸SóÚ˘şŢÖ‹ĐŮâ˘ŘJ.¶ W˘-&÷FŁťŚM0^’ç/¶[µJs3sĆÚVřézg[čK–]n§Q…1ó®¶Ć{ŘöBMěŰmÁlŞ•vRë0•s›‹psrƬµÚŽŰÄ›m!˙ şÁÎNg¬Z±ťÄ4ÓT¬·•É’t×Ăm±SŢ´*“ă-´TmLaZŇj±†m•ĘĹvÁ b+Úb±uX!«g·rűó6CÎWŰ9łf[1gŚßh Ä0ďm‚†śŻµ…>ő”UžšnYĄ<ľ§ˇM0„±ó›m±ś0‹“m‚†—GÚBwqŞ\)ÖO·»iŹ#äZöAKüâ¶üč˝:m‚F2Ďo6Ó6:w ŞÖôRžś,×ÚEÇŃům—¶TÇóç7Á¶]řň­<ľ|«˝ĐÓő¶ĐJSS¶5Ő^Çc0ńěh  cpAď‰j#1Žą-đźÉęŘĽ ±;ÄoCÚřNg>Şúń‹đ÷Ä#J˙łĐó["m=H{ŐĎä´Ť ííŻ%i\)GâSb‡Rßß\ ľůŇsĹ7ĎßÜńc©2C‘´«żHŕáožľ9ń ôü®('ľy;—úĐlĐoľů<ôüGńÍ6‘68öCôü&X×’řôŠK"fúÍîŹ/hč7—==ż!ľą |sÇVQÎoon˝…Ä3śß”ďAĎ ý¦|źTN×ď‚´ý’ÔV¢HZf`Tôdc˙"ň,s|ű€ďżŇî˙gŹ×ş>÷ßD˙+řć_–Úż|óźcâ›ß<űQ'OiC‰ß}ü2жŰgNpüżXßyŠ\ţ>ëČGDůż`U?&úęÖ÷ß!ĂşŔ:öVlŔúŇyÖEüňź,“éë€eŢ"čë÷E|¶řB˙#ż"ýi‘ĂĐÖÔ7ľ^.â»»vˇç?řX[MąŹo°ţňď¬?°ľzH´ń?¬cWO8$҆—˙ˇÁĆ7ńAâ{¬Čmą |ół E˝ |óᛥ~!îhÚG'%xä,4Műř#úńđ8hĂłß*ʇ'@Úś–ŰwŔţ‡ ÇI<&âWö~Dţć‘Ö;úŢ>bäAży~N¦»»Ŕ7ëoxü3źxüĽ‰a…őĘÜż÷Xů~AĂďńÉ ßŔ˧¬÷|W†u/€5†ťłŃńř&kÓŃĆ´?/ű—†Ä;ź`ít÷fkŰ›yń €ő‘OËőşŔ:şKŔz €…ŁéŘŠgEüŞŃkĐó{– `˝ŕ;÷`ŽJ^˝Nŕ«ŔÚóSąď'¬÷ľ‹—O¬ż)¬˝o‘űľľůÁăb<Ľ|sŕOIß3šýS6ů©]€f’Ó_cĘ K@^ó[r–´ź7$ž6%Ňú†Źü®ń«_ţŻ2Ľ2řćšW‚oľ»^ĆÉ đŤőĂ‘ĚŠŚ¶­1jđńxž?˙iG ‰ßT¬‡ž´ňçÖłţ=˙‰ä_%â/xÉ—dXuëµOýűvë- Ľ¬°^ń+ÖIë+ĂŰŇőëݶÁÇüůÖ_$dXMëŰ׉z˝ŔúČ»ľ.ńą»ţCęăűßlđ1˙.ëSóśNăk¬gżH[3@f\9ŔëElP(¬Ż˝ÍřÄ,řĆ‘—čx||ó­ rť+@6y«<ßK-ý=C7?s´ űW2n·‚´ďî”i{»H[Ó˙y¬ěi/¸Óř×ĺ í{×Ę0Żi˙q‘ s—H[{ŢJů»Ý í3/–Űp%HűŃź—ÄŻiŽcąţ»2~~ťC‚ťH˘sčwg$ZĂ'-Ś®'Ť{–ı=4>&â™ÇIĽnsäžAC,Z“ř*á&,2°5dĆ2§,ű‹yIĚTĚçĐ«ěú˛ Tâ{u™A'~°Nęŕ®kAÚONFüżE‚´˙ÄdÄ?CÄ/~Ż ď&řÍçĐóµä°Ř[˛c\ţ‰ź˝B”nK®Ŕ&`ô#ŕ›ź˙¦Á'‡ç€ož//â`Q·ä%Řđ?Š´ç‚´ů#©~q°°[ňă÷Ăgiż%Ň–ĆB$t`q·ÔĽY†ůöĐ”Ôţ®÷‹´ OÇŁ`Ć]pű†Ł˙ %ö OÇĺ9g™Ř?*۬FOZ¤}¤Ý± Ĺ]/Ň> ŇŔ×*>*Ň>Ňîy /ii÷=*ç×I ľyĘßPSŃőiVxŹÜIʉ´á'.#ă? ľą˙ĄˇuýL¤Ťlů>ş>ľ1[ávýřćÚ‹ .)ýµ¦ł'Đ,»ÎÝŮEĽŇ}öŮíěÖGľúEQŃĎĆ•VĘÔüKđÍŁŻůřÍ/eÄ˙J¤ŤnřSńÍŔ7Ö#RG’Ăuô›Ë°BEž/‚o&?,!>ß\ůeQÎß‚o¦^-upěAđÍ=ăR˝ÉéšöĹ^Ă““ŕ2ţ”1ý ™ ţ¤•' GÝÄŇľ¤!ŠóÄöą‰˘ňtôřúYć_•­c‡Ţó"í+ ­(7ľL¤}¤=÷G2| ¤ýĺ*y„=Ňľů=’qgŚ« Ţ»ĺ ŐBď·ÍŞuŞnźhn9’źd/[ŽXÍúŚ]´šz—Ěy»4á€N¬Mtîźa÷4;Ĺł»dqű rżÁy´_°(¸’öÝš/˝×˘ qIšWľWÓ}/‘!ĄżÓńźîžłźŇwń]—sµAßá÷}4ďjΞ1Z^Ś~˙ ;řÝc–s˙E˙Æë/®ŹżÔęű‚wîÝpő 3ě~Ö/X…µ¦łűa"ŕ^˝Jűdw¨8a÷Ě,N»ťűpŔ˝áĆ(ţöqň;K»đÁîá`řĄikčoF§(n …Ç‘|oĄAëŢłÎČw1š?Fó©8ěőÇábŕőĽ&Ľđ:Żlüł;–ČpśPé¶=nÖć = a 9*]“`čÔ€U{lŕaŹ~ ÷µ÷,Ą÷˘÷ČŤDOҨPoÉRoKóDy ÜŞdçrT$Ö‹™0±AÁńŤ`„ܢŒĺHÂG{V§ÎůË(bĐwÎő6 ůŁůěwŇŻ+OŃďĺkĄ‡ŇÓÔtyÚ4ęJÇÝč1Ť*×—“öFcOŁ]‡ÓlŚÂŤQxjÇŹ7Jó®đŮď>CđÂ~š6(őűf[CNWo>ż1`*7ś©ß†<¤ Ľ.ßň»\7µĆ#•Oľ÷+_–2oöMĘůĂŢě«Ţ\»h7űÍuŠôRđĂŻÚßjűÝřŐKŚěŁůË$đ«ÄOÂ/şř ]†¸14n$s»¸9N)\Ĺíd|â⇠|¸ňb!K×ݤ‡»ĹÎëĆĽEíÁÖ›çÁâ˙í"¦‡HŇŚäeG~G~«{3e”ÓŻRq"Ěáť§#0ňđRűBúĽţľÁŕ×öáü×Ě‚Sdč[łĆ4w=íi4*ĺ˘ŮÂܲŻjŃ˙ăă[¬V?ŹHť[˛çQç_Ëí/W¬\sÚ´-츠Ů0‹'*ułdaĎ$×v”ë°i·rőÉ\kÚĘÉáLć”uinşŐj4woŮręÔ©üěň_<•ŻŰSLîşťäA0öÖs6>’’۸wSnŰ®];7ŹmÝ6–;ęŔÜ[·­ÜQË¬ŞźŢ>=:]nćÄ·_ýś´-TéúdëŞ÷•ąąúL®hÖrřbłe—'fZV®ÜĘ™µŇ–şť«ÖKĺÉ9%Í jłťć´,»Údm»ńб܍VͲÍJîđĚÂmî`ąhŐšVÎD5Ŕ1Íi«”›`ŕn@ŕđ‡űqŤĆiŤrűëľÓ+Wć¬2J·sł¨ëĐ{nŚEá^š«ŰÖzkŁŮÂͱsőţ|jĂ\®b¶„ĽŠ ë5x(ĺĘ5§Ľéz5vÁGÍ?U®TrVn¦iMÎT.Ąö Hč›ÜťŽŢtŰ±Łą=‡îÎÝąçČ‘=‡ŽŢ}%ú¦5]G©Ö¬E –«řP¨É¶Yk͡–Q@×!@·î;˛÷&ôĺžëüŠ?tW ˝ÎáĎ’5iÎTZeôÝűôĐ‚ŃfÝFËĺ»ćn0[fčr.ęąQëĹĘé+ÎŃÚ(lýo}'ęöWE( ÇŞ•BĽ˙G(ĎŹ"öŰmŐm¬#W.–´ć1„©€’¤R˛ÍňTŐĚOU‚_XŔ–jfp3<$;Pč)´®źĘ;"łˇOýúîθësNˇ;hý_ y§ëĆh6›yvEHŘRz—~řz„Rj&â-ĺđ”¶ěoŢŹž?ŚŢE2źq¸Ŕ»\5yŔÝŻ@fĂ•(•2Â|™ÝTŻ´î,×P—“ĂŞw}ˇĺ7ŁŚTvâżV Á'˙Ů0.Z‘Ú–Č^€˝DÎÚđW!ĎŹĐ–!‡fĚJxŇ^[C|3fG#:ěE­žč> :iÜźćÉ™zsƶśrĆ"ö<*qŚRéĄk0ŕŰ.ŤAd¦jµ¦" ś@;_($éŢ é@€ «ŚÄ}TČŇt*Ą'î8K’.wAx1 TçŘkçĄýâ-<¤đuÇŻ®4ÂqśÖăh;©“‹ÓË .VđČţ4ú2ö‡FřA—ż!_ 1 §¦DHą č~â™ÁŃbĺC”°ô[ż‹ęół%ô–¬Ů˛‰=ż†#†}Ú~7˝Ň8 ôŃ_ĽE˙QčY$\5¶…«ú & cĂiŕľSëęCÇ›­“{šsŐF«Ţ˛ňP"îý±}¨÷_ˇu#f­iÚeâkl˛nWg*ÁĹdßńZ„őťáÚ)#Ó¬ŐgÍPsmöĐQôx(B[zŘM~aŔ÷=xzĽ)¸ 2©!4ÝaÚy4ĹúÉoˇŻŤ2éÝ•agÖUµúůĽ%(˘HŘ‚6ü5€ß‹PĐ`Őś)NWća…A×Ň«20î]ĺ,7›`e-ÔóÉ_äśE¤•ÉZ˝ĹeűŔBFľ˛/X†ó-CÂŃqءyáź"îü­=5$î[Č2űuh(\ˇŢVłT6§B.6d?@­äŁň—Śł4 5ţ‹%ôŮî(j5Ç®ZÓyć(7¸!ńŁ<‹‚(quxŐď˛ăŻAŮţđJ“y¶J…§ Đr1Ţq pI“íÂi&6}ýă(-™˛Z{ÍJ%4^‰ňÄ®ŽPDźčŚf«Üw#˛Ť}?*ŞüU5[vůt(ěńkP§4B;¨'Śüxáý¸ |rŤ| ëě12°”ˇ·==^ˇ” ‘ÂÂaďýşaś˙´pĚĂG;ŇZ¨vŮWĐy_D2čfęÓž÷?ýۆ±,@éf-ŘuŞŮhŕI9xÜŹ<ŚcĽˇ‹z!„a+CGElKÄ&lŘAżfËç5üE„fôO–[X@ [ÂĐáĄFtA’ ÂaV™Z®\˘·µő şBSďÖ`Úúöz$&†íĺŽáwW„•!úošăżyĂ4CPďüšľďŠ@\Éeť.VfJÁmŮgß©pÍ‘ů§uşe›Ĺľý¶9cĎÚÖTđŇâ9h`v=xČëŢ*C0Ěţ˝h|ŹE$ŠeUó„EÉŻe¦^ňí?ЏßŇGf¸°\xßfô˛c4ČoŽ[Ćę?üż†±â3qÖc7[Ţ兠뵟Dcµ+` #w;†ó¬ýčŁ<ωÚlÍš•«¦ţĂŢŹ>˝$"ŠšV­ôŃ AěƬĎ÷v×˙AÄŘł€±É™'Y÷ůi´ÜK Ěź]#Y°e†W®÷˙5V%ţeJć7Y„^ý˙ÖĐĘ<` ·âäÉšB—{ä_?ż-"!,a˝Ó$˲f;8î¤çÎ!îň'šłTŃš”''[ĺbî†/ţ ăä p*|DkŃĐ}ż‹‰ľg­\)7[őÉŕĺňSţ!íµá)[î)ů^á°2BďÁ_ átÝ ×(„¦őożĂ0jODˇőIÇ©qxyńźÓůă(D!ůNF÷Y°DrŃĎ ăĽ€˝^E& U(ř™O-GBU<üvi{XTŤü-ă. Pfy‰ÖaV»™ľĂ0¶^ˇ Kj&“ Ł,x—˝ôSÁ,ô«©0őТâĂ ă©”§jVD!~čÁżAto¸reŤńîJÝj  «ď@Kä€E˝\Ý iµ¤űÎú—¤ÖO UÂôĆűĆ cĺ+#4c.ÚÉÝ'ÁĂć9÷F2ĘÝФmťÄ—3Î…gc˙çBôý;˘4-ŢѨ‰ÄÖ ľ}řx„Rúť‹m·‡.a ÷YčăJd …yh‰żBěď«©+m–JˇT^éŤĆć(–"ÝÖä¤Ul…’Ňoű Šľ6 †Šő:âőřśłí˘ľď˝q°(űεŕÍ™jŐ´çBqÉ qúümQX›‡ÁÔÓ— FhfÝz §!a2Ţ˙ćpJ3O¶ŰĂ4Ť`5ăęĘF$¬ŽŘ¶F ¸¤ç8"ó{˘ôO`I<„šńÄÖ»B,ČAĽ°;]K˘ůs B#q8´ŕî˙BĚ0Ę:¬·Vźo ¶üŚźŚşĎŇű˛ĂŚŹý5ú.Š%§×0ŇÜę{މČďßĂ -U•›ő0ę·ˇń?Dßţj±Ů)¬€5Đ÷côxaÄ.ég·;Í"_č·ä ĺőşŰŞXłhqâ"[Ąŕ ý‡żD_oŠ@ĚŞ#´Ůůôߡč( ź!!d…^š< ÍUńÁÓ+.ÁAĎ#ÄbO ×-nš¦[î!őţ–7ÂíąË”6Ó(arXzŢp¤†Ő}#ŻaËXýž ®tó¨y”¶†úVo™­™ŕ9fĂ3đÖu€}«ĚŐčB;ÔŇ'óĄ˙FX YnÄĘ©0jýőŹ žÝôaaĹ,{mĺăƉtIwirÂj™ˇŐŤhś8ˇ9#˘9-|Ťm(mŰÚ|ĺůyÔˇĎďÉ #éĄĎ»!űż€°‰˛c°Ŕ†M°Tń¶ď"’ůb¸˘ôĂfĘj¨•[eł’çKÁĘ˙ h˘Ťż1BoőbŻáuĘ—˝E˙Nř}ĚZáĹĄŢ ˙=˘č‘‡„=Ič•㾏 2ýźÄÖ®ę #—ePžő+@mb…”ťÖ>Ř‹>żeIúܰ“ÁĆCH¦í{s„N=aĎ4O RŽTÎČc hVź@a%ÓÚ‡'¬e:č®™ůzµΠěŰŃ·D€ŢCŽR9˙O8·Ç ~ŻCKTŠ or7tęŰDÍ:Ła‡7»˝}~ŢPÔ"Ę%ŚŞbđĐżˇ/3Qz™+TC,”°ŞřŕżF€ŢW4›–ăÝ&ÔLÜűÄKĐă“QŞOW‘ˇóĂż@†ÜĎŐO’LąZŃý~|dŕ»»|Sś6±É ^Š ˝ íîuáÚ&‹f“vŮ*UÍZ4ĄÂЧ?Ś*Úˇ«Fŕ‘°Ĺ,ýó †qńćĹŚĘ–ÝÓĹĘL]©žOˇNZ¶>B9˝ | }Řv¬¸±­z¶G€Ď—ȡuŢ˙’C_lJé5‰Ž€FľĚőPË˙1üň0!˝îűŁżEd=¶Ŕň†Đ f:®§ÂËMĎüzD1ď.ÖÓVÍj•‹áU ˙†Pťya”R€dv'wŕF cóÝÁČÓŮ“a†­.ýÚQ˝+BcŘi0ĘąÁéŐF őu€BĂ‘4Â’ÜúOB#5Ŕ‚sóv“oť*‡Đ2÷&Ż5Śä…0—!BHdýŽš;±óű=cřM°ôo˘oٍe†ŽÂŇó_ŁEY˝L żĂŘŔ—°‚mZ1 í!…ŮBú>kĽ, ˘°%)‘ĚBŰ’ţ_$Än=“ˇÂŠ wŢfŐëhŰŃ’gýô˙AÓĆň% ĄBŘR†×\…˘Cl`č×—a†ĺÍKßđWFď‹Đ°A~6ôčzúĽ;B})Ď…7KčţŤŻĆĺĎŽ2p„ó‘BÍ&-Tä"Ř&Fh4]‹Źľ}!¸÷•…•ŃĂŮ|řł¨×DhDĆą}>”Ťú1´dZ`’ě掎 Q #ňőMŕ‰di”AvżĂ”0ŘúpŰßz)Ý7DzF~*kłBn&ô.#âÎßY@aÝyý}Ż6ćĂŞ‡Ř‡^µ9”+łűď ¤r#öDpř÷Ěô᫣˛˛ú -‚Íí5Ś%Dh^kc;Áđ«ČoüÄpľ ?Rč®~č#7˙ďˇGÄ>YeÖJ¦] urëűPž•ŽÜ×Ě &Ś1Ą]B-ři8‚u÷9ßA·üĆw ŮwˇŞ˝ÇB-$ /˙ç/ŁÇ†=3€C3öTřĺPć"Bçô5'ˇVľ _˛ý¨cQl†:ĽW%ŢŠ2P€Ľjć©hŇę đ!*łřYÓ.;§eBo%mxËnôx[xňŇ⮟)á'ÍPqkľŹ–ŞÉ?WŞbrIOců"X®řÜźdž]PđéÇňÔL}&Ľ±Â˛ß@4Ýű­É'BBo'•?q;‰ŞuĂJJë?ľÍî¸v€†ö´üŃ*)vQ„v3îPvč@ŐŹ¸m EÖÝÔn5”Ç…»~ňD]ôTĚđŚsôňď#qěÇ‹čF‘a°7Ňłĺ 8K!ig'4 ô=šD’ĆĆ($ŕPYF,˙ÎŻĐgߎ۱I;ý¬Qø|>ě^1ł„™XžZ1BŮżéW`’)ÖO7¦§™ÓŘ\ŮŇCwÎî†3®ŮđŤŹKúző0ŕW[ŘŻÁoD¬ˇŘŻŢŠű"´˘?âI„ő7>Ă0ÖD)Aç·˘)źyýVĂĘůŁ0٦ď;— ľ©Eéúf«*Zˇ40ľo±čđÝžíW˙ž?6BIđžOÎ=ÄruŕĆO!„EÚů`c%´ľrŐ' 1ěşXjmËŠdfąöű(O*Šą@?]%…¶}b-Ł?‰P7R -{˝c ZöEÝ`ĺ^3CŤ’úÇŚ@gGĘŞ…Ż‹C­ZŢ>J\ťŽő” 6_C ʉ ČĄ…üĽy(6»äY†qĹßE(¸ íŕćFDA‚äÝOĹ«J¨¶\¸â †qéK#RÜ2á$&šź‹á·ďB,磇˘–ľÔ OÔ‡Ąč5˘áš=ˇ«wĚ"ZCEó†¸ýN<´€DVSaäęĺßGń±˙ŽHt=x –®“łĎDâQWË#ĐÓjhúůßD"3 ,łCË"żÂľoóń5 MľÂ»Yţ1ó–ţ0B‹ČJ7Ě`M˙ŐčłË"Ŕć˵0˛ČŞź!>Ó?xtĄ3töVęM4DďŠ8p.ţMýáŤëĺ‡űĂX6¬.ç'ŤrÄ`Hlm‡Ţ¦ÝőTŻw†GˇË€;Ű +ż˝˛ŚH(ŕp†TĘ ­±üdőíęç­E??ˇ0á(3´‡·óţÓ0vľ0â`M“}•š¨úúęš%G2CŮ\<ń(Ű\Yć¶'řq°îoŢz(áÚ/äAÉŐĎř,Š~GÄŽ –¸ˇüg~ŠżcÜ«VŘ"F—G_^ ŢKÁ™ËźjD3šĹö“f9üĽąěŤĎ@Ź€Mž ®Ź2űż±±ţóU=™©ľŰ‚›2ř94×.ÔŐ9ČzuSD’FwÔlÂ[BH˙#Ď;‚8RÔĺ Y„RŰ~|zD1ü‹‚P>đ—!ů5ŕYőLwî\äĐ'FĹ­XČZµfąŢiE˙W& #eĘ—®‡ [LÖB-ľesÄÖ0¦č×}ążěę\ö+†€Đąę‹·ť_őĺŻL˘ž?C"ýůgĐzÔ?ü”3ťˇ úÚ§Q3î÷/ČłYŁŇ…ˇí żŹÇ#ď‰Đ¸ĄŠ1Hčí­7Łg,€˝č4´Sa=›ľä øෂѧßh eđ(âQÚŔďú }Šč ŻG“{˙iÇd5DísW_‰Čä÷#"hěüÖ¬©‰r-° ÁgţzĽ*!'®ˇś0ůvZp+"üÎrwáqÔJ÷Ϥcä¬{é­wTš*•őŻIçÔŹîĄO:K홦öĽ]Lç:˘[ńzĆ$O+üŹÎł˙Ň'yÝó‹Ś_/:OüL‘żoÝB'ç“Ŕ[»‹đ;M·ďňÚ/ď“űĆv #Ď SnxĽ'ťSŻş—q{ĎŞI[–ÓYBë^RÄťžö-ĂDüEzOÓ˝ńPŻ=@ůë•"š‚¸şâ Ŧ×Ń^şĹérĎ4őC˘Ť#†ŔjGNwkßş/?ë1)âÄăÍ1€;Ă·^hęč—fŘ9~Ír÷ĚŚkIrˇ_dŠČ¨Ú·4˝AŤa^l'FÉňÍ\ĎnßçÁ5 ŹH:3˛Î'Ö|âŇTw¦ŤWL6µ¦¨…ú™˝ (GýŁ{áŮź¸Yč16N1źiT/\ Ç%—O\–Y<Łę}Ű3‚{ aC2™f”,ö¬Dv84ä{šžŔűę¸ĐżfąĹĹ“ÁLŰĽ"2ěş-Ź÷,·TdLXayGe…—MʤsZŕK†™°2¦-íPÓŠ/ofß‚"RŇ’I~Kµw¤—„sĄ’űwŠx ń–aô˛wćr•ĺ&µoćŇĘă˝_VVůĆ&đĆĹYüÝ'ŮRźĹČ4Ui…zíî9˝ŁRäD¬ö-ĂNËj{(Íô”,±šŤüěâżâUţłśľ×Pdě.Ń.9ź,©_ńňüˇ«•Żz•Rş]Ę™”¤hQľtgW2$‰3+}#éë T§™Um~JŠO×Ö®NIWĄlńZĹŁ>ţčSşDNTgJEŽ3Ň1ůřJ’cáE“űŇč¨¬ŠŻĽŁ'U‘]›µwý1ćIÝŻľ@h<`€zăKT6E7ő]Á ŞNšŮ<»ň„č0GÂ’"Gť| ¦¨JśÂg7Á†Ż<„Sô‚Şúd#Ő0›îKĆ[€$ś=Š hĄ*C‰Şjq¦O%gří]ZĘ–Őă‹Řf‰—é Ob¦ŢŁ2áXúŃ»Z1yD…Źa¸sŘf‹ˇ8ĂŹńŔ(TLűó{WKQFř¦& &Â7§NĆ?“¸Ŕ‰ęڍîL†BWWKŁ EoDqŐ®^iˇVŘK¤‘†PkÉ*žhyËŰUOÓ|Čŕgر´@áVĺŽó(Š çܧGĆőÍ@ŮŤB!©Ě›˝ČŁo'Í“YqKßĚFbŰ A ‰hĄz3k˙RŁTŃo6ĚÎgHŞD®ľCÜ-ŢL †ş4g _‡ánŕ=–RĽ“ĐÝM‚Ä7x®n3üŽišĚLĂWŻÎő\č Kô“řŐ'_‹Dg骫‹âpK|â>ÜĂpíňő,`IޞIô0pä¦öšËĹk·tők73Űâą$;.ÖEôÖjNđk†ipá–ĽŞ—54—EW7je" Î)^ݎzŞśâY˝Ó‰ÖXvÔE‘Ż9FłËwxPěq´JÎ;d€˝NŚBąđęxŠ)á‰BsÝăÇA‰ăçĽÜŐ™’I€Óůx Dćľ}–âňđO;Nď!†$şŹě¨ńrG÷ßî OäßiGµŁU‹n Qöć.EĘe«·˱r^·#jÚá<ĆĐŰ¨š­Ş‰ý®úq¦ť \M°ZĘ·VR¶Ş;FÉ $Q 8źÄŠwČ1ÜIn ŮwN¤ht†Dđw੾”ć2V€tE"ĽV ÜĂĚ2ŐJ*Şč5 bŃ /^ ČS|5Ó.v9ŰqçěUľíŽ&·Ő&mPťÄ‹$ÇŢ”>ÁĽŞg W‚¬7`Ž=]U$ŃŠ–UrĘł’#.ňÉíďväńó/@r¬V­˝Ľ3Ó/]&ů.yVuĹ­&ś¸DňÎŁSf}ţÂ/ű/eŁźÁ;A”2eQ?Ę”ĄřýˇdÁzš+Š•‹sřÇ,ĐRI®$(caQn#ĽžQ) ®JĄűî* W%›P8KŽ•zK D÷Áw:Dµnh˘ŹŹŞÂtÄőÝĘâÉu­7o†cČ&ŃĽHŇ żéNäy@á›ňuÁ”Ů'ĘH€…Ĺh\ëP¬38µ=ü®…GËw(ĐaĂ#%}¸ë¦@Z â»XÉ,ëÉ]óĐćhUą#Ü)5—ÝMÓfşîűĄÄŁżśv„ä^Ô ^®”čđŇÝÖÍŔI^ćXąĐ%»s,đŕâ–Ç IĐíBâWq“ĆŞ¦óžĆ@ąĽ·ą‚c˘§®NI¤ŕ 44ú٤bäăęP@’T55UTý‚ʱJ­e?ÎR¤BYňE~´öđaÚW’ç1Zkv·=ËB®†ěşŹĆIÜÚuŹ0íf2č–¤ëÚi»•‹äXEąÂŻČTř„ëęLďu–VÓí7ťN+ŕ Ęť †ăn©)ŮŐ7/ę x¬š0¨D¸Ł6ř´r˛›W°Áˇ8€•Ű·TI”7?<|Çz'ŠŃŞşÎĄ´Źę*Q˘-Ň}ăĘâBw9%bĨŽ^ ­%ĹÍ t°RBęlłt¶Y:Ű,ťm–Î6‹ßŮfqĹu¶Y:Ű,ťm–Î6Kg›ĄłÍŇŮfélłt¶Y:Ű,ťm–Î6Kg›ĹčlłťmŁłÍŇŮfélł°Öw¶YĽ¶Y°Ű_ô×yvžťgçŮyvžťgçŮy&şŚŘ đ;ńČnÄ.4ś8püËqü!nutŇśex<Ĺ=,ž{nżÁKĹ ě«çéŤţ+čŮCźŰÉoü<řEpţkćŤÄÎ{Ü‘jÚhˇ9i0?ń‰Ď+ÎéSő‰,|!µń8IąqžüöĽ+d#­{ŚĆ›/®ź81ÔşPŻfĽĺün‹Ĺo©zkř‹tkFÔŰ7zI-”;JŚťŚŽđ·Ď"}ľÇuٍ7şŞ(˙Ĺ)„©¦/vůíă\Ŕ ‹ß'Łţę_XÚx2ńv&x9g›>ţ·üť+:;‹ŮÎ(í~’žŁnčĚQOŚs3,~źŚú«aiăÉÄŰ™ŕĺlüťmúřßňw®čěL`,f;Ł´űIxŽÚ7Oď4Ükvçď,­Ů÷Ăą± pŃ ťĐ ťĐ ť€žŁn »~ëüuţ:ťżÎ_çďţá9ę&ş‡˙#n{-ź8q_˝ŮS5§ÍŠY«O”ą-ú-fĄjÖö×m«(î Óší&3µ˛¸&Ö®7$«Đl˝Ń*Wo>ď''ĽTq¦e[®ňÁ ďăéĂÖéŞNŢ}ád·ÝÎÜjo0?kVĘ%|hW:gď€z°á9Ľa¨j2“íŢJ5ďşx4_ś(Łšđb˛¸JąĆNLxś{řpźëN•ŠÓĺćI»čôž#·îw#ůOí™LÍ}pî“ Ň­Ŕ¨'č )éţׂcX[Żó6ó]%ö Ţź®=2Ý“ŻŐo´j(ĄČ/F(UęSśt{¦›ĺF˝Ülň›;±­uŁbG7R¨Á}w­ú­{X˙‘& l&‹KŐ«˛Ř|~ĘĆł~çÓ“ \7ŢšBaŞRź0+…‚0ôž(#ĘfDîyćALÜ} u v!ÁO^1âfh.}ő=¦ŢÂÝφ–tš˛—bćô<¨™FťpJôÂaU «j1mŮŕ¦bźĂ){z®ÁĎúŞ7XzúNť„#J{~"¶—AU<)7‡!h×ůĺ‹1v2=m™­ŞÉo“.ľaćÚN{šđÂAÝ"˝żz°Ć÷ěpő5‚Xn˛r\§E±ă†fËľ łlF®7šUa«Ż;r>HéŔáťőŹr–Ŕéaĺ>Ĺ‘jąT4‹Ó–{°¤&NĺgŠüÂBÜëę‰ÜÔI8úýyfyłôđ­˘?d-5ËS5ŰäĽ[ăřĄgaQľÔŰă,cżmÍjŔÉ)«ÎiŁÉżőt*×*Č·ş“<Ś‚ŔYĄLĄn–ʵ)N¨ĺ&¨vú„DggŔÎőßÖTvÝĺ=Ü0Ëö©2š‚D`ŕhô>’€Ý×Đ“ěpö‰©ó[Ü—+łĚ8ˇ©’ŠzüÁ÷ďI{—ó ÷‘jŻŁt#yDéĹ…YÓnj3U<“ ;‹¦‘rťŃŽÖ˝L/‘ͤ+JŮYW…Î(ŹVoűQÎËÔ$Rtüş€iSąťzTůž\ôs ŕçżČ˙lŤŹK'Ż“č)‰č5Ałs‚ÇÝz4¸pűR_uś±ě¶E‘ĚéWsnÍu(lŔ‘ČňH*F‡¸ß··ŐĚ“3zV˘ĐËkTOw¬ő’Ô×çt&üęlÎÖşsŇ8 R®—Ó{ p%@n\r„Î Á¬F3ęD>˘ÎěČmr‡}Ż.OŮS`˘rűW†5-0cĆŃ\ĆÚŁ=–BŇ„p%˘Śp;”ăß…/0ö9ŔĘĽ%ŃÔ‚T§UH„SšţR7]+ Öߍfnů¶Î…@?ˇ 5ű—âÓ„DĽ){¦VĺgT÷ĐáS˛U?®‹kdĂ+Ľ¨„-ÖĄYu&€Wđ©—‚+î™2Ĺj©‰ŤĄ'K`MšF\u¬X"Ƈě=Ľ˘u ÷[l”čEő˛ó_‡Äę3řżÎSżS/UDKŮxY:€x»=|°ŮKľŔ Ŕ˝rÚS—ýŤfµl#B(8gS?ö=í7BűQwËF- Ú`i®Ć/5ď­kVUľŰë Ł|…łĎQ?—:4*LÔÝ€ş»ś2p[6űĐüĺpmŚ—řÝk[¨}EmU Ç×ĂJŁ~ uÄ4 W7=Dj´N›âö¶†4WRiM"ő“Ľ lÄ'W»^5ŮlęĺĽĹÓłÂ`1¶ň K– ]ö¤ÜN6śĂůĎq»ŢČ:śĚÉÓčKˇý™Ddü z8 ě&äÄ—›ţLiÎJ5g˙›á٢ÚW+qN` ­L˛Ňó_jÚlm˛$˝ű‘lľ^;VĂ‹3ŢźT÷Ö÷Ô7 "ŁÇiµä¶ˇKÜ)ÜdpŇt `ÔË„L™`ŐiĹŰÁD/ýň¤¤ UĽ._nt*Ś,r$kÖéł|qéštLěφ—XRČ·°×''›_ŁůzđtźŮÎ6”Ą˝Bˇŕ*iÇůC˘ŢKWŇŞNp))ËuălÚT—FR;t7ŕj]Úzx°čÉŁw—ŁKĺˇŐÝăăS¨8Ätdź¸˝Şbµŕ§:W’xΞŕÍą{q±ă¨¬h”&Ś^:đ^(Ű­é’É8—ăłtÍ@nŚ>iYăéěÉËq˘Űc˛ VˇÝŽPRâ(^śXíKbč{¸`HĄŞÎ÷’ÖťkŇ3]«+Ę1ťW ťS=_Ç ŮŇd^öyçáL4Můź˘°Iç8_-q1xŔČ˝]ľ*„"É?Y.Ұb5n-čLÇŞ9Č{yl_Xç»OběcĹŰ•P8ą9™¦ĺ‘ëă;Ć弣TCŇĺU"ËÝÖ0ÚŇ{vűůë…jNiÂĚ “O5ŕbYď6^H=oŕŹŰ={ 6ÉôS§ub#1ŰŞcąőŕËP˛¦Ý´Ć ©î˘(UÁ˝[¨ěY¦rSÝgđtl§ú.íůkż'K`żžkÝ2ĘÖyŹŰIz ŤŇ±=Gx?HŰ˝oeH;U.ˇ5ˇÄ3Ň'Ą“ßMé†ÄşGó…Âřö[Éěr#˘PČł¶´¸ěďáĺ5‹ş@ <±ĘzřhÓÜ‚ sźŐíľjíů†Ňńăî ‹řŚ]?-”ąŢN:»ó|ĺÄJŻ–‹U‹oűą“KU§l Ţ®úĎ0Q„˝O™3ͦؓŃXfđF4ĺů®/OVýXŽć’ů ęS“3¨w¦ž˝ĺÉ@bµńi®şč…ëW­đŠő]"0µ»]‡w;š‚–)–|^žimäaíň‘ŞsŞŻ 9ÇÓrF9=Ý—yąôp† Ýë)?ČŮ‘Î;'¸I^ă;=M•lŘůx[Îrĺ6«EŻ{Ë“ŠeŹźďâ!„O4plT缴?™ÂdtJpY¸ ‘t¦~iž.±×GłĆE˘îĽ:ĐREDěĽkѲQŮl¶QĎË-3Nš36Żf˛ äs˝§ËÄş‡ZDzۀ÷1<ÜŇńĽńcČ;„±C™GďŔ2stş\CÓ*C‡r6É•¤3€**¦é¦çsňLîľž#‰83×®¸®HX¨˘ߪL›–d¸’h)]’6źt·i‘•É%/†­sĐLţÖýĹŠ<ť|ö„±V'19są^ZJyÝx‘’Ąç´GłWmrźţ:ĎŐ˝¤ ŇĽćy—Ý*ĺ»ţp™*6ŔĤq©ëľ>Šu@îcÎ4žµľt)ÉË,2é(€YQLżË#Ĺrßho }y(ŻÍĽďD3zÜšQZ ŤeJ„4úĆŃôWíąußřá={÷ I%ŤŘEĹ2ąY Î©k–Xü޵’)‰3©NI©ŢOş&ËłVŤ/aRdłŇN*Ş ,ď"FÄHXŔűŢyE,đôÓšF­š69Iúş2Ď–,LuŽ\Íő6)bɨ^s]ťžĄ|¦Őd¨‘¬IéťzŐ^¦ÔZăŚ}g5Ćë˝oyęń5˝QŻńÖ¨7{Ť cˇ‘}čŘÁ…ş]@,v‚•Ně$K‰d )• <śt ؔܗ:|ß®óń$v”™@‘l5ţ[GdĺÔ[v; j¶PăKŽ´ł˙lráě˛yŮâó¤˛t»ăͰm7Ö‡ş !|ś÷ÖˇT߬1ůÓ8?öľq#uŽÉt ęY!äoH5¤E«-7:=%á$[R6lŐ»ßÔűŐ4^€=nůńľW$«ÚeUëꤳńΊt_mäş®ĆëŁă.Ţ${×őĽ@&Ý4'­ß7î%Űđ˛€äáAŘë­ńqg»ă6»Ě $OepožlDP7y_Jf!|ßDÚ´Ą%nżÖ8)}RZÜv5‹S'%˝ĄzWXšî°ľőĽĂ"^á„Ř‹7 ‘říŘ˝1Ţěw;›—ëeííZÉXËy\s ˝ä©ë(ß©Ő]ŇÓŻµlëGó¨…¦ß9rô€sH¨TM‘ĂXëŃH(8LKڶtC(3¸\°śÁ¦"Şřúü×ßÇĄąĽAs;›ć6‚ ^ť˘ŢC_ľ·ŻŰˇČ`é˘XÚ K–6ŢWPi/řŇúUďs¬ű˝sň¤ ¸¶r ßuYľ ËŃUQŤăzáŤS4.čFǬ3‹ç›ÂŠÚS©× uTŇ{±š+’§ňă7‹Žsć@˛=h‘Xť°ěPĄŘ0śĺęČ$śFµ7ę.OJĎ: â¤ĘvVY‘î8^7çÄÜÎôxL[)-ĽÓµ<ÜyŤ›\˝ÜŁQ-É7Źĺkt‚®˘Á—ďđT ę©S'ĄQKVë¬woô‹0@P׺äďÓ ŐÁŞ…čAł-Ći…ßŘ6@ …oÝż/ 9†ČJ\µ–ó¸ i€ ‹Ş%Ţa´cU”}0 vU‰Ć»útV·–z_v™=®úe×^á4Č´+Xhć–IgN`ÔIj$,w‰H ĹCíĺÝMőć©ýĆ&QÜÁE«çőKYžŔč›Ŕ1y0EF 2ŕŇÝtęľI`P—I3ŕw‹6d­‹ë íŤöą=·ż8Ł3D—uЬ¬Ű@E…c7Ť%m¸±$fE’é<®ňŇŢß“ĺޤ !?ľgś#_sĂošjqŐkÖ)S2­ĺš÷BDw•ťëşÔÉ“€0‡Ç-˛`ęÖdsš«—R„‹ ya-¤â)+_Ě%I(H:˙Â÷Á˛8Đ{Ę.·”]}ý}—$(ä ż.s˝Śż Űiă')ťFŐkE{'ŠŹ{ł|o"]ľÓŃçN‰!f­÷VYukĄ7Źś”Ł-Ú‹L<ďÚöąJ/%íWűÝłŮÍÖ'“üŮ|b?©č­“ăă“\fJÉj7S‹aÚT˙6Óô¸+)o6Ç+–.÷a/Ĺ6”ŇhÂĂÇűţO4Í!NsJh×p3byLÎG1* «@é.=ŔsŇ (ź u Ś^¬˘*ŰuÍyJeÁăîWD7ĸoÂs šó`'e=Tżö"ă>Éx‘‡Ďu–IG g˝]«T˵ ąĘ9´ ř’űîčq´1mň~ń¸?«O2µg5hM$YÚ˛6Ëux?çŃSela‰ă€2ĺŰŚ2ł˛ńzň$Đl™ÍŰjÖxąd•ö˨«Ó•Úő·ŕřܬśĹ|nö˝‚GwYź×ýni[Ň ęÁGG=cbVŘ?§˛žĎXaÄ:KwąZ/ÝV€:5jĹ"kz@űůčsßÚŘ}Ăţ1…{]ÜŐ]V•yÝÂz}ěuńdďÄ©& B±ŹcčîśLź”úCđě›4c#†+ĺŞ Ł:6çrvHÖý,ą$«řüî#’%ž¤ Ŕµ—š§–„G3¨LÔůją–ť}ô,…$ $B!ŕymrŕęj€,xlĽg Ź–{ÝwÝe*»çŇ””vŞ/Ř©öŠ3 ă2rľł\9Á•Đd§ä`ů„0‘®+ F2»'ë^†p–&ĂěçXÍ!f_'ÍŽłŹÔYcfMŤŹđ#~śŻŕ»ŽłHč€!Ěo—˝ć"Ŕ<đSâŇ‹¦g4QЎĽJŰ~ŇKźdťş°H—îQ©ś?pYł„‹l@]îCĐšcŃě`5ÇX”IňţY|ŃÚęj#íř)ݤýŢÜ'űÜ1IÇ(Ť‘;°D=“ßĘé¨HŻúEŽ>Ö=‹ącTgę{­â9.Ŕö‹ô"븹\ŇÉH/ňRS~sYťá»2;úżjD M”Ľ­Ą$0DŢhŕ<'ä‹ŰöŮŁŘŞ)Ż`­.Ëbň›[Ťröbä-tő Ά }Ó)éuq)"Xh߯çěŐe$¤µĐFĘö>ň›˛xu»ý ărÜáŠČ0«;–ÁĺËá2sŹ!Ď҉Iş8ĹV^yM=Bä7°Ç™tö…_dçA }óĐĚzDëÎjĎ„Jţ ’ÎFc…î]žGéÎŻřÄI†¶ş8—1čÂ"d]˝;BŐ j·NÜf€îĹÎUńŞâ˙ę:EîŠPŽťľÂ¤Ę«Ç8­ŢĹËĐÚk% ­ŕĎäwü¶Ź«ËčŰ˙mż§đSVËĘoЇ©˙ď_U'~ę{Ž‘ÎKçĺń‹rňNu±Ź>‡ůí6 uÇČľ»NrÓtŐPŔ»˛Uř O?+Ż.ĎORDܶřńFŐé€+Bőˇľ»Ž kÜÂj˘ÜF›j„d!ěý˘îëü"Ä›-aI¶¸ţ·ĽĆ=<”Äř‘µĚŇ›äŃ'ä ÔLĂßňF°ß›j@­4“˝:Éoęćšú®7(ŃÇÂý©łń[»}z6"Ă[˙WŤ Ľ&J±‘ŢT;?ą‡ŔŮyEŁ!‘‘đ’Q¬ŻEJ·[7.o#ű‘_rŕU¶ŻäŠ˘•|Šc_嫊GőTŹRůŞWi0EńË,kv¤Zą±ĄśĘŃy\ôAnú˝Á…’‚)ÉřŇ7+č˝´|(xe”‹Cc ĐĎiŮ .F襗U ŠË!yť¤x.t ŚV9gHB =W% oͰŻ÷n–~ěÚô¨ô ŕ.0żç` xőí˘€!ŔĽ1(*›’ ĺŐ€#MQžMŞXZ6ČyBô`[ąAçGZ)i“<-›á‡©2ě%w)iZ»g˙.öć ýÂ<4ëńć2š‘á-¤ËĽ4´@ĄküV1 y–T٦úűjńÖĄ Ą5ĐHé(ËÍ‚5|Zß÷ pŻ“Ş~S.H˧WҲgco.°PÝ č'ń«Oç<@ňmŕ:Ŕ¬¸Ä„ÇÜ~HQ?-Mç°Q{ŕBńjP˝·řů»ô´J©W[éězŇÓúFŇ^Ł«÷Ŕb•‹^<. Đ]ˇqĎĄ»ěJ{îŐĂk—Ëc°ŢÓ‘ĎůXźd.î[ăÔ˘t~Š\wAŞ\žG˝ď¤Őú¨ŇąuyÖ8Óuß~áö¤©wĚŕuź†ÇatÝ­°ž3˝˝@ąŻźvyvÓ_9¨ő{®˝ôÚ}yŤßR~ü\¨hŽŻjĎÂzú›óvXŕqń–‡# Í­Zîűˇ5Î-´ľĐ<Żđ˝tŘ÷U˝3HgÁúËj˝ z»Oô»™Tw·JŔŤ·ާµčśżx^Ź­sĹĺíĆŰË{¸ÖmĄźgm?Çî=nHňô„˘ą2Ňu «Î±‡ćjť3FíEŃę剺‹ŠÝ7­¸îČÖއçľţ7ŕT?Żä^÷Řzą_×»Íńr2ćăĆçú9÷bz7]~—p{¸gňňçwSś§7\­żjo/•şkR=oÜđtőĺy!Íé&ŃÓ=±÷ő3^—őy^âŕq;ąűO‡ž—oyx˝ŕŃʬĆg‡ÇĹ9·›†q€|k(źÝˇîÁŃÝöĺá‚T˝{Jq.®qÖIľű‚’Ç4ť+ő~[oGKľuޞ\W0ę.›ňđ¨ąČPąYő­zo’ËŻź{ĺ«uFčuť€Ëů›ÎMFá"ĘŐ†ZŹç$RŮüŃÜęŁńɦ÷¨węö&¦˝pCĄćtOÖî;9µîô4ľű{ą M1żinĐ8 Ő»đ÷rÉéë7đkU™„[$enőp—ÄĽ×Ĺ0!`3Äĺá^{+zĹ$ia4ăŮÍĎ.UîÚ÷]^GűŢ)쾉\ďÉLç&źÖKŃ,kĎË 4w:j¬ľtw‘gŘV Źz§‰S¶ôdĎ[đŇjEBöĽÎZ}’äZ|;°SÖ:Çv·rG†ĘŻ˝ČĂëˇÇĄKŢ—:{^(®€ÂăF:ßkŢt÷đi/Y&"u,cD$«ô†p4«™ÚÄÍ`vĐ\§ŃËŽ>Bu5ŹÚ/§t71űÜëyGŤ§KB­Ď{—s`šáľĽÄĎď_łĄ!’E7ŃŇÝ3ą8f[š+”Ń’ËăZ2Íĺ[#,ĘÍŐ«‘tÎá»q?Č×dC^¬Ý`ě×î,jškŻTŐ»:tß㢻wZńŞ»Ž˛ŹĆIRéŤTgxv<ÔĄŃܤw‚Ěb• +Ź»XĽ®YŞ\x¨ VŻëÝ>ŘÉÝĂ`ĂS˝ZľoĆă*ńA)ě+)7“w°˙){}&6Š?Xą}K•DŮüĆו¬ďĄă~l572hn•—Ük+öŢž·űé Ű ˙TďÝîaçZE”ß-!CźŽˇOÇЧcčÓ1ôqÚÖ1ôéút }ś.ěút }:†>ÚÄŽˇOÇĐÇčút }:†><±cčÓ1ô!Ü­cčÓ1ôéú(őţí˝ xÇu Üs 7@$EI¤†¤ŔKä@f8`¸Ö Qěî:^˝zőęŐ«ëUkŁŹÔÚčÓÚčÓÚčÓÚč#ŁŢÚčÓÚčc´6ú´6ú´6ú`ŻÖFźÖFźÖF[r·6ú4´Ń‡¤]"żÖłől=[ĎÖłől=[ĎÖłől=[ĎÖ“?ăQ#ň<ýî!.j‘_%Ď6ć˙Aę?ŔüŤź×o‡±q—áńlźłŞł±Á`i ĽřÝ^'äią–ką–ką–»4íŁîˇ}TżAű(XGlllll4Z‡˙ÖaÁÖaÁÖaÁÖaÁÖaÁÖaÁÖaÁÖaÁÖaAPë° lldŇ­uX°uX°uXPÁ»uXPjlll”Qol4Z‡[‡[‡±Wë°`ë°`ë° -ą[‡;,H7ţˇ›acF|žmŠŤßK7ýÔ~7>&Ţăcâ=˛Ĺé€w{Łě*â®3ěMµ‘vĘęÄ]n°ŤFT7K\ ÂNö¦[ă8ř­&Î$nq[ ¶÷fĘ N˲žö˛†˝ˇÖXp6ÓbCüÇ ĽÂűŕŮOÜU”á!~/ä·’¸{>Ĺ˙VHżŇ]Fܤ]KÜF(ýľ`­ĽořqłĘAqľź¸+‰; ńŻXŕą`%!M{5řAŘ&â€đř=LÜVȇ—‡â’F¸P<·A¬DôÝtą†¸=Äí¸;‰;x¦—k!żaDg oä»ň„÷q{‰{ň |ńřŃř×#şßDÜ' ż(7ĄĎ-÷­đ}ŕp3‚ÁóĽâŃĽ‹ÄŤ÷«(ď<řÝqh>‰hDóŢů„ç!Č÷NČ÷ä{Ę÷.(ĹéÔóÝÄ}č~/Š·ň9 đßĎqCćÍc÷jĹ ˇ'­ż Č—¶ź _JĎÄýňşň¸`ź„2<€Ę} âśçC—¶ĎIp”^˙¨Đ+ ń3đĚÂÓ‚ňLĂ÷ŚRľ)É„śÁÚ;•ä×¶dM÷?b~8ÜÄዣjüżK ŹĘásjxLżZ Źűâc<ĄĆo“ă÷*řSľmŮkřÚ'†oĘđ_ÔᣦóŁw"€~írř[Őđ_úÄoWăwJńăoŇŃ÷14~—?rB)oG˝ôë–ń}IĹŻGŻ’ź-["ĐÇî)N=beŞÉ-C•-ÉB±šś.Ö ŮäÂl._©&a˘,i+Y¤¶ěxúârđ/ČŐçßťcuĹźäŢp~^Ĺî5ü«ąO?ن÷Káń ›Ńx+P<ú˝R†ű-ĄĽż¨|?¤«˛‘aČŐĐ7c¬r.s¨V°—+H1`ÔDZrü‡ýâ¤nöăH w•á_%«ĺđď«ák¤đřq^nRʤKdňĹJ­ly x™ŚÂT¸,â'ęm”kHqąá/„®0|«ô>5ţ•rüý:•d©Éɉ=÷ZŐŮb¶rśŁ&'S!Ęé'„×Ő‰˙z9ţűYxü¤*-",ݸ0˝JJ=–U“>ř-Őň‡Ás/Ť'T:n”ă/Şá›üËwźŇô×+íáqN÷«e8WâtQŔ‹ţ~Ş-żţ; =† ˙vµŮđ—ú[äp—ň´Őđn—*—~Űŕo—ĂźŞĎkäř§”úĂĘ…Q§ňŕ×~wľí÷~5ţN9ţ÷Ôđ”á'wőtUńĄp†%8ńĽTó˝VÎ÷PPü]rüµjřn9˙SíE˘—WůüĘ»GÎď´.?7?ÄĎ`~üˇ—;$Ľn°Á}¶ŮţLąŹ€Veś†Çá…'Čćy8Ĺ™Ş=—*©gňÁđL7fÇ?/â‰Ó]l"§ßň¶ß:W*[• Q*‡ YëśS¦„S¸ťˇđ`ĺăń›…Ď—O"­8ë€n›śž]ö7„ _ÇJ×,Ľ9śv€ăó«ł^ľĐł(Ţđl‡g‚Ĺ{‰‡w#:t+tÜt\ôX´Ât5Nű~/ÇăŰŕ §¶ęibő„`‹–#_§űĽCčő6_{ŘiČÁ iąúXĽ ţÍŕ˛Áý^i¸«91Ç43MP4W„+BXđďŠ&XĹJ3 ¤YöÂsž,ÉqŽŇ]ŮŨFY ĎU Ë)žô˛:KYKQV´ě×!_úĽRS$/m;˝MwŤŤ~Ľň‰Ŕč„–o#˘—!řŽŇĽi¨(8 ů?‚ę„÷ś› Q÷ĐŚxÝtťńůś˙EÁˇß‰ăm(Î/t´4.ĆŕŰ/^rŠľ¬´Áp×MsG\śN1™NuŃĂᲠQšF`¤rQn€çfxn…çďio;ű>ĹżŻŃÔ‘F¦Ťář±«îXŽ|ĂŽ0yľ/”™–eó7o Ľ·Ás…ŹÓq§ŃćÍúÖ†¨7‡/SĆ˙ š7R|w0ĽńďkC•—Ť”yüf·Ź~CîsůR4Öč)·6C,˙ňü€ß.ö˝t GěUNÖođřMÔmîÇýQ˙yą2cÎçWoţNý łďÓü{OťtŮÓDşÔ#—/nľB.73ßĚĚ„(÷}Ë‘?Ŕ‰půÂuź88Ě{mŕřw\ąvpČuy8ŢŇq}ičĹÝšÜ*Ĺ­WÜ•Č%Ü&ÇalFn ¸­ŕ6+n»Ź»Üp;‘öp<|¸=Čí·ąëŔńďŔÝh°--ÜÝ\‡»ąëÁÝnrW~Š{Ć©ńÂ:Ţ;s„Ť{ÄFďwż¶Ů¦ u]ȡ·W¬ę?Űl›şŹɆ`cž®ĂR:ĎDZ6ÄâجËYôđňčL«ćXÜ>íÜ0 C dę  ZĆŹÉ€źźglźŕńj2‹|!ľ:…1>Oź6Ű6gwt"űBŢ`:Ż‘Ď^Ů’žŻo§0ˇçéÓÎ-ćy|Ç25ç(¦mO÷a2yců”{›mÓN÷a2kwÚŻvn ®Iß °Yęł Ů«óö2™µ:ł]Çë›Bt MíĎŐ÷Ń) Ńyú$Ŕťţ3f9Śk2łsÚŻNanŮ}LÉö€úeŰ»ŔŻnlÎÇĎdćŕ´_ ĹđĹúěpě»q©'™nóó4%[ ňWě¶ńZ¶×ęđép,°yy´s#l<‚chÍÓñ—Ö¸G›m[ŤW4¶›ćă—ciúO“™=«ű+–O;:…mé,đĂ”Žž6úŐ§X2ó÷îĆ6Ě|üLfÓŚŁmŰ2ă˘Ů»PŻnlŤ,ŘŹZđńëpL‰]XóôpLŤńF)™ă­HXóôI€1ô‰ěrův8ÁĽ<`ë+ě§ÝÁé?űŁ_Ľŕ’ť/đěWM{IţČšď+©Ť­&ĽÇŽ–ď’°GuűF{ʉ3řčŐ”ŽáË_ ……~Ţ?Űăęwn#­ŹÖÇř#DSa„Á#.góŢ)lyúĚ*|Eĺyµsë>!ż`É'ě§mČG˙ŮáXČů×ő•­y'Ś›Űńňhç†v<ľ;«;ŕŃ…Ěęx{u¨ć›]m¶­śŔŹvnAľ»5†>c•ŞS%`ťăŤňVŰ*ş$§ÉHłdňW61ň#ެ‘ŕw“Y• ńŐÎ ÍđoĹ0šÉŚhżÚąÍŹď^Ů:ŚŻoślYĆ÷ÉË2z&Ŕ`K¨Ď.dŻĹŰËd6Y´_íÜ^‹¶†bBŐVf4$6ŠŠ Nóv"¤Ó=7.›’‰ Ł5Qç-&Lňtş¦á †"k%ž<ĆVSĺ=ĐS'xäçĽrĂ!ň%GĘĚŽlôÜE-SZP2 $nľ†(ŽV$” %…R’Ť:ߨ¨öň B‚˘¦ä߆Ť’ˇzNČwńᢺjD©eŐł<PĆIrdQÁR1aŞ [©r!/퉣űzĽ‹Ąo"ş6Ľ^~Phßł1|úVQ@“ ŢČšŇm j@T“•g‘KȦâPś5‡´\VÄnřŇ-DSş&!_ĄŮK¦xŃzt6&ý«Ř[ňt¨÷´Ô+Ôa-×úGv©ĐU-5eˇ¦îĽ»bĄ-ČëĂB·đŔŐ,0ő«™ĺäD™$Y«g~Iě{Ë82š®osÁ"Unça¤„gĎ‚xXa!ł]1íč-ŁëáŘŕvWg|o´”ůrßĐ8ž,÷Ť©^^_ ÔLJŢ݊е{tWJhűhĽG&ceÁŃĺ¶),78w‡j÷B^ÓĚŞ:Ą±HG—A(ͱ´·ôRÇ•"°˘Î ą$OLɰ*ŞU ůTóPc%¦ęŃ}#ľ4Ôö+ĽnYPeA@_)XMÚ ă-…B‘,CQżĐéş ˇOfëvĺŢyźRJYÁ@őŘ8Ú°ůţ82±ÜˇŢ`ŕ§* iWn*xF–®ögJ7Äđ%ş[şÜ÷„n¶z…Îł±Ş<×t#×Í1hÝDëŐť®ŰT±rZ¤CµżŢĺ¶r݆müăńz «548«á™Lęj$üŞ^'ŮÜOȶöë´â&,µ;_4bqŐEČ>Ôh.lÍ.Ő•«¦žxŕšD°±ĐóčëL©ąéćˇEŹ·”Ń´ o%]–ĄˇâzŞĆoă1P‘{IUlŞß¸®š7.E•(ŤˇĐŚ”ŽłÜ"X#§őuGFŇŐé7ĹzB6}žŤť{KFçE=‰·Ů<9ĐęşpŞă”b=qJ2ë?…”őSęE/ć)l˝çÔ)ÍíptĎ˝zĺśí‡&WíoˇYŘź‚ţÎľ{÷®ő(L¶Â/”ۢD€Xru_´>Ş^´ŢcoĺW µ3Oq ÚĎŻÚˇÇAĘ-©°Ç_5}Ď˝Ĺt{Ź˝ăßuë˝í)b­’6ř§ä)úA9PR(•0©ü—IgÜ5=(‡KúhPo5uhî ÁaŇ˝*"/ô:G¤Ę„ŻTĐ•â4‹qDÔ!÷ńă2¤űÔ«Fh7‚ďĽv<đĄmĚS\€ÂżQś.đCťźSËk KH“Uҡő^Q9Pąîcź»yěS›G/;¬ VřŞZąăŤ÷] ÷A÷pȧ!PňJ¸°JŚP+R QÚT??-ˇ^tâř+÷cdjşËíłŞLgžâ6vĆBe;«őkźĄĐ{*±Sęµ.ŕ«\ëÂĎT¨7@;ţh:Äń­ŃńšÓř!n€Ăj áŢ$ŕ#MZ “.jˇ t);ş.–ł)¤B’¬PĎlŐPeóD÷Ĺ01mĆľEéWŠ#ęŐA(DĐxŕöŔ˝P¤‚zŹo';đn˛ć>čkqX5ů~ä‹—”pl$“‘ŻhrČSZsZ‰äĺ§N6a/.;őˇr8řĘw‘§4íŇ žčÖFđŃŤţń µË•Â9ĎΕŕţłĽ¤.o$K©ë[+y€ű>i'Dćpî­A„z#Îá^‚s¸ s/¬Â®pΩ¨˘R:šâ¨H!FU Ż˘ŰÁyőň=qfĹ'D5BÔE·n瀋 Đá§c“>~FÖŐzś/řn6á)šŠsşE°"ŔA+±ź4č!’`ě±ĎĘ(g>ńů•µĄ0ĄŕĐŚĘÜ[ą›ťť”ŃÜyÇž^‚Tŕy¤S•űnűhŤŇö™źrĚ•yŠcCLí’4›NđC"|„´ăŇ–đD×-*çpT«ÁhE źËAŇ[öG2śťŮQuű쎛ôč4ŽŇűHAJă ”5ňM|’GÂÄÝkřPę‰U|ÍŁs‚GíD€+Z)<ŐkďDĂ+śł?ę°F(ĽîR% tHHK”nażĘT„óCŞČ“Bš~Ă ‘Uî- î&R .ä5Ő>8OäF.¨–W`ą7Złí3GnĚ[†pĄr$)ĄY—˝\:ꤋ±N=¬ä ť\ŇEę¦G‘\¨3?ĄíµŰŢhÂĆţ=1űÄ‚…Ą@ë‚GKX„ŃăNęÂfd13µ{ѸBÔ™&îŤç:l?Ľ"c{Hý]żíĄ»śúË{8l/!EěOuq‹]»ČFşčîz×Č·G7FîOuŐ™• -=wÄ: EŠ$d1ŃźRGĚ<]—@—Ô{m/E!bĹQ"đU¶Öđćč,żöpÜĄőŠhh˘ą‹ű fŕ^î*t˛˝ ă&T h Ç˝P˙ćDĂu ^x “Ç*Ë7os_©’Wqť‚¶VVȨJĎĐĎsQűVÇ_ŮÂĹD›h|p#7^ áqÄîqÇOigY$ÍÂđ(¨Zűą$V§Ô¨;ÁÍňŹşúľJőÇkđ ¸Í\YŹďćľhUđRf–ÁSÚČüf0cQIÁĹč:Ä"ă#GĚ -eőqy2’äřICK¨1$ÔŘ·ĽşßĹ}E«éć^řp7óSE"DťÓPŤh™‡vPČ˝  YIŤŻ—űIMo€ůęTŻ,R;¸g^«ŢR Ń\űVą3®”S*đеër–‡’?Ş˛A9HZěTňő˘R+Đ$’ŻVĂ”®Íuí<Šşş Ť§€i«9ˇŇˇ7Şká+·´ á= š]_Ýü!ňŁG AuÝÍżńŰOYŇłýÄ›8O¨jČ(DézىC%~ŰŁe4HᇠŐń†ăŹř­Ďń”ö@ôÁ‘Cµ‹çŢŇž'˛Ľ7˘&ŞeŢęs†PĹ\ !<%©·Jř»El·J‚đCcá©"Xĺ7BŁyM×ćyÄ˝đ”ü죏xşÚńł1ΉHU§GÇ ‹(Ţx€ęL.©c) Ü'oźŤT'™§PŞŔź˘DcpŮaOI)í?I+íOµ‡çÇC]2ĽăB¬Ř Ĺ+Ô_eÁŠźUŐvÇ_ŽżZ>5Ş6V%TLĄÓ# RéŰm´ŕiŁńľýí|öŮź®Ń/yŁu%ŰNůFëźŇ‘ŃÚbłJ‘Ë·Z ”·ß(IĺÍ8ş@!/á8Ş:ęĺŢH|q/Q–tRUÝ˙”>śXUĺ'ř⓱ě\«đF’7úPkŁä×z¶ž­gëŮz¶ž­gëŮz¶ž­gëŮzň§z9 ˝ Ŕ #°Ë ŘÝĹô‚–~C\v@-ZUé ß”t2ş7}rÉ7š ›NŢŚýIĽ‡•ďôŔVnĎ|AŽgÄqĽ&Ý4AăĆ1âŻ.…/{üç ěŘ97µÁ C<-žłcŤ©ĐŰé•Ďt*ĆpßłtעŕiąÄ,Ü}?Žs/N„óűrî[î°ó­“"†HM°µůĘą]©ÍĽ-<ź±R]âT’Üż0|áv#(;Ă ń›·kÖJgąˇi#NHt`ÉçEd˛¬÷ą ?fżG&XXä8</iŔ_–:PĚçÓĺ1{şĐ*ĚçĘŵą”Wě3Ż‘ÇŻůçĺĘoMu±dŻAĚ[eiëWPvkţüďÉc˛Îěş(?Φ+łŐôT`«?ý.j  Î,VŐJ3eşN§LÇdvه˙Ŕ0úţ,83W†lE$<ĺVýýŻFâău0ĹŠ«:ž)’2ÍÓ}ăŐjp&˝»ľDĚ·ëɤT.Εęâ?˝…Äůať´šŇ«śOf&i^“$ßB±V°scň…Ä}×’Źś÷†Đ’ůőRÇ0°üŹürKţ»äż[ŠUéöŮ}ŔšťCdÄ>#|Kě®âÝąđŻ!5őýák‹AO~–¬rĄX8BŹ…˛×ŔüÚ¦—$~§üVH}Ť˝ŘX¸ď{)[ă]’řŰŁ¤2§ę€ŢË…dČĘřćNøĽŁbőU‹űrSUë\ŘzYóÁďďgë(LŹÍgÓµ»–"0í㤠ľ\)“jńHšŁÂăáÂt18«_®‘ÜSgVtť÷NŇnşë¬ÖÇŔ>ÖŔj"ÝXŰ‘«ĄŻV¨Żĺ¬ů)‘Ů>;˝Yě$Âúź|°Ş˙ąS¶ôľ°T1„Öxß[ßCݶdpľ4Ś€0zý:}š G'<ďPńßžJ ;•rf8ź›*§Ë‹Ăµj._ÎäČ@–žo,Wžó(Ńň÷)RǡfÔŮ~WÎĐýµřćÔřÉÄىŔŃď=XCAĢMáҢÓČ%ÁD0'RąDC ó΋AÍA„±{ôK(46v1ł3°%kĺŚe]bôéżôŮ(–Éx0o]‚‚ů®ä‘ő±s‹öÎuľ-’e|ß]ś§V{Óů|q!EbUs%q˝o±&¬P´§kŐbę¬ĺ\Őš¦‡%ť“Ą4˛ŔKúmümV2iq;cĺąš)kâÂľsůô”xĎ96‘˙˘đ_Im©¤j…=ÉjźŤpĚ ¦R)^6P‚Sť•ÚT%C7PËĂ,\śŚłÚ’«÷e'¦¬ę‚e9ö ĹňÖŚ¸Ž7^J;—iĆçŇ9aаƋÚ[J—S6µRdŘXuŔ¤‹Î}ĚńĘY‡e;YÂĽ5ílÔ§ÔUí%,şý¤Z@”—ęxĹ9›ś)ű q gťM‹ńôąśCýUčR¨%«<‡=P vŰt°ŞUttŽť×M—Źľ|šDČX©b‰¶]'W:Â×2[¬”qĚDfŠď’×6ńIż+‹sSNŚřtŃą0«“ľKgŰ™Źsżm,ďś°Śe¬sŚśsk,żŔËÜ9[,ç#ŇyuđXfmÂű»ˇŻE°Ä-$šÓdcËaŤGkâŞÍXÖ9ĺÜ^¨ÍYe|żř¶¤Z~é2ô4=Ä.¤mőBéµ?ź®TD‚)Ś{ víĘĚZdŚ*ÝÍ„čŇĹxa6'îťĘ§ gS`ĎC@ę&ĚF—ÔlÓ9ÜĎi 3–*Óůšs|˛­˛OY9(=2EzR““É’żă¨=&("cµĽF÷Ě”sYű°łÍQ¬Ţ: 0™!Â$ę\´Ú™Łň¬0SťƦ@ŠŐ 9a;4].;÷3Ĺ ÂŔCt†“&:_Ň #- Đ9,Z}Ń)ޢxŹĄłŹ8ŻGJĄ+ŽíÔ)'ꔎ×ŰÉk µýýRĹFňĎ20–’QiĄLÚjĚb^†I1‚YN‹×ŞóZÉ9Żçś‚dEţVŮ1Q+µůč´Cézĺ ±Äč ďu[` ÜY„<‹ °o›IĎ «¬"!yušQ^ô3‰ü¬}ž‚§Î?Rt@›ůą\µ¬UB&Ĺ*âŐ-sNý¶ÍM‹Š‰Í9´ ţ‚9csGĆćÎ:r·`9Š˘LĹą¬xu2Gâş$ę¤$Lµ"É. R™+:Ż˘Ş«™łâŐÁ˝Vq.±<—>WBďôî9WrúňE}E_Ńqo.槨¶§L¬Ă|ŤÎvŇŇŮZ:ŰϽζ\ś·¨•ó2űő!ŰËEÇvŐ‘5§˛ŰŠTž3ô#´v[­ËT捖NwéętʸŢx™ŹáůPş{˙>Â}ŮĘ~Zx^mGkŐNť Ű?~p’HÁ\u˛leje:­ÍÉk‡ŃŁç\ętŰ>DBNŢ}ř8Ź•Îr»”ŽÔ˘•ŕpĆ ř;’ÍU¨pËtłĘš˛qçT±Ť“jŽ=/3Ç`žQhŇŔéawŇĂL;M3››Úi{v>WŞdśÎg-nŮ&c˛=ś´ĺüäB±śťś"Âá¬čé2ą’ÓC TfI›&úh±ś"-­‚k†¤!Ô>¦č:‰ďöéˇ>'I9°g;iąÝ¤Ţ8•čŮ_Ńq T‹Ą#´Ë>¶1B¶„[Ą ™Ĺ7QˇäPyŢ*O+NźIéĆ)NߏĄËÔîć˝éjfvTô î°ŞsĂńj5Ś­s4 f`ô¤ćísRÓeË‹MŰ)Ôˇc'8HŞ:äót×6˘Áe[xqdm€0QĆa»˘xMĚZy¿Ųŕ/ę3‰ć)z*éyçl»sÚöĚÍĄg\A]  Ľ‹šµćM›yM,Şés~µçî“:ěAk&O$1“rťĽĎs X%şšŇ8#ŽşÝ¶Yü1Ź>´ŁZi ‹‡ŻkŐąÓĄóNS«q‹ćn§Giuą—h—+WăĆZyžĎź¬ä¬qn[tŢÎívüř›–Ç:(Ätµć ~ŰŇ…twVFčçłi1Xy´–v’t±Ż !AŤ› –4?Sň»-kMŐ*řOܨڇشb“ćĚaÄéöl«őO.á’KČăR%Ȱń Pę(‹[đpe¸5Ăy©6Í:VżbO]ŚŐĽmA«y|łâ%µ”{ŰĹ ÍÖŔ˝lëëĄCNžă<[ĽČS-mň4m‰üѦR'ú^ňv¶Ó)vQöZ.™Ű[Mm˛]BĚDIőľK˘ť•-ş5ţ" i·łNďĂ‹ž@[żîC{eă”?D¤,˛¸ź ál7i|ä2ňüăĐ·˙•˙ţ4y~WŔ˙$Jło/ sşHó×?&Ďżi>…Ň|îćTŘŁ˙Çĺ4˙ĄůĆ—ÉóoYš· ˙Á[żFž˙ÍI{ {žâö×"ěiö±UR^¬EÂ~ôßú]ňüKöŚ[sËyţ…{V„]6Mc|[„˝ …}ýrŮ>-ÂÚo–éűoQŘ:ŞU}‡ůż.ü{k‹2ĽĎ 4ĂŹ°rS˙Ł4/˙łDŹčżCinů¶S'Ńţ}«Ţ*Ń"2/Âúßó§Ś4Íg¬ct˙đ/‰|~‚ŇüĹŻ‰|~Ą™yyţŤHóżEŘŠ—~‹á@ó˙K”ćĺG¤şgűCa/ů[˙ĹI3¬Ď XŹ XŻ—ë`'ÝŐ;`ŕÝÖö/2 ţáOübO˝jč÷ů¶±Y§A:˘Ž GgˇîqÖ.ÚóéÇɧH‹ˇĽňňü&+@ŕË“rE=†ŇüĎnF(g_(éWgĂR˙W„żyíw%F‰<ö‡_Ě5‚`˝ś‘ňvöI"€"ňôٰO˝$§» …}n+9|]„Ťˇ°W·HĺŤ  °/ýTŕß Gá_-ŕw­ůw†ÔĐ7ٰµŻJĺ‰mEaëčfčď°í(솲”.R@aăż$ĂLˇ°“”˙V„íBaŐÉůíEaźy<˙«»…}˙‹2/ťCa?y%¶Ţ(ÍĎŢĚx–‡íaÝC´ý;‘×›QŘ  Ü(cQŘ{?!×˙ť(ěsźÓa=×®qą…Ýú˘ ó^ö“R›!^ě˝błśßQ6÷ʦ†NŃó¨Ý=dJőEŞy6"ăv\„µ©Ýŕťpô­(MáÍ2Î÷á4OÚäS, ę„Í?{š<_iîGi^›1¸đŚ˘Ž6ńu*ÔQ'ü Jó•C" ędߡ‡PGzĄůęÁ;ű(ę`?x»Lç‡ÜBşýk@ĘuŔ%¤Ű·Ź<ľµ|B:ún„čŇ_É•ő0*Ü×˙;y˛q@ô9äoŇüPcMٰß˙˙ #¶šĄyůŻ“ 2%Â:ľO*řr1S˰ÎkžŤĆ*Nk~QfĘ÷ˇ°‡˙VĘ?2‹Â¬#×\b3(ď3›exďGifÓď¨b9”&C5S!$˘DiľE:žt?KsĄy$+çó!”ć›O ÜćPš—hÝ -$RŇ0Ř«DHDîp3Ř7iś·/ŁPD~ř#R‹‹~î‰_WśĄyĄůĚG$¦Śţż(ÍľAě–¦‚Ň|öĂSF?ŠŇ|Ťâů#’bťżńO2#×PŘGd†EędçOţśÁÖ{ŢpýbŠóřIöÖˇ¦tőÂeĄ-®—MŁ}ľăF]´źRiŻ{F žJ“„†&Ť—;r?*wśźý){ď€w=şz BŘxç|şhĂy(<ŤlĽ0Ť•ď̇‚f,]âG žJĂn6®÷řĐ5îE׾tĺíȸ Đ@ă¸Ę§¸ě±taŃĐ‹ţSŘą_©š8'§¬Zc}ç=ę%ÜŻŢÚł”Ú‹‹Ú‹ěţWl– 1Ü ĂŐ*,LňÄ»ř­"ľYô„ń- ŤďD-äf$ÉľČĹłÚu(Ä_„!éŚÍř@|ţŢďĽ)™ľÝ¨«)=©†ËݦQT*îNŹnô%Ţ˝şiĄçĎŕüx7¸€§VüŔyCú©]¬O7«űŐËö|‹jĄňö ÔľŚĐgńíěŃYüm2ÉY8Ş‚O+áŰqUr’6Á^ĺ§,ńŕO?aÄ߼‚µťřU&u@ą·ŁrS<îćjxĆ•đ6 ÇjxŇđ­k«6őŁM­ ŇŇxŞś„¸|ţŢcYŘ aýR=mMÎTdßťMPµŃąC—Ţ0ä&…áE}ógë98~¬®üYzżüe-SÍßx^ÍżMއ#Ń6®ĐaLůžPľŹ+߇uxëđęëíeŇŹľj}«ĺwÓWŻ1ňgâ ‘ÉŕsQIźL^0<^ŘŻŽöő<÷g};Ă˙uĂéRM”–“ˉíç|<ňâ.ŽoC.\;¸Näş›ë. ±ßą„'ÔĽÍ’yÄŕvđ3cLU»u ČLICŇ›ŕyŢŔ÷ĺ,ţmK†µ>«Ř4î~•»‡OT¬2Ĺ»X°ňĂ‹…Ěđh©”Ďelă#•ásé ůbbŘŞfčs\‚hŕŻë7%“‡ry+Y™M—-B‚B…Zˇ w[ZÔH‹µ‡Ä˘Űt“ĹéduÖJŽ'ÁTĹŽälµZŞŚ /,,¤ĆwŇËú¬L5U,ó˝G‘Mđ˛ťŔŘ_,-–éĆŇäÖýŰ’»nşéşť»ŻÝµ;y܆ążX¶’Ç-g[®“ôN’ôřl®’„m»Iň:]¶ŇĹéęÁűćäb±–̤ IzŰ+Ý)5U«ZÉ\5™.d‡‹ĺä\1››^DŕHPŤđRŮ.Ž};/Űťc'’wZşÍ,y¬6Eh›<’ËX…Š•L ¨OeÖĘ&§8¸Mxb4%ŃŤřv­Üś´r$Ľśś·ě“ÉÝ<+€»#él(ŢL`mMWiqĘIvf)Ăb’^ç@H©Ú§! C6™+ŘůÍK¤°ł>)ţB.źONYÉZĹš®ĺw¤Q‰¤Iž<|ü®Ł'Ž'GÇHž;ţŔÍ$Mu¶HB­y‹AĚÍć#"—Ó…ę")şş÷ŕřţ»HĘŃ}‡Ź>ţ)fňĐáăc„-“‡ŽŽ'G“ÇFÇŹŢâČčxň؉ńcG'¦’É ‹"É7Ń 8>U2mW.ˇwÖ˘&ą*.ŇÜLŇŹ&3„ńBT0![zž€ˇ+’é*ŞĚćeĚćö2 ± ľS#_̤ó[‡ĎŤIň˦‹É[v&áęXŰiI5»·uÄ\Cc–ÎÎĐ4ÁŐäíĢÁ… MÍXUĆÖtĹŢś¸•DßĆa ÚąN'·ćH`-źßZ¨8a‡“đ«T‹Ą­Ië)«Éé\!›,p IdăئőƵÉl‘™KŢšÝv3ÜKe§¦Ň„’;űRĐRş:»Ő.‘µ,¤ß8Î qdŇ´tvű!ÍVd)ć †˛ţ­In q+i…ä†[“S““cŁ÷ś86ş˙ŕädj#}r›˘eU&j…ł…âBA–µöü6ž ˙*•ď¶ú8úÍŽO>˝ç›Ź)Ýź«OȨ™ÜĘ%ę8C×ÖŁ& G4Y…qťš¦üĽ×p•µ v!ŃfĄÝ¤íČM…ýyC?ĺ#(ľďQˇ·vŢ×.ˇ•śxWÝ´÷Č]»Ś“Ţ矼AűâşłůüAéFő‡ŢuđÇÝxřGÔÍg™ęËüUrö)-S$»˘»@F­[3Ż\ ÍŁJµ´†Á­apkěKßÖ0ř"Ă^3óéKs ˛ăéđŇÜ\·ÔĽŢ,äÜďöKđ’Ó[&ú.ŰżjŰEnŞŽm­üťßZ.űfĺĚŮ›űwŇĂÄäQ™/ OŐrů쥯jű¦eä3„…ćÄ/̦)áa1m… ­±JIöá˝\ĆV¤(Ý:ˇ`Ąč‘ůІH´ÉÝĘX42k°&·Âé¸6Ă͆éTNPůM›%•'\2 nľË0n„|hsĄ:Öv€Iao4Ř‚ůfC4sk`lF°ŽĂűjCń¸†¸ >k ,›!îjđăř €ßZHGĂ®€2®‡tWBś«^ *'é1‡«!ÎÄáxl*¶˘r“asänżh˛“¸)Ŕaź#¨ţĆ ĆOo‚ôă(Ýz?0Ž*0Î,ŕűU„˙qđëšď:S?h° Ź‹¦?e°]¶¸NĎŔó!Č˙4ÔÁ$Ŕ?…đˇ4ţkĂÍ×<ÎÇiH“AeČž3P糀3•G˙lČ|bAHťE®|<çŕYşá»dČ|ó¨áÍ7gż2*Gp(ŁrÔ|ĘAg(?¸>NpÝcBqxáHó3ä˙Łed/Đ’ľß`ČĽËó9ôzĘyůmTA7d^~›!x™«&Ô˰wľ¤ýE|ź|ßĎwŚ_|ź5 gŰ çĹç× äĎů÷9÷â~ ô:[®µ#ýnâń'¸Äg™ýŽ č§¨”kŰŕąÁpö_$~ťąˇŢn7¤±Aââ~Ła¨w$úÜďä™ř÷Ě5u ŃçZx'ĎÄ`®A¨űŇ>¨é6öLü&s BÝN)týţ/őćä8#xVĆĐA'đsÓ…bUIńHĐť«Ř¶Ňj^Ź6ĚőuNÍtLĹt«áĘÔJŹ<Ú‘óGŁ"goDţEÄÄ”f{z‚ł›í+ łŔđ<ďä™řs B˝ ŃçeđNž‰˙Źąe`Z.Ě Ă™\©_ů2­25v^íĘËŰV޲ŤuŃĄş-t„±%™ž®Â*ít®\Ë–ą™Şe5ÜŕžS'đĚő*–ň„ŃëźţtÜčőÄůČ[ţ\‹b9!oR%q‡áÝthxgHŕŃJIIŮ%§ĚůÍßéŠŐ2çX®U’öČI˙Aˇü¦ yÔ2ëNfľe®µ}2„g+ü8¶ű!Ř/ß«€»N­ĹrüëýXĎ‹P^‚1Şô»kŃśÝď~ľaFGK4ôAx‚KĽJÜ7–E„q˝Á0„«[ođa+ĺéRX4‰żUŠÇÚ\nH3ÔŮ´yµaŠž Ď[ŕť<_`®A¨‡YÜ ďä™ř"qżŐ0Ô»}^ď´3ţmć–;đ¤ÜńĄ¦rÇ€á+€^SăJń#7uM«dříţ%hď\~tňöŹçĚ ‘ÎS>ńµG/…nŤ~ĆŻ|$ćfť˘p.«“Nkĺřýz:E VŔ7Ű+Uşđ_].÷Á×GUŇÉw>/ŻWţ?P¤Hq6ĺč~ôGąş~Îv ŇY¬xŢďä™ř2s B=Žľ=ě™ř s BEňăťř*s BHôy%Ľ“gâkĚ5ő(@şßG‰Küq˙ąa¨$ú\ďä™ř#ć–AŽňţÜ0„­»?÷•Ł´?Ą˝ćsJĘ+ŤPR,D”ŇÔĚxĺĂn(Šł]ç‹°ąE-ŕz9ţ+~zeďC§Rg¶NN>±ň‰C“Ű< ;DÎŮwŢjđŹ˘óZaËu•áß!$ĺđď«á _yuH)ŃŁöŹĐ}xo4꫏Mţxşâ_-ÇźSǤpWǾŋˇ{SŮbu2W ,™¶× C®Ż'Î}łoéqóÉ+)·Č)Ő™-A#°­†?żl“ĂϨáŰĺđn%˙kÔ’ôrG®â䥄üŔG5?jE—ÍÂŮbúwÓÇ 6śŁK>{ŕť<żKÜď5 u ŃçFx'ĎÄ×™kę@: 5ş‚=żOÜZ–.…w‰†á jëď}»”kŚpm"AgRĹłJňrň4hő¨3¸çŮ{ł4UŚßNßâÉ ‡ĆOÉń7)ńw5ôaĂżˇ_+…G®ńÇţě†|‡!ýÔn”ăß«†ßdč٬ma6—™Ő!eďĄ@FŚz*]†Ł+äÍM€ÇźĂÜ@ĂŐsÝM_oµç;z ŢO} žmŢ;ĘÔ÷ĺÆCn;Ď+VbŔş6Ý©°˘˛ÓÂęfŘHp" ¤ń°=ĘrWÓV©1}ĄygľG—ďÍŤ€dć{t{–k©ĚeËŁ±%#uopÓßśÝČŻÎ ĺYó§´ĎqÚw±:»š3M‚­ Ľn8ę×?đﳦîpZ2ß2ČŘŢiĹłĺĹ„CŽź4˛mV…ÓXëe’öu J4@\ú}FwZřŮżécmćő*4us†ťĂ VäëxŽ,6[DÁ97u!ÉÎiĄĘĆĺŻÎáĺYH Ăüë/&—ósŞôîÍ»´Cą (Ć7CRJmF”kŠÁŢűv•k.v >^ő†©ĂL­F`ΔĂěuţÂźç­ĎŐSĆ×xÍŔsŤ!×pS—HíVłśűyδă«Gެ]V /%¬§eľq¨I¦ÔYńF¤›bŁĄľL)uS7&Ř9(ËÇBů:uËNŹ»#YÝd Z¸‘VŠHs8̤‹ŢyRTŻTŃԵບęňbr‰1ă—Â5U!ŢßHÔ1·b#łí” `}ńţ˝^ˇJS÷¸ĆNî…Ů5¸ĺâŕz‰Őŕ6VsÂč:xnP¨€ş™ ßĎáŞ1uéb„çUđÜϡ:ëshYKr)ŐgŞlăQ…–öjxn„çĄôcF÷Q:_Ă鼞۔ŹMÜsdO őŤůŹćşž[YŘ9V;lŽM\Ż«u./&—†Đ±úßxTáÖ9řÂg=šč‡Jő ß8T‰Ŕ~ZękÎZEJˇÂ¸ŃÄ 9v;•šş9GHô; çGs˝žĂđÜ…¸[§Q'l×ç¬3Ľ'kwło~KĚ2•*ÓŤ€éFL÷°šßyq0őéĂś>~ϲbr)µ¸~%ŽÇn5š×.ŽR7 TÇŻˇ˘ó|–c6ş†ŮmĽQ†SĄ Q…â2 Ôˇ]?5J@˙qD1ľ,ż—Qîęĺmě\©ŕ9t)”Ăż8ôkŞ<ŹfóáĎS›ŠŔî8\ó°ďć«p†^Ľ–)Ď]Oy_ť:•ë?%ĚáĆ…M «p"°ď SäŚŃD3 vŽ70ŠÜË1 ;ëxK¦9ęşnÜUóÖ{Ă8µĽ‡ĽÎfŽ›–“KIň:Ą>ż†păp›Ůw6ÚK0Ó4î^˘ąµËůč硗Ŕ–VJ˝›E~‘Ůů™>ŽďâĂú.äz|\;¸~ä8,ţ˝\—â aŚ »ËŔ ‡ŽtŰ}:—Dn¸Mŕ®·9ŽçZp[ÁmWÜ5ŕv"7ŕö"·ÜuČ ăß7 wSÜíŕnPÇeÜ~ä¶ăß</óÁ p÷"w´Awą5ŕîCŽăĎżď÷¸‘;îr§Ü$8˙ap*.íă˛ČeŔÍ€›g!Çů„ç;» ®‚\ÍÇ- Ç˱î1pŹ#÷DH‡ÓäÇó9î)po÷vä8/đoGmŰÔ˝Ü;‘{¶Çyń9䮇üéGąóq‰]ŻŹ[Q‡Sá6čÖ…pC¸-!ÝŤ»¶wý%äîhŔń2j’;ÖwňvS!Ýôşü2»ůîÜ29µĽoi‚Óµď§/Ž ­»˙ŚŤ\č<˝2Ł—wÓ´Č\şsŇÖDgç@O˙Ě18—đüşě ¬sąJµb8§ŐlĐ?« DŮš+Î[ đáŮźIĄB=ZŠtg©BeŇ*ĚO˛›Xpiă>Ą…‘˝Čď{đ_ByúÄÇűľŽkČ@°°Űzµ”ŕčµ?D L ;‚2ÓŽŤ<©Dĺ‘ü$zöÚôś±ŞăŮ#ąÂY™š!¨ůž Ň‹¸"<žµ*Uţ$‚űyx\Ř~QĺĚ!^yÄŠ%”…Č:]­–Q*ęăŮIv{›;\Ysčý­ěÝĽNĂE^íM[Ůчn¤zŠ—¬2ed D oŻU¬}‹U«b¸MŻk0j™·#¦Fnú«ĺő “¶ś‘©ć K®˘™7*~\”ÄC§9ł}$dyĽřÜ |l$µ˝~Rů6)â÷5kéÄ_+Ă0Ua 1Mmü“g ąŞľĎ ďĎa ‚´âf-ôź”~“ëOPŇyoR˙Ĺű#MĽŹŁđoŕ4JĽo x ďďÖÄ{ ĹűS]ńâŚDÜ˙ż(°2ˇ°ç4t§wŰü‰— f˝÷±”˛ĘĺbYŞ’Če˘JŘ=¤ţbŮÜŠüf'nÓ±m˙Č©kwŢtćţHşčqÁtó7ĂĎ‹Ďx§=],ĎĄ«“Y«T‘9ΉÚCÂ,˘ŐŞÇÎÎTˉ$‹ŻÖťY+ä­Y":ó65ë"Bík± 5 m3{€ÜŽPÂ÷Ł˝W‘wSGzA®rŔ*‰?DXj2şŇRĹ•7aäČý¸M*…ůžšGn˙Áš‚»ď't?ŔëěčÔ#¨Ćî˝ryĚ}ňđŁ:ë=pđŘČP%yj¨r&™LJ%Ă „y`ÉCaîHjňóĄšv‰îŇŚ«ăK¸ż,2 S,µĘ×ä|n¦@ šČM"˛÷†>7WmDçýS:YÖ7U..T¬űP¦,3–ˇw•›wjŞűuŁ÷>%Ľł_/*TX6ë rc·•ĎaµQŰbsür›0ZF‹ł›\“fޢŰm8]*ĺQB]›ňĂ=Rvc®m][)%’‡*·‰¨ł©żÓŞ]5ž±Ó§7:éâ§4•|ů­ŐÁm;ž«ć-칲ÎűŘCďřˇśJdÜжQW+ŹmLn4B5qWO{‰X‚Q»SOiŃÓ̉úwŐńP˙˝7 sĐVyź¨ňdr¨ÂŞ]›"¤ĚĂđţ¤˘¸Čéô!ŠŇ¸Çpö«¨Z€č¶N9©ŕf[ ňEU,÷"ŞI]ŞO“>Ţ5Í›ÁQŞýG>a:yG~/ęŇÖ‘^¸™|q*ť']ŤżjţtA„~gIć ݬF—›$汥`”îNÎP&}ŚOBţmž4a‘Đŕłă äăUĹßőŔ[¤©˛•>«!Ł9ż˘kq±­Ű: OÚť ŹGf«:7`Ŕ!ůëÝa3ëe™QÁ‹®5†ĄFÚ9]Ëç]ęqÄŤ&Ňł*>ľFp9D×Ď„©ł|tŇ Mé v“; ČERT4ú°–±LQLí!iŢ·€ŽIŔŐć ő#ô”ł¶3éŮj÷#CYň·­SŞ#óJüeđ;éĄÍxµ/M—úĄçPĹ˙‚•žWfsĂÎC„ť8;qŃ'Ě (=Y–)†^> gwŤ{ÓúTşĂűóčýµă7”ÜóVyŞhźŰT{JĎ{$§ÓůüT:svŇéĺQzžN OĘ˝dŕčşŇ "8θíü´) {sʦ ’Ŕ$ř‘±±ĐËC«zUîăPąXgü°ĆUžš–¦ëÚ'}şö.+öWj%{ĎŔÉtą+ŕ9•?\’)#ŞúŃZÎŞÚŞŻ×ütŻsiUŞXPc†čŇĚIä·¬ÄÔăéDy~µNŢ^~aI´—çŕý#K†yfI0˝KEôQINx”÷ET ËĚ< ç%罺&tpş°ĄšśÎ˛ÉtŇVHٞ’hú$™)– {•Š…,á®dµ„fgGOn!ý’»€ďs$ĆyĂţ…ŕüÓ ň&öWą~ŤąBĹ*W'Ůš›B… FßEZüÁÂüčH.!O´,çҶ·!,ra3ŕ Aç‘YłÁŰU6 áď„đ·K˝ú ţ `ľNqÝ’Źi<„¬ DcÂX™˛Ä\nΨ˝i@«Á«wá>”÷jĽG8żďĎ#fyütAW•t69ĆjESĺTý„Đ1§rpÔÍ1kŹ43Ł•QiVauP»M>#đ‚¦$çTm[Ţ?A:‚|ÎĘňş#9TŮ‘Ě榧­r%9].Î9M7W ~eŐöeęĹabYBĽň¦Z±j)±XćŮ%Ą@!Űż»ZqtĘľ\C˘Č¸Î)݉UMĎÄ…HQŻWă‡G~Ď ^ä&M\í”Zo*“ÎĚZG Ł•Jn¦ ‰Ńť*Iś˛_Ňę^«š>ć\§ÁiDÜ!ę/ŞIV¤Ž§§ň–ś0L^ÝűóéJĄŢĚěDőgÖGęţX>ť+¸ Žš26ŁwXĂ6 8ýĎÜá%5Ľžú h“ÂÎł6‘ĐöD)°*H66aXÓ!óđ,–Wćt­«řÄHĐǰ‚ěŽR°‘X>QÚHßl:I¸Ń%±üqéáźD’@ťôcoZJë~EŤřŢ«ćŻÎćvfĄŐ ‹D~0ßo>ą$ Ăŕ:¦ů9ôđéľú59ś€÷•XÜ2 Ý ŕÍźĐ`ŽqÁ+ßĹ0ćňgTňM6î$NŁ©ô’÷)5/Ů_ŔAaDOĚ%ę €×EÍÝ…q?#'”ăŕ©Éɉ=LVl89™ş`žAÚóÄžÉ*ë⡺ń¨“ßÍ·„ŔÝţvÚ0’C×^Îięčś®Žŕy-™>íĹźpęĺ±Ç5ř?„˙rĐ%d=O6ČŁxLŞ‘kb'Ľ\3Ôńo“äZSŕN*ĺVĺTrMŕ˘]©3cś7ć5Ľ1ß@›áđÓŔ{lÚ ‹–őµAOz<ˇÁ˙‰&´Áşé@>ď$Ü!{ëŰŔäD‹ěQČäŠřě•u×l_Dˇî[j´¶J5íh¦N7U±Ş| ĺQDEŕĘ:L¶çeś´ÝŻN±\+ű™OůU'¤Ů+ÓÎŃ“í«đ*D –ëó\öF+ő”­uČčÓ ĘhYó˝3ď‹­©“D~šÝ;|(¤Yúľ ‰éŐŰ.hXcÁ«Eú´ěE śĹ-ŰK2©=Žvݢ3•«¤Đ´­+•ôHG2¸U=̧=âÔMwŹš†Ë-ŮŁ>]ŃöÓ.„'ťŁ»JE´'Q6!·’†@zŢiźÎµ¤ç›Šô‚Ň>\ŐŇ #íž‚ÉĐ™-«0›±§Žöłx"–v6Gß1šUD‘ ýÇ5.ńéß.d§Ůă/]̡"ŰůźŁŞU.“fŹˇĐ—‡ăQÇ—ż Ď4µ Ďzdqů ňlĂqĎ ĚŮŔb3‡YŃ—K¬\ⓡ&sž«›ýh)µlMçÎ)(ą jęvúâ€ařžNeÉ(ŇÁ(¬6ÁÔąĺR›d•ÉąV›ú-,)(y÷ ńűߍKJ¦G‘&Ü2؆U§ę$Ąity—a<$~¸ď ZŽčÁůhZ%Ţ łVă§m©ćPĺńˇĘ“.ę;|xť’Ű“‹:hř:hxj§:úş ­ç5uđü%Z]Ŕi‡ôů×++ŐĽćPËáŇ}>@šh˛'|ÎASZ´ß{đř]úôsőרÖĎ{`4ěŻëç/kVô?>2WÁ™?Źââyu5žP¨ˇźÜ8vĎť#Ň~·'Qň:N${ ńx$̱ =Ź7‡ŰdĚ[U˙€ô‹Jü×ę…yžßn€Ł›Y×Óc¨âĐĂÔť_lL”SŮÓą\“ó ž9'˝rohęąr.Č~ĽdhíFŘqŞ‹ă@ö śąRn˛b˛R¶E C±ô íěíłçzjŐ\ľ’‚ŞĂ0zřń ;†&˝mŤ$5kĺKňÉ”;ˇrd/U],YJYčńąŁÜ~ŹZ;Ő$¤â”óŔó5Ĺ÷ó®©ńŞu®ŞŻI÷şR ĎcŕýÓwâzÔ`ń×nuEÁË:B1ű®Á;UľŠs>?ř˙_µůîNíşÖď‡ńÍ÷éŕ.¤Ë…cér5—Îß›®ffGË3=®:IókČďĺ%…ąĽ`űĚĘ~\çäˇoÇćű˝iŢ˙v q™wW!-g«syŕÓ1LćÁ‘4®/µ5®´eB:źź¤[5i{’íS°Ĺg® @jI*·+_©ĽŤ^Ą˘wż9©ˇ [Čóhő6ÔîĘH‰‘oŔ§® «‰´§›b(2?ôđK%#š‡ŢÉ;«ăůĽ›;WŤ řaS(?«JOHQĚŹ„T >âÁHË7?„ü®ŃŔř†ŃKQó>#;‹‰¬’$622‚Šá×>Ě =3Me{ŔÄôW=$ß·ĂůW7éŕµ–Ľ„‰ůŕˇi—Îqť&ÂÓ˝˘ŐË:Me‹őy„-•,ŁK†KÖR˙mŘź0d×axÔ€[;™\ Ň|Ňš§&ýĚřčQ^WřÁ‰‰qo‚‰xÖ9ĽHŰEŻĆ( ĂÍá祾ŻaŹşXŔ?VÓZAą¬sSň$Ĺ-i"ÉU’Ö\©ş¸ˇS÷ŞMÉt’ýŇ%şµ*Y°’˘Lú$9HÂÎŕ'éÝ”< IÎ摎c¬Ű”´ †•ÍU“ŐYËd˙¦d”-4ţŔqVnJ†KvśBz>7“®ęb mJÖ†ł;NXÔä©’u˛VÎt(¬Ý”|•ĘN8Uه®<Î#Kf\|ް=ďÓČEńĘ*ůńx×–DĽüőî×·™Îö6Žů1Ą‹čEqÜqÄ»˛ŃbQ„ş4Ŕ¶…\¶:Ë[Ě_y·µĎü…B3Ó-·Đ0-1ŃyÇNňKŠh7*U'M‡IĽ‚Ý®Ů)"läT±á_–Âď=Ż„ jśłŠţč꺌]lçť§ň•úĆS‹Z›XŃä5tÂ;˙Ł»–:äŹę*ŔŁăŐ›OJjH€Áô°^ĐFybZGżh2$ůđĽŢôţX2óŢŞ†jŐ딺=»¦ kµc¬r.ăq@Áµ[ˇ‹éN‘ÄOs6Đ©ŁŞMXk­9?Őč3>Ş‘{E 5˛@ť˘@r7âś•Ní…%)Žýţ°Ďţ»ÔHt‚ĺ×5T XŢrŚ•–|)9lĐ8T,ČUJtLçd¦Í\sB©XĽ˘&bYČ ęç ĆCÚîÔ†ÇÎfúšađ ">§Ćľż!óNdĄęď. ůYg-zÇ* ‡¸»y¤­ŕ!ËAç=@7c†i~±*6 )5äC0źŽé…Ě«UއröúÜGKĘvţ€*Ň1ýФ‡ůńL˝őéS‡në%:’wgˇ÷”,á¦Q—•ś‚ÎJŽö€—‘źDţ‚†žĺßFńcFPŰH‡‰›}Ż ¦ĽR8.ď:U»0=V(;s•¬Ó7óP>‰¶nI¬kń‘Ľç)± ˝[Ăş\˘|QéŤf1©UöŚŹŚŚ<ŚŇą¤ĂĂ!‘RęÂsiDá‰5"žů‹KÎ’ŤÍz|©&”ˇ‡Ž…Ů\fv’ßUŻ8Éüýú€zEĂKó·?Ô¨ť^7éz‰k^GX/?­˛äćĽ^ ‘±µu>ŁýŰKę˛uŮĘÔČmŢmQ;í­AĐĽĂ-ÔL.Xľ„ź[˙5éŽ-ý8Ł'ç‚-,›0/dľ¦´ű+âč5!€µA×Ú»r•1n;N“\ÓDź–łŽ+§¸ő>m/ĺŢúËŽĘűOô{L:ŕr&Ľíć{ţEÖt6í'Ké˛tů„ަěxÖźçý5Ôˇ}U©&ŤUC?PóĂ–ńhŚ÷'}`I˘B@ÝîďčHŮťšś<81qpě>Ű܆«)G<áš×űÁŤË†ŤUj¸ű¸BĄ˛8§ÔG˝÷ŕıŃýeµrÓ†39źÖśţ]!ßěę s®Yl¤©ňĹĚŮ}9Ű‚˘čÓ$%꿆p C‹çµ!5đĚß[ň@ľ+uor7 ^éĘ»fŞ+Sś›K˛˛řĂm…ĽŻĐÓj+o„ż}Ƭä gqˇ[é•G•j¶X«uLôôýĹBÁšzݎ_ŔŐËóuŮĆ+ö-oĽĺ8“ý`đ„PŇĘąŞu„IC®$93çý›ťÇ„*ůGüÝ[G2±=fß|ÍťÇGÇŹű2›÷U.>Ú×ÇuL )7hĘ,‹Z^ÂĎ/”­J5]ö¸%hóXMX¨Ó)·q);LÚ»_¦¬ç!ÁŕąÂ|ń¬Őś0ý!Hu–@ĐD9cŹg}hó’ŽúÖŻ§łď##ÇÇŹŽŰ—ލěĎP ·´őŢKÄ7jţ9®x 2¶qýúđĺÄŢů´/QŚÍ?ÓŐŘŔB®:»?ťĎ™{‘y«\QőRŰpGąVŞćźhkťÂ¸/WÉ9öłž_2Ľ˘ÄPoVQvŞhއ’îđNĘ6{h˛{“ ş+u$]©¦Hß[SLcR%ř]^Jp<“Żě2Ü=őß­ńď(• ݦ‹FýW5™•|±jg§Ňş†(V„?â컡5ün'†ůß–ÜĐţŇšNµ†¦ćßx«“šUöů{D¨v7P',aÝc-˘||đáŁńżŐ«:OÉďo_Ż&Ţ—UcCÜüú4đ‚ĆÂZŤ Nk Ő2O‹:¸żĂő†Ău"CÓˇţĘw.‹ß×~Ĺň\]‰ÜwŚęĂqĂţ9 'tĺqťI/‚ŁhŞ#^~§­łyě§bŞ!HÝëG~ü}pI¤ďX §ĘëćEűu,Ń7Ĺ4ĺĂ•#Dmćú%ż·V7Ĺű…żľäâäp›ˇŠ˘Ĺw/uś®”¸•Ő­lj÷SCß«Śä>˘!·Ţr˛Y/“ße¸F#&­Ós^PÚj"ç%şP¬˛}ČÂüž(“4qzŇĐKŞŹm%µŹ’€öŞ-ľY+eŮŢ@Ż»NLzzŐç, ?čŚOtçS~POź/ń@:ľZř95nż]Ŕ‹…ô\.s;aŔó yś1Čýz ­4Ń HĚ˙©ă•séł–ł˘žbçT†+úD€¦Ýżb¶Z-Ť ďÚ}CęZňo×B] ܨpĆÖmɲőh-GFgö>λŽ?–$˘óĐ›/¦¬dąV(ŘS!-Wł» ‚E0>ĂŮbfRht$Öą”ďáŹHRnÉřú=Ţ|}÷ĺ,÷>ĚV +o¶ďK·Î©X"Áb~ź•ÔüP:ým›µ‚˝°UľvŃCLꂯiĽQÇÓíDTVJy¸eZÄÇhĐődZżąO xu«ŢŤ+Ô2Ít°|„˧Ý…ŔË˝vMş0-˝ĚŁlđš|݆ÎAÚ†vű%.ŞDűMF{ˇ,× öşµ ›<˘¤˝wşZ+[†ůŹţęťTź!"ý&"¬Î»[®Z@×j:ű's„iŠŹ–)a·*m4óźüSrÜG!B DŹfĎʧfÓpVŐP·ń‰¸ëĐ ¦X)ç2´+iü–bŹÁDAG-ĎŁTě˙ *7…ę Š"Ú/WD»Ďą`óEüÄšĆR›ź’Áł|!¶,j”“´˝ď)'܆ŽërÇnÖ§U¬tď`ú‚/âŇYK®4°đTňÉół‚=Í˙­¤Óč†ô(őâd±[,U=6§şÄ@g9“*–iWáz¦k…ty&H%Ú5˝*žlĐd•čD µ ^±Şhĺ‰zAťF…{ŔRÂ(b öMtcväŹgYďRŰi)ŮF—ŚDŻŕóŹ˝ô9ŤçQh3ćîÔ®˝©]†gáÄř¦G]}žájĽ†řyX7ő8®g^iSŇ9°”ŢÄÇo*=©–â!z(1M1U…®Ăňs5ă°€:ĐA»•ű'ę0š©ŃrĽxÖ*"Ţq˝rX˝)I– ĹťoëÔžŞm«˛„XRłű”¦Qű˘5*[ŐrΚ·öc‘Rű$˘Ö9ąő;i 1x¦ M1(;«KJ”öi±ßW§‡Ë p<ÂzłJŽń”H$© séGŠe¤N¬vésąʬÝűIé):ąäˇYE§u+xŃéÝF˝mşOkžçţ—k¸ĂĹóĘĎxäˇ_ š*fµy'®đÉĂúMÜS—ŢC§ŃěaI¬őIO(ž/…×4ľ| —P~0ăŮÉjza‡CŰNç™J¤čÓ q4´ KŮŤ†‡ťAŰ‹eőøÚáÝGőë˙qËŮYg\µÚ?'Č‹ Av!…îNâđ.rů˝ŠŢ]vŔ+ü_Ŕđ5íDgć .w¬Ë듎č’zdĄÝ˛ŃíCü”¦ń55/?}ÜWĄ+ĄóĹ4Ú9ö$˘¸vŽ*˛Ţ ÖoT˝br¨˛~¨rĹi¸ Úń:ĄóđŢŠÎüŹćsiŰ>eŁ •^y^š%ÝOo4uŇ&®ňH{©8y‘»lĄłĺ,/ţOXđ»Q+ÂQ§g‹E$‘ŚUÄőléăĄq“ô;n5qk€BëXm)Hâ6×qÚ!ÎVI!š=ÝGwq]öHOó"n‹Átâŕs›Oš(ÍJHCkęFŔqp\ ¸­ގéphËä‹…ÄŐ6~™µţu`Ęá+uuŕUÔÎ Ţ«Ë=ařŐ+Žß€mÇ`«•óhv”źyLfĂ+U]&]r&/ůá:0•Î&·PÎŰ’L—gj°e@ŻË¦[Ę&rZ%aŹGYjÔŢOŽtŹYt”H÷=޵Eľ7ůń`(ň:{·ź,»Ä÷§Ťn 7„<6 MLcqcvüó"Z4řÚM÷ŁyüĂt˘đë7tÍ6Ą|Jú:`^{§¦–[BsÚŽ…u\NaŠK<;48ż_`s E;ŁÜN!Żžzí4šWŻ^‚Ą{‰ĂďŇPÇŁ…‘blĺÉşŮ÷&ţÝĐ<¦ 5„úŠńsČu‚ăi»Cş>äúCşäVy8Î˶Ďk­‡Ł¸_ŢŐU­aDjQ«Č¶z‹uDŢËúo ÎPŤ`‚7‘„şK ¶ď'¶»Óđ_ş0Í %Í ĆŁ =ç®á^X“!řHáµjń ΓŘčEµjÔbř‘‘ř]Ł{ż'Żž˛°•HCĎ @ŚÚţî¬a%QĽ÷«zŐY;¬"BĆm\™ţc˧tŮß8ÚŹ˘¬¦;š† Rlő1T€đŇśOě„ç¶%‡`ž‡_i>tÁ Ćĺ•| P©=Çx{ź¬,VŞÖÜ$ꦄZXV˝ D—s™Iy&Ôv˙8˛b^÷şESS-24.01.1/etc/ESSR/000077500000000000000000000000001455642170100136455ustar00rootroot00000000000000ESS-24.01.1/etc/ESSR/BUILDESSR000077500000000000000000000005031455642170100151250ustar00rootroot00000000000000#!/usr/bin/env Rscript ## -*- mode: R -*- ## code to build ESSR environment. ## Assume that current directory is etc/ESSR ## run "./BUILDESSR" to create ../ESSR.rda ## exactly as in inferior-ess-r-load-ESSR in ess-r-d.el source('./R/.load.R', local=TRUE) ESSR <- .ess.ESSR.load('./R/') saveRDS(ESSR, file = "../ESSR.rds") ESS-24.01.1/etc/ESSR/LOADREMOTE000066400000000000000000000013711455642170100152250ustar00rootroot00000000000000## -*- mode: R -*- ## loading code which is first sent to R on remote sessions local({ ver <- '%s' ## <- passed from elisp root <- '~/.config/ESSR' if(!file.exists(root)) dir.create(root, recursive = TRUE) ## cannot use sprintf here essr_file <- file.path(root, paste('ESSRv', ver, '.rds', sep = '')) tryCatch({ if(!file.exists(essr_file)) { url <- paste('https://github.com/emacs-ess/ESS/raw/ESSRv', ver, '/etc/ESSR.rds', sep = '') utils::download.file(url, essr_file) } ESSR <- readRDS(essr_file) ESSR[[".ess.Rversion"]] <- ESSR[[".ess.getRversion"]]() attach(ESSR) print(TRUE) }, error = function(e) { print(e) print(FALSE) }) }) ESS-24.01.1/etc/ESSR/R/000077500000000000000000000000001455642170100140465ustar00rootroot00000000000000ESS-24.01.1/etc/ESSR/R/.basic.R000066400000000000000000000167631455642170100153450ustar00rootroot00000000000000#### Essential functionality needed by ESS ## Should work on *all* versions of R. ## Do not use _ in names, nor :: , nor 1L etc, as they ## cannot be parsed in old R versions .ess.getRversion <- function() { if(exists("getRversion", mode="function")) getRversion() else paste(R.version$major, R.version$minor, sep=".") } ## loading ESSR.rda might fail, so re-assign here: .ess.Rversion <- .ess.getRversion() .ess.R.has.utils <- (.ess.Rversion >= "1.9.0") .ess.utils.name <- paste("package", if(.ess.Rversion >= "1.9.0") "utils" else "base", sep = ":") ## Instead of modern utils::help use one that works in R 1.0.0: .ess.findFUN <- get("find", .ess.utils.name) ### HELP .ess.help <- function(..., help.type = getOption("help_type")) { if (is.null(help.type)) { help.type <- "text" } ## - get("help", ..) searching in global env works with devtools redefines ## - Redefining to .ess.help this way is necessary because ## utils:::print.help_files_with_topic (used internally when there's ## more than one a package) uses the quoted call ## MM: don't understand; more specifically? ..help <- function(...) { do.call(get("help", envir = .GlobalEnv), list(...)) } if (.ess.Rversion > "2.10") { ## Abbreviating help_type to avoid underscore if(!is.null(getOption("warnPartialMatchArgs"))) { op <- options(warnPartialMatchArgs = FALSE); on.exit(options(op)) } ..help(..., help = help.type) } else { ..help(..., htmlhelp = help.type == "html") } } .ess.getHelpAliases <- local({ readrds <- if (.ess.Rversion >= '2.13.0') readRDS else .readRDS aliasesCache <- new.env() getAliases <- function(file) { cached <- aliasesCache[[file]] if (!is.null(cached)) return(cached) aliases <- tryCatch( error = function(...) NULL, if (file.exists(file)) names(readrds(file)) else NULL ) aliasesCache[[file]] <- aliases aliases } function(reset = FALSE) { if (reset) aliasesCache <<- new.env() rdsFiles <- paste(searchpaths(), "/help/aliases.rds", sep = "") unlist(lapply(rdsFiles, getAliases), use.names = FALSE) } }) .ess.helpLinks <- function(topic, package) { tryCatch( warning = function(...) NULL, error = function(...) NULL, { ast <- .ess.fetchParsedRd(topic, package) .ess.findLinks(ast) } ) } .ess.fetchParsedRd <- function(topic, package) { path <- utils:::index.search(topic, find.package(package)) utils:::.getHelpFile(path) } .ess.findLinks <- function(x) { links <- NULL findLinksRec <- function(x) { if (.ess.isRdLink(x)) { ## Ignore `pkg` for now links <<- c(links, .ess.getRdLink(x)[[2]]) } else if (is.list(x)) { for (elt in x) findLinksRec(elt) } } findLinksRec(x) links } .ess.isRdLink <- function(x) { identical(attr(x, "Rd_tag"), "\\link") } ## From `tools:::get_link()` .ess.getRdLink <- function(x) { pkg <- "" dest <- paste(unlist(x), collapse = "") opt <- attr(x, "Rd_option") if (!is.null(opt)) { if (grepl("^=", opt, perl = TRUE, useBytes = TRUE)) { dest <- sub("^=", "", opt) } else if (grepl(":", opt, perl = TRUE, useBytes = TRUE)) { dest <- sub("^[^:]*:", "", opt) pkg <- sub(":.*", "", opt) } else { pkg <- as.character(opt) } } c(pkg, dest) } ### SOURCING .ess.eval <- function(string, visibly = TRUE, output = FALSE, max.deparse.length = 300, file = tempfile("ESS"), local = NULL) { if (is.null(local)) { local <- if (.ess.Rversion > '2.13') parent.frame() else FALSE } ## create FILE, put string into it. Then source. ## arguments are like in source and .ess.source cat(string, file = file) ## The following on.exit infloops in R 3.3.0 ## https://github.com/emacs-ess/ESS/issues/334 ## https://bugs.r-project.org/bugzilla/show_bug.cgi?id=16971 ## So we are cleaning it in .ess.source instead. ## on.exit(file.remove(file)) .ess.source(file, visibly = visibly, output = output, max.deparse.length = max.deparse.length, local = local, fake.source = TRUE) } .ess.strip.error <- function(msg, srcfile) { pattern <- paste0(srcfile, ":[0-9]+:[0-9]+: ") sub(pattern, "", msg) } .ess.file.remove <- function(file){ if (base::file.exists(file)) base::file.remove(file) else FALSE } .ess.source <- function(file, visibly = TRUE, output = FALSE, max.deparse.length = 300, local = NULL, fake.source = FALSE, keep.source = TRUE, message.prefix = "") { if (is.null(local)) { local <- if (.ess.Rversion > "2.13") parent.frame() else FALSE } ss <- if (.ess.Rversion >= "3.4") base::source else if (.ess.Rversion >= "2.8") function(..., spaced) base::source(...) else function(..., spaced, keep.source) base::source(...) on.exit({ if (fake.source) .ess.file.remove(file) }) out <- ss(file, echo = visibly, local = local, print.eval = output, spaced = FALSE, max.deparse.length = max.deparse.length, keep.source = keep.source) if(!fake.source) cat(sprintf("%sSourced file %s\n", message.prefix, file)) ## Return value for org-babel invisible(out$value) } if(.ess.Rversion < "1.8") ## (works for "1.7.2"): bquote() was new in 1.8.0 bquote <- function(expr, where=parent.frame()){ unquote <- function(e) if (is.pairlist(e)) as.pairlist(lapply(e, unquote)) else if (length(e) <= 1) e else if (e[[1]] == as.name(".")) eval(e[[2]], where) else as.call(lapply(e, unquote)) unquote(substitute(expr)) } .ess.command <- function(expr, sentinel) { ## It is possible that the REPL is marked as non-busy when the ## output is sinked because prompts are not sinked. In that case, ## redirect the sinked output temporarily to ESS. sinked <- !identical(stdout(), getConnection(1)) if (sinked) sink(getConnection(1)) on.exit({ writeLines(paste0(sentinel, "-END")) if (sinked) sink(NULL) }) writeLines(paste0(sentinel, "-START")) .ess.environment.state$env <- parent.frame() on.exit(.ess.environment.state$env <- NULL, add = TRUE) ## Don't interrupt `browser()` sessions (#1081) restart <- function(...) { if (!is.null(findRestart("browser"))) invokeRestart("browser") } ## Should be an exiting handler to be able to catch ## stack overflow errors rethrow <- function(cnd) { stop('ESSR::ERROR \"', conditionMessage(cnd), '\"') } out <- tryCatch( error = rethrow, withCallingHandlers( interrupt = restart, withVisible(expr) ) ) ## Print result manually because we can't rely on auto-print ## without changing the last value if (out$visible) print(out$value) ## Keep `.Last.value` stable invisible(.Last.value) } .ess.environment.state <- new.env(parent = emptyenv()) .ess.environment <- function() { .ess.environment.state$env } ESS-24.01.1/etc/ESSR/R/.load.R000066400000000000000000000057441455642170100152000ustar00rootroot00000000000000## This file is sourced when R starts and `load.ESSR` is called. See ## inferior-ess-r-load-ESSR--local. ## Do not use _ in names, nor :: as they cannot be parsed in old R versions ## obtain the R version number as a string .ess.ESSR.get.rver <- function() { if(exists("getRversion", mode="function")) getRversion() else paste(R.version$major, R.version$minor, sep=".") } ## load .base.R and all other files into ESSR environment; then attach ESSR .ess.ESSR.load <- function(dir) { if (nzchar(Sys.getenv("ESSR_TEST_LOAD_ERROR"))) stop('Loading failed with a nice message.') Rver <- .ess.ESSR.get.rver() ESSR <- .ess.ESSR.create.env(Rver) .ess.ESSR.source.files(ESSR, dir, Rver) .ess.ESSR.attach.env(ESSR, Rver) ## BUILDESSR needs this: invisible(ESSR) } .ess.ESSR.create.env <- function(Rver) { ESSR <- if (Rver <= "1.3.0") ## really old library() revert order a bit attach(NULL, name = "ESSR") else if(length(nn <- names(formals(new.env))) && any(nn == "parent")) new.env(parent = if (Rver >= "1.9.0") getNamespace("utils") else .BaseNamespaceEnv) else new.env() assign(".ess.Rversion", Rver, envir = ESSR) ## updated by make !! VERSION <- "1.8" assign(".ess.ESSRversion", VERSION, envir = ESSR) ESSR } ## attempt to source the files in the ESSR directory and place the resulting R ## objects into ESSR environment; the updated version of the environment is ## returned .ess.ESSR.source.files <- function(ESSR, dir, Rver) { .source <- if(any("keep.source" == names(formals(sys.source)))) sys.source else function(..., keep.source) sys.source(...) ## .basic.R: try(.source(paste(dir,'/.basic.R', sep = ""), envir = ESSR, keep.source = FALSE)) ## all others try(*) as it will fail in old R if (Rver > "1.3.0") { # no sense if very old R for (f in dir(dir, pattern='\\.R$', full.names=TRUE)) try(.source(f, envir = ESSR, keep.source = FALSE)) } ESSR } ## attach the ESSR environment to the search path .ess.ESSR.attach.env <- function(ESSR, Rver) { if (Rver >= "2.4.0") attach(ESSR) else if (Rver > "1.3.0") { # borrow from older library() e <- attach(NULL, name = "ESSR") .Internal(lib.fixup(ESSR, e)) } else { # if old R, use as in that old library(): .Internal(lib.fixup(ESSR, .GlobalEnv)) } } ## copy any ESSR R objects in the global environment into a newly created ESSR ## environment; then remove the original objects and attach ESSR .ess.collect.ESSR.objects <- function() { Rver <- .ess.ESSR.get.rver() ESSR <- .ess.ESSR.create.env(Rver) essr.nms <- grep('\\.(ess|ESS)', ls(.GlobalEnv, all.names = TRUE), value = TRUE) for (nm in essr.nms) { assign(nm, get(nm, pos = .GlobalEnv), envir = ESSR) } .ess.ESSR.attach.env(ESSR, Rver) rm(list = essr.nms, pos = .GlobalEnv) } ESS-24.01.1/etc/ESSR/R/completion.R000066400000000000000000000141571455642170100163520ustar00rootroot00000000000000## Do *NOT* use 1L -- it gives parse errors in historical versions of R ## Try a setup working in as old R as possible. ## ===> ## 1) do not use "_" in names! --- seems impossible for the Millenials .. ## 2) use our own simplified definition of '::' and ':::' ? ## if(!exists("local")) local <- function(expr, envir = environment()) { invisible(eval(expr, envir=envir)) } ##' Robust version of ##' utils:::.addFunctionInfo(c = c("recursive", "use.names")) # needed only for R <= 3.y.z local({ U <- asNamespace("utils"); fn <- ".addFunctionInfo" EX <- exists(fn, envir=U) if(EX && is.function(FN <- get(fn, envir=U))) { FN(c = c("recursive", "use.names")); ##dbg: cat("Calling utils:::",fn,"(c = ...)\n") } }) .ess_eval <- function(str, env = globalenv()) { ## don't remove; really need eval(parse( here!! tryCatch(eval(parse(text=str), envir = env), error=function(e) NULL) ## also works for special objects containing @:$ etc } .ess_nonull <- function(x, default = "") { if (is.null(x)) default else x } ## not needed for completion; called from (ess-r-xref--srcref *) in ../../../lisp/ess-r-xref.el .ess_srcref <- function(name, pkg) { if (!is.null(pkg) && requireNamespace(pkg)) { env <- asNamespace(pkg) } else { env <- globalenv() } fn <- .ess_eval(name, env) if (is.null(fn)) { objs <- utils::getAnywhere(name)$objs for (fn in objs) { if(is.function(fn)) break } } out <- "()\n" if (is.function(fn) && !is.null(utils::getSrcref(fn))) { file <- utils::getSrcFilename(fn, full.names = TRUE) if (file != "") { line <- .ess_nonull(utils::getSrcLocation(fn, "line" ), 1) col <- .ess_nonull(utils::getSrcLocation(fn, "column"), 1) out <- sprintf("(\"%s\" %d %d)\n", file, line, col - 1) } } cat(out) } .ess_fn_pkg <- function(fn_name) { objs <- utils::getAnywhere(fn_name) print(sub("(package|namespace):", "", objs$where)) } .ess_funargs <- function(funname) { if(.ess.Rversion > '2.14.1') { ## temporarily disable JIT compilation and errors comp <- compiler::enableJIT(0) op <- options(error=NULL) on.exit({ options(op); compiler::enableJIT(comp) }) } fun <- .ess_eval(funname) if(is.function(fun)) { special <- grepl('[:$@[]', funname) args <- if(!special){ fundef <- paste(funname, '.default',sep='') do.call('argsAnywhere', list(fundef)) } if(is.null(args)) args <- args(fun) if(is.null(args)) args <- do.call('argsAnywhere', list(funname)) fmls <- formals(args) fmls_names <- names(fmls) fmls <- gsub('\"', '\\\"', gsub("\\", "\\\\", as.character(fmls), fixed = TRUE), fixed=TRUE) args_alist <- sprintf("'(%s)", paste("(\"", fmls_names, "\" . \"", fmls, "\")", sep = '', collapse = ' ')) allargs <- if (special) fmls_names else tryCatch(gsub(' ?= ?', '', utils:::functionArgs(funname, ''), fixed = FALSE), error=function(e) NULL) allargs <- sprintf("'(\"%s\")", paste(allargs, collapse = '\" "')) envname <- if (is.primitive(fun)) "base" else environmentName(environment(fun)) if (envname == "R_GlobalEnv") envname <- "" cat(sprintf('(list \"%s\" %s %s)\n', envname, args_alist, allargs)) } } .ess_get_completions <- function(string, end, suffix = " = ") { oldopts <- utils::rc.options(funarg.suffix = suffix) on.exit(utils::rc.options(oldopts)) sett <- utils::rc.settings oldDots <- sett()[["dots"]] on.exit(sett(dots=oldDots), add=TRUE) sett(dots = FALSE) if(.ess.Rversion > '2.14.1') { comp <- compiler::enableJIT(0) op <- options(error=NULL) on.exit({ options(op); compiler::enableJIT(comp)}, add = TRUE) } utils:::.assignLinebuffer(string) utils:::.assignEnd(end) utils:::.guessTokenFromLine() utils:::.completeToken() c(get('token', envir=utils:::.CompletionEnv), utils:::.retrieveCompletions()) } .ess_arg_help <- function(arg, func) { op <- options(error=NULL) on.exit(options(op)) fguess <- if(is.null(func)) get('fguess', envir=utils:::.CompletionEnv) else func findArgHelp <- function(fun, arg){ file <- help(fun, try.all.packages=FALSE)[[1]] hlp <- utils:::.getHelpFile(file) id <- grep('arguments', tools:::RdTags(hlp), fixed=TRUE) if(length(id)){ arg_section <- hlp[[id[[1]]]] items <- grep('item', tools:::RdTags(arg_section), fixed=TRUE) ## cat('items:', items, fill=TRUE) if(length(items)){ arg_section <- arg_section[items] args <- unlist(lapply(arg_section, function(el) paste(unlist(el[[1]][[1]], TRUE, FALSE), collapse=''))) fits <- grep(arg, args, fixed=TRUE) ## cat('args', args, 'fits', fill=TRUE) if(length(fits)) paste(unlist(arg_section[[fits[1]]][[2]], TRUE, FALSE), collapse='') } } } funcs <- c(fguess, tryCatch(methods(fguess), warning= function(w) NULL, error = function(e) NULL)) if(length(funcs) > 1 && length(pos <- grep('default', funcs))) { funcs <- c(funcs[[pos[[1]]]], funcs[-pos[[1]]]) } i <- 1; found <- FALSE out <- 'No help found' while(i <= length(funcs) && is.null(out <- tryCatch(findArgHelp(funcs[[i]], arg), warning=function(w) {NULL}, error=function(e) {NULL}) )) i <- i + 1 cat('\n\n', as.character(out), '\n') } ESS-24.01.1/etc/ESSR/R/debug.R000066400000000000000000000177241455642170100152720ustar00rootroot00000000000000### BREAKPOINTS .ESSBP. <- new.env() ### DEBUG/UNDEBUG .ess_find_funcs <- function(env) { objs <- ls(envir = env, all.names = TRUE) if (length(objs) > 0) objs <- objs[sapply(objs, exists, envir = env, mode = 'function', inherits = FALSE)] objs } .ess_all_functions <- function(packages = c(), env = NULL) { if(is.null(env)) env <- parent.frame() empty <- emptyenv() coll <- list() for(p in packages){ ## package might not be attached try( { objNS <- .ess_find_funcs(asNamespace(p)) objPKG <- .ess_find_funcs(as.environment(paste0('package:', p))) objNS <- setdiff(objNS, objPKG) if(length(objPKG)) coll[[length(coll) + 1]] <- paste0(p, ':::', objNS) }, silent = TRUE) } while(!identical(empty, env)){ coll[[length(coll) + 1]] <- .ess_find_funcs(env) env <- parent.env(env) } grep('^\\.ess', unlist(coll, use.names = FALSE), invert = TRUE, value = TRUE) } .ess_dbg_flag_for_debuging <- function(fname){ all <- utils::getAnywhere(fname) if(length(all$obj) == 0){ msg <- sprintf("No functions names '%s' found", fname) } else { msg <- sprintf("Flagged '%s' for debugging", fname) tryCatch(lapply(all$obj, debug), error = function(e){ msg <- paste0("Error: ", e$message) }) } cat(msg) .ess_mpi_message(msg) } .ess_dbg_getTracedAndDebugged <- function() { packages <- base::.packages() tr_state <- tracingState(FALSE) on.exit(tracingState(tr_state)) generics <- methods::getGenerics() all_traced <- c() for(i in seq_along(generics)){ genf <- methods::getGeneric(generics[[i]], package=generics@package[[i]]) if(!is.null(genf)){ ## might happen !! v.2.13 menv <- methods::getMethodsForDispatch(genf) traced <- unlist(eapply(menv, is, 'traceable', all.names=TRUE)) if(length(traced) && any(traced)) all_traced <- c(paste(generics[[i]],':', names(traced)[traced],sep=''), all_traced) tfn <- getFunction(generics[[i]], mustFind=FALSE, where = .GlobalEnv) if(!is.null(tfn ) && is(tfn, 'traceable')) # if the default is traced, it does not appear in the menv :() all_traced <- c(generics[[i]], all_traced) } } debugged_pkg <- unlist(lapply(packages, function(pkgname){ ns <- asNamespace(pkgname) funcs <- .ess_find_funcs(ns) dbged <- funcs[unlist(lapply(funcs, function(f){ isdebugged(get(f, envir = ns, inherits = FALSE)) }))] if(length(dbged)) paste0(pkgname, ':::`', dbged, '`') })) env <- parent.frame() ## traced function don't appear here. Not really needed and would affect performance. all <- .ess_all_functions(packages = packages, env = env) which_deb <- lapply(all, function(nm){ ## if isdebugged is called with string it doess find tryCatch(isdebugged(get(nm, envir = env)), error = function(e) FALSE) ## try(eval(substitute(isdebugged(nm), list(nm = as.name(nm)))), silent = T) }) debugged <- all[which(unlist(which_deb, recursive=FALSE, use.names=FALSE))] unique(c(debugged_pkg, debugged, all_traced)) } .ess_dbg_UntraceOrUndebug <- function(name, env = parent.frame()) { tr_state <- tracingState(FALSE) on.exit(tracingState(tr_state)) if( grepl('::', name) ){ ## foo:::bar name eval(parse(text = sprintf('undebug(%s)', name))) }else{ ## name is a name of a function to be undebugged or has a form ## name:Class1#Class2#Class3 for traced methods name <- strsplit(name, ':', fixed = TRUE)[[1]] if( length(name)>1 ){ ## a method fun <- name[[1]] sig <- strsplit(paste(name[-1], collapse=''), '#', fixed=TRUE)[[1]] untrace(fun, signature = sig) }else{ ## function if( is(getFunction(name, where = parent.frame()), 'traceable') ) untrace(name) else if(grepl(":", name)) undebug(name) else undebug(get(name, envir = env)) }} } .ess_dbg_UndebugALL <- function(funcs) { tr_state <- tracingState(FALSE) on.exit(tracingState(tr_state)) env <- parent.frame() invisible(lapply(funcs, function( nm ) { ## ugly tryCatch, but there might be several names pointing to the ## same function, like foo:::bar and bar. An alternative would be ## to call .ess_dbg_getTracedAndDebugged each time but that might ## be ery slow try(.ess_dbg_UntraceOrUndebug(nm, env = env), TRUE) })) } ### WATCH .ess_watch_expressions <- list() .ess_watch_eval <- function() { env <- as.environment("ESSR") exps <- get('.ess_watch_expressions', envir = env) if(length(exps) == 0) { ## using old style so this can be parsed by R 1.9.1 (e.g): cat('\n# Watch list is empty!\n', '# a append new expression', '# i insert new expression', '# k kill', '# e edit the expression', '# r rename', '# n/p navigate', '# u/d,U move the expression up/down', '# q kill the buffer', sep="\n") } else { .parent_frame <- parent.frame() .essWEnames <- allNames(exps) len0p <- !nzchar(.essWEnames) .essWEnames[len0p] <- seq_along(len0p)[len0p] oo <- options(width = 10000) on.exit(options(oo)) for(i in seq_along(exps)) { cat('\n@---- ', .essWEnames[[i]], ' ', rep.int('-', max(0, 35 - nchar(.essWEnames[[i]]))), '-@\n', sep = '') expr <- gsub(" +", " ", paste(deparse(exps[[i]][[1]]), collapse = " ")) cat(paste('@---:', expr), ' \n', sep = '') tryCatch(print(eval(exps[[i]], envir = .parent_frame)), error = function(e) cat('Error:', e$message, '\n' ), warning = function(w) cat('warning: ', w$message, '\n' )) } } } .ess_watch_assign_expressions <- function(elist) { assign(".ess_watch_expressions", elist, envir = as.environment("ESSR")) } .ess_log_eval <- function(log_name) { env <- as.environment("ESSR") if(!exists(log_name, envir = env, inherits = FALSE)) assign(log_name, list(), envir = env) log <- get(log_name, envir = env, inherits = FALSE) .essWEnames <- allNames(.ess_watch_expressions) cur_log <- list() .parent_frame <- parent.frame() for(i in seq_along(.ess_watch_expressions)) { capture.output( { cur_log[[i]] <- tryCatch(eval(.ess_watch_expressions[[i]]), envir = .parent_frame, error = function(e) paste('Error:', e$message, '\n'), warning = function(w) paste('warning: ', w$message, '\n')) if(is.null(cur_log[i][[1]])) cur_log[i] <- list(NULL) }) } names(cur_log) <- .essWEnames assign(log_name, c(log, list(cur_log)), envir = env) invisible(NULL) } .ess_package_attached <- function(pack_name){ as.logical(match(paste0("package:", pack_name), search())) } ## magrittr debug_pipe .ess_pipe_browser <- function(x){ if(is.list(x)) evalq({ browser(skipCalls = 2) x }, envir = x) else if(is.environment(x)) ## enclos argumentn has no effect for unclear reason, need to hack eval(bquote({ x <- .(environment()) browser(skipCalls = 2) x }), envir = x) else { browser(skipCalls = 0) x } } ESS-24.01.1/etc/ESSR/R/misc.R000066400000000000000000000127721455642170100151350ustar00rootroot00000000000000.ess_weave <- function(command, file, encoding = NULL){ cmd_symb <- substitute(command) if (grepl('knit|purl', deparse(cmd_symb))) require(knitr) od <- getwd() on.exit(setwd(od)) setwd(dirname(file)) frame <- parent.frame() if (is.null(encoding)) eval(bquote(.(cmd_symb)(.(file))), envir = frame) else eval(bquote(.(cmd_symb)(.(file), encoding = .(encoding))), envir = frame) } .ess_knit <- function(file, output = NULL){ library(knitr) frame <- parent.frame() od <- getwd() on.exit(setwd(od)) setwd(dirname(file)) ## this bquote is really needed for data.table := operator to work correctly eval(bquote(knit(.(file), output = .(output))), envir = frame) } .ess_sweave <- function(file, output = NULL){ od <- getwd() frame <- parent.frame() on.exit(setwd(od)) setwd(dirname(file)) eval(bquote(Sweave(.(file), output = .(output))), envir = frame) } ## Users might find it useful. So don't prefix with .ess. .ess_htsummary <- function(x, hlength = 4, tlength = 4, digits = 3) { ## fixme: simplify and generalize snames <- c("mean", "sd", "min", "max", "nlev", "NAs") d <- " " num_sumr <- function(x){ c(f(mean(x, na.rm = TRUE)), f(sd(x, na.rm = TRUE)), f(min(x, na.rm = TRUE)), f(max(x, na.rm = TRUE)), d, f(sum(is.na(x), na.rm = TRUE))) } f <- function(x) format(x, digits = digits) if (is.data.frame(x) | is.matrix(x)) { if (nrow(x) <= tlength + hlength){ print(x) } else { if (is.matrix(x)) x <- data.frame(unclass(x)) ## conversion needed, to avoid problems with derived classes such ## as data.table h <- as.data.frame(head(x, hlength)) t <- as.data.frame(tail(x, tlength)) for (i in 1:ncol(x)) { h[[i]] <- f(h[[i]]) t[[i]] <- f(t[[i]]) } ## summaries sumr <- sapply(x, function(c){ if (is.logical(c)) ## treat logical as numeric; it's harmless c <- as.integer(c) if (is.numeric(c)) num_sumr(c) else if (is.factor(c)) c(d, d, d, d, nlevels(c), sum(is.na(c))) else rep.int(d, length(snames)) }) sumr <- as.data.frame(sumr) row.names(sumr) <- snames dots <- rep("...", ncol(x)) empty <- rep.int(" ", ncol(x)) lines <- rep.int(" ", ncol(x)) df <- rbind(h, ... = dots, t, `_____` = lines, sumr, ` ` = empty) print(df) } } else { cat("head(", hlength, "):\n", sep = "") print(head(x, hlength)) if (length(x) > tlength + hlength){ cat("\ntail(", tlength, "):\n", sep = "") print(tail(x, tlength)) } cat("_____\n") if (is.numeric(x) || is.logical(x)) print(structure(num_sumr(x), names = snames), quote = FALSE) else if (is.factor(x)){ cat("NAs: ", sum(is.na(x), na.rm = TRUE), "\n") cat("levels: \n") print(levels(x)) } } invisible(NULL) } .ess_vignettes <- function(all=FALSE) { vs <- unclass(browseVignettes(all = all)) vs <- vs[sapply(vs, length) > 0] mat2elist <- function(mat) { if (!is.null(dim(mat))){ apply(mat, 1, function(r) sprintf("(list \"%s\")", paste0(gsub("\"", "\\\\\"", as.vector(r[c("Title", "Dir", "PDF", "File", "R")])), collapse = "\" \""))) } } cat("(list \n", paste0(mapply(function(el, name) { sprintf("(list \"%s\" %s)", name, paste0(mat2elist(el), collapse = "\n")) }, vs, names(vs)), collapse = "\n"), ")\n") } .ess_Rd2txt <- function(rd) { fun <- tools::Rd2txt if (length(formals(fun)["stages"]))# newer R version fun(rd, stages = c("build", "install", "render")) else fun(rd) } ## Hacked help.start() to use with ess-rutils.el .ess_help_start <- function(update=FALSE, remote=NULL) { home <- if (is.null(remote)) { port <- tools::startDynamicHelp(NA) if (port > 0L) { if (update) make.packages.html(temp=TRUE) paste0("http://127.0.0.1:", port) } else stop(".ess_help_start() requires the HTTP server to be running", call.=FALSE) } else remote paste0(home, "/doc/html/index.html") } .ess.rdired <- function() { cat('\n') objs <- ls(envir = .GlobalEnv) if (length(objs)==0) { cat("No objects to view!\n") return(invisible(NULL)) } names(objs) <- objs objs <- lapply(objs, get, envir = .GlobalEnv) mode <- sapply(objs, data.class) length <- sapply(objs, length) size <- sapply(objs, function(obj) format(object.size(obj))) d <- data.frame(mode, length, size) var.names <- row.names(d) ## If any names contain spaces, we need to quote around them. quotes <- rep('', length(var.names)) spaces <- grep(' ', var.names) if (any(spaces)) quotes[spaces] <- '\"' var.names <- paste(quotes, var.names, quotes, sep = '') row.names(d) <- paste(' ', var.names, sep = '') print(d) } ESS-24.01.1/etc/ESSR/R/mpi.R000066400000000000000000000012451455642170100147600ustar00rootroot00000000000000## simple Message Parsing Interface .ess_mpi_send <- function(head, ...){ dots <- lapply(list(...), function(el) { if (is.null(el)) "nil" else if (is.logical(el)) {if (el) "t" else "nil"} else as.character(el) }) payload <- paste(dots, collapse = "") cat(sprintf("_%s%s\\", head, payload)) } .ess_mpi_message <- function(msg){ .ess_mpi_send("message", msg) } .ess_mpi_y_or_n <- function(prompt, callback = NULL){ .ess_mpi_send("y-or-n", prompt, callback) } .ess_mpi_eval <- function(expr, callback = NULL){ .ess_mpi_send("eval", expr, callback) } .ess_mpi_error <- function(msg) { .ess_mpi_send("error", msg) } ESS-24.01.1/etc/ESSR/R/ns-eval.R000066400000000000000000000413401455642170100155400ustar00rootroot00000000000000## NOTE ON S3 METHODS: New S3 methods are not automatically registered. You can ## register them manually after you have inserted method_name.my_class into your ## package environment using ess-developer, like follows: ## ## registerS3method("method_name", "my_class", my_package:::method_name.my_class) ## ## If an S3 methods already exists in a package, ESS-developer will do the right ## thing. ## evaluate the STRING by saving into a file and calling .ess.ns_source .ess.ns_eval <- function(string, visibly, output, package, file = tempfile("ESSDev"), verbose = FALSE, fallback_env = NULL, local_env = parent.frame()) { cat(string, file = file) on.exit(.ess.file.remove(file)) .ess.ns_source(file, visibly, output, package = package, verbose = verbose, fake.source = TRUE, fallback_env = fallback_env, local_env = local_env) } ##' Source FILE into an environment. After having a look at each new object in ##' the environment, decide what to do with it. Handles plain objects, ##' functions, existing S3 methods, S4 classes and methods. ##' @param fallback_env environment to assign objects which don't exist in the ##' package namespace .ess.ns_source <- function(file, visibly, output, expr, package = "", verbose = FALSE, fake.source = FALSE, fallback_env = NULL, local_env = NULL) { pname <- paste("package:", package, sep = "") envpkg <- tryCatch(as.environment(pname), error = function(cond) NULL) if (is.null(envpkg)) { if (suppressWarnings(require(package, quietly = TRUE, character.only = TRUE))) { envpkg <- tryCatch(as.environment(pname), error = function(cond) NULL) } else { ## no such package; source in current (local) user environment return(.ess.source(file, visibly = visibly, output = output, local = local_env, fake.source = fake.source)) } } envns <- tryCatch(asNamespace(package), error = function(cond) NULL) if (is.null(envns)) stop(gettextf("Can't find a namespace environment corresponding to package name '%s\"", package), domain = NA) ## Here we know that both envns and envpkg exists and are environments if (is.null(fallback_env)) fallback_env <- .ess.ns_insert_essenv(envns) ## Get all Imports envs where we propagate objects pkgEnvNames <- Filter(.ess.is_package, search()) packages <- lapply(pkgEnvNames, function(envName) substring(envName, 9)) importsEnvs <- lapply(packages, function(pkgName) parent.env(asNamespace(pkgName))) ## Evaluate the FILE into new ENV env <- .ess.ns_evalSource(file, visibly, output, substitute(expr), package, fake.source) envPackage <- getPackageName(env, FALSE) if (nzchar(envPackage) && envPackage != package) warning(gettextf("Supplied package, %s, differs from package inferred from source, %s", sQuote(package), sQuote(envPackage)), domain = NA) ## Get all sourced objects, methods and classes allObjects <- objects(envir = env, all.names = TRUE) allObjects <- allObjects[!(allObjects %in% c(".cacheOnAssign", ".packageName"))] MetaPattern <- methods:::.TableMetaPattern() ClassPattern <- methods:::.ClassMetaPattern() allPlainObjects <- allObjects[!(grepl(MetaPattern, allObjects) | grepl(ClassPattern, allObjects))] allMethodTables <- allObjects[grepl(MetaPattern, allObjects)] allClassDefs <- allObjects[grepl(ClassPattern, allObjects)] ## PLAIN OBJECTS and FUNCTIONS: funcNs <- funcPkg <- newFunc <- newNs <- newObjects <- newPkg <- objectsNs <- objectsPkg <- character() dependentPkgs <- list() for (this in allPlainObjects) { thisEnv <- get(this, envir = env) thisNs <- NULL ## NS if (exists(this, envir = envns, inherits = FALSE)){ thisNs <- get(this, envir = envns) if(is.function(thisNs) || is.function(thisEnv)){ if(is.function(thisNs) && is.function(thisEnv)){ if(.ess.differs(thisEnv, thisNs)){ environment(thisEnv) <- environment(thisNs) .ess.assign(this, thisEnv, envns) funcNs <- c(funcNs, this) if(exists(".__S3MethodsTable__.", envir = envns, inherits = FALSE)){ S3_table <- get(".__S3MethodsTable__.", envir = envns) if(exists(this, envir = S3_table, inherits = FALSE)) .ess.assign(this, thisEnv, S3_table) } } }else{ newNs <- c(newNs, this) } }else{ if(!identical(thisEnv, thisNs)){ .ess.assign(this, thisEnv, envns) objectsNs <- c(objectsNs, this) } } }else{ newNs <- c(newNs, this) } ## PKG if (exists(this, envir = envpkg, inherits = FALSE)){ thisPkg <- get(this, envir = envpkg) if(is.function(thisPkg) || is.function(thisEnv)){ if(is.function(thisPkg) && is.function(thisEnv)){ if(.ess.differs(thisPkg, thisEnv)){ environment(thisEnv) <- environment(thisPkg) .ess.assign(this, thisEnv, envpkg) funcPkg <- c(funcPkg, this) } }else{ newPkg <- c(newPkg, this) } }else{ if(!identical(thisPkg, thisEnv)){ .ess.assign(this, thisEnv, envpkg) objectsPkg <- c(objectsPkg, this) } } }else{ newPkg <- c(newPkg, this) } if (!is.null(thisNs)) { isDependent <- .ess.ns_propagate(thisEnv, this, importsEnvs) newDeps <- stats::setNames(list(packages[isDependent]), this) dependentPkgs <- c(dependentPkgs, newDeps) } } ## deal with new plain objects and functions for (this in intersect(newPkg, newNs)) { thisEnv <- get(this, envir = env, inherits = FALSE) if (exists(this, envir = fallback_env, inherits = FALSE)){ thisGl <- get(this, envir = fallback_env) if (.ess.differs(thisEnv, thisGl)) { if (is.function(thisEnv)) { environment(thisEnv) <- envns newFunc <- c(newFunc, this) } else { newObjects <- c(newObjects, this) } .ess.assign(this, thisEnv, fallback_env) if (.is.essenv(fallback_env)) .ess.assign(this, thisEnv, .GlobalEnv) } } else { if (is.function(thisEnv)) { environment(thisEnv) <- envns newFunc <- c(newFunc, this) } else { newObjects <- c(newObjects, this) } .ess.assign(this, thisEnv, fallback_env) if (.is.essenv(fallback_env)) .ess.assign(this, thisEnv, .GlobalEnv) } } if(length(funcNs)) objectsNs <- c(objectsNs, sprintf("FUN[%s]", paste(funcNs, collapse = ", "))) if(length(funcPkg)) objectsPkg <- c(objectsPkg, sprintf("FUN[%s]", paste(funcPkg, collapse = ", "))) if(length(newFunc)) newObjects <- c(newObjects, sprintf("FUN[%s]", paste(newFunc, collapse = ", "))) ## CLASSES classesPkg <- classesNs <- newClasses <- character() for(this in allClassDefs){ newPkg <- newNs <- FALSE thisEnv <- get(this, envir = env) if(exists(this, envir = envpkg, inherits = FALSE)){ if(!.ess.identicalClass(thisEnv, get(this, envir = envpkg))){ .ess.assign(this, thisEnv, envir = envpkg) classesPkg <- c(classesPkg, this) } }else{ newPkg <- TRUE } if(exists(this, envir = envns, inherits = FALSE)){ if(!.ess.identicalClass(thisEnv, get(this, envir = envns))){ .ess.assign(this, thisEnv, envir = envns) classesNs <- c(classesNs, this) } }else{ newNs <- TRUE } if(newNs && newPkg){ if(exists(this, envir = fallback_env, inherits = FALSE)){ if(!.ess.identicalClass(thisEnv, get(this, envir = fallback_env))){ .ess.assign(this, thisEnv, envir = fallback_env) newClasses <- c(newClasses, this) } }else{ .ess.assign(this, thisEnv, envir = fallback_env) newClasses <- c(newClasses, this) } } } if(length(classesPkg)) objectsPkg <- gettextf("CLS[%s]", sub(ClassPattern, "", paste(classesPkg, collapse = ", "))) if(length(classesNs)) objectsNs <- gettextf("CLS[%s]", sub(ClassPattern, "", paste(classesNs, collapse = ", "))) if(length(newClasses)) newObjects <- gettextf("CLS[%s]", sub(ClassPattern, "", paste(newClasses, collapse = ", "))) ## METHODS: ## Method internals: For efficiency reasons setMethod() caches ## method definition into a global table which you can get with ## 'getMethodsForDispatch' function, and when a method is dispatched that ## table is used. When ess-developer is used to source method definitions the ## two copies of the functions are identical up to the environment. The ## environment of the cached object has namespace:foo as it's parent but the ## environment of the object in local table is precisely namespace:foo. This ## does not cause any difference in evaluation. methodNames <- allMethodTables methods <- sub(methods:::.TableMetaPrefix(), "", methodNames) methods <- sub(":.*", "", methods) methodsNs <- newMethods <- character() for (i in seq_along(methods)){ table <- methodNames[[i]] tableEnv <- get(table, envir = env) if(exists(table, envir = envns, inherits = FALSE)){ inserted <- .ess.ns_insertMethods(tableEnv, get(table, envir = envns), envns) if(length(inserted)) methodsNs <- c(methodsNs, gettextf("%s{%s}", methods[[i]], paste(inserted, collapse = ", "))) }else if(exists(table, envir = fallback_env, inherits = FALSE)){ inserted <- .ess.ns_insertMethods(tableEnv, get(table, envir = fallback_env), envns) if(length(inserted)) newMethods <- c(newMethods, gettextf("%s{%s}", methods[[i]], paste(inserted, collapse = ", "))) }else{ .ess.assign(table, tableEnv, envir = fallback_env) newMethods <- c(newMethods, gettextf("%s{%s}", methods[[i]], paste(objects(envir = tableEnv, all.names = T), collapse = ", "))) } } if(length(methodsNs)) objectsNs <- c(objectsNs, gettextf("METH[%s]", paste(methodsNs, collapse = ", "))) if(length(newMethods)) newObjects <- c(newObjects, gettextf("METH[%s]", paste(newMethods, collapse = ", "))) if (verbose) { msgs <- unlist(list( if(length(objectsPkg)) sprintf("PKG: %s", paste(objectsPkg, collapse = ", ")), if(length(objectsNs)) sprintf("NS: %s", paste(objectsNs, collapse = ", ")), if(length(dependentPkgs)) .ess.ns_format_deps(dependentPkgs), if(length(newObjects)) { env_name <- .ess.ns_env_name(fallback_env) sprintf("%s: %s", env_name, paste(newObjects, collapse = ", ")) })) if(length(msgs)) .ess_mpi_message(paste(msgs, collapse = " ")) } invisible(env) } .ess.ns_insertMethods <- function(tableEnv, tablePkg, envns) { inserted <- character() for(m in ls(envir = tableEnv, all.names = T)){ if(exists(m, envir = tablePkg, inherits = FALSE)){ thisEnv <- get(m, envir = tableEnv) thisPkg <- get(m, envir = tablePkg) if(is(thisEnv, "MethodDefinition") && is(thisPkg, "MethodDefinition") && .ess.differs(thisEnv@.Data, thisPkg@.Data)){ environment(thisEnv@.Data) <- envns ## environment of cached method in getMethodsForDispatch table is still env ## not a problem as such, but might confuse users .ess.assign(m, thisEnv, tablePkg) inserted <- c(inserted, m) }}} inserted } ## our version of R's evalSource .ess.ns_evalSource <- function(file, visibly, output, expr, package = "", fake.source = FALSE) { envns <- tryCatch(asNamespace(package), error = function(cond) NULL) if(is.null(envns)) stop(gettextf("Package \"%s\" is not attached and no namespace found for it", package), domain = NA) env <- new.env(parent = envns) env[[".packageName"]] <- package methods:::setCacheOnAssign(env, TRUE) if (missing(file)) eval(expr, envir = env) else if (is(file, "character")) for (f in file) { .ess.source(f, local = env, visibly = visibly, output = output, keep.source = TRUE, max.deparse.length = 300, fake.source = fake.source, message.prefix = sprintf("[%s] ", package)) } else stop(gettextf("Invalid file argument: got an object of class \"%s\"", class(file)[[1]]), domain = NA) env } .ess.assign <- function(x, value, envir) { ## Cannot add bindings to locked environments exists <- exists(x, envir = envir, inherits = FALSE) if (exists && bindingIsLocked(x, envir)) { unlockBinding(x, envir) assign(x, value, envir = envir, inherits = FALSE) op <- options(warn = -1) on.exit(options(op)) lockBinding(x, envir) } else if (exists || !environmentIsLocked(envir)) { assign(x, value, envir = envir, inherits = FALSE) } else { warning(sprintf("Cannot assign `%s` in locked environment", x), call. = FALSE) } invisible(NULL) } .ess.identicalClass <- function(cls1, cls2, printInfo = FALSE) { slots1 <- slotNames(class(cls1)) slots2 <- slotNames(class(cls2)) if(identical(slots1, slots2)){ vK <- grep("versionKey", slots1) if(length(vK)) slots1 <- slots2 <- slots1[-vK] out <- sapply(slots1, function(nm) identical(slot(cls1, nm), slot(cls2, nm))) if(printInfo) print(out) all(out) } } .ess.differs <- function(f1, f2) { if (is.function(f1) && is.function(f2)){ !(identical(body(f1), body(f2)) && identical(args(f1), args(f2))) }else !identical(f1, f2) } .ess.is_package <- function(envName) { isPkg <- identical(substring(envName, 0, 8), "package:") isPkg && (envName != "package:base") } .ess.ns_propagate <- function(obj, name, importsEnvs) { containsObj <- vapply(importsEnvs, logical(1), FUN = function(envs) { name %in% names(envs) }) lapply(importsEnvs[containsObj], .ess.assign, x = name, value = obj) containsObj } .ess.ns_format_deps <- function(dependentPkgs) { pkgs <- unique(unlist(dependentPkgs, use.names = FALSE)) lapply(pkgs, function(pkg) { isDep <- vapply(dependentPkgs, function(deps) pkg %in% deps, logical(1)) pkgDependentObjs <- names(dependentPkgs[isDep]) sprintf("DEP:%s [%s] ", pkg, paste(pkgDependentObjs, collapse = ", ")) }) } .ess.ns_env_name <- function(env) { name <- environmentName(env) name <- if (name == "") "Local" else if (grepl("^essenv:", name)) "NEW" else name name } .ess.ns_insert_essenv <- function(nsenv) { if (is.character(nsenv)) nsenv <- asNamespace(nsenv) stopifnot(isNamespace(nsenv)) if (identical(nsenv, .BaseNamespaceEnv)) return(.GlobalEnv) essenv_name <- sprintf("essenv:%s", environmentName(nsenv)) nsenv_parent <- parent.env(nsenv) if (environmentName(nsenv_parent) == essenv_name) { return(nsenv_parent) } essenv <- new.env(parent = nsenv_parent) essenv[[".__ESSENV__."]] <- TRUE attr(essenv, "name") <- essenv_name nssym <- ".__NAMESPACE__." nssym_val <- get(nssym, envir = nsenv, inherits = FALSE) unlockBinding(nssym, nsenv) nsenv[[nssym]] <- NULL on.exit({ nsenv[[nssym]] <- nssym_val lockBinding(nssym, nsenv) }) parent.env(nsenv) <- essenv essenv } .is.essenv <- function(env) { exists(".__ESSENV__.", envir = env, inherits = FALSE) } ESS-24.01.1/etc/ESSR/R/pkg.R000066400000000000000000000012321455642170100147500ustar00rootroot00000000000000 .ess_keep <- function(.x, .f, ...) { is_true <- vapply(.x, .f, logical(1), ...) .x[is_true] } .ess_devtools_functions <- function() { if (!requireNamespace("devtools")) { .ess_mpi_error("devtools is not installed") stop("internal error") } devtools_env <- asNamespace("devtools") exports <- getNamespaceExports("devtools") funs_exported <- as.list(devtools_env)[exports] is_first_arg <- function(f, arg) { args <- names(formals(f)) length(args) && args[[1]] == arg } funs_pkg <- .ess_keep(funs_exported, is.function) funs_pkg <- .ess_keep(funs_pkg, is_first_arg, "pkg") funs_names <- sort(names(funs_pkg)) funs_names } ESS-24.01.1/etc/Makefile000066400000000000000000000027131455642170100145340ustar00rootroot00000000000000### Makefile - for scripts and icons (./etc) of ESS distribution. ### ## Before making changes here, please take a look at Makeconf include ../Makeconf #ETCFILES = $(wildcard BACKBUG[S5].BAT backbug[s5] *.S sas-keys.*) #ETCFILES = ESSR.R ess-developer.R SVN-REVISION *.S sas-keys.* ess-sas-sh-command # ETCFILES_1 = *.S sas-keys.* ess-sas-sh-command *.jl ETCFILES_1 = ess-sas-sh-command *.jl isRELEASE=$(shell test -f .IS.RELEASE && echo 'yes') ifeq ($(isRELEASE),yes) ETCFILES = .IS.RELEASE git-ref $(ETCFILES_1) else ETCFILES = $(ETCFILES_1) endif #ICONS = $(wildcard icons/*.xpm) ICONS = icons/*.xpm ESSR_UTIL_FILES = ESSR/LOADREMOTE ESSR_CODE_FILES = ESSR/R/*.R ESSR/R/.*.R all: show-etc: @echo $(ETCFILES) ls -l $(ETCFILES) install : $(INSTALLDIR) $(ETCDIR)/icons $(INSTALLDIR) $(ETCDIR)/ESSR/R $(INSTALL) $(ETCFILES) $(ETCDIR) $(INSTALL) $(ICONS) $(ETCDIR)/icons $(INSTALL) $(ESSR_UTIL_FILES) $(ETCDIR)/ESSR $(INSTALL) $(ESSR_CODE_FILES) $(ETCDIR)/ESSR/R chmod +x $(ETCDIR)/ess-sas-sh-command uninstall : -cd $(ETCDIR) && $(UNINSTALL) $(ETCFILES) -cd $(ETCDIR) && $(UNINSTALL) $(ICONS) -cd $(ETCDIR) && $(UNINSTALL) $(ESSR_UTIL_FILES) -cd $(ETCDIR) && $(UNINSTALL) $(ESSR_CODE_FILES) ## 'clean' shall remove *exactly* those things that are *not* in version control clean distclean: rm -rf SVN-REVISION ## 'distclean' removes also things in VC (svn, when they are remade by "make"): # distclean: clean # rm -rf ESSR_*.tar.gz ESS-24.01.1/etc/ess-julia.jl000066400000000000000000000060421455642170100153160ustar00rootroot00000000000000module ESS # These methods have been deprecated / moved macro current_module() return VERSION >= v"0.7-" ? :(@__MODULE__) : :(current_module()) end parse = VERSION >= v"0.7-" ? Base.Meta.parse : Base.parse function_module = VERSION >= v"0.7-" ? Base.parentmodule : Base.function_module function all_help_topics() ## There are not clear topics anymore. Approximate those with a very general ## apropos(" ") Base.Docs.apropos(" ") end function help(topic::AbstractString) if (VERSION >= v"1.0-") Core.eval(parentmodule(ESS), parse("@doc $topic")) elseif (VERSION >= v"0.4-") Core.eval(@current_module(), parse("@doc $topic")) else Base.Help.help(topic) end end ## modified version of function show(io::IO, m::Method) function fun_args(m::Method) tv, decls, file, line = Base.arg_decl_parts(m) io = VERSION >= v"0.7-" ? Base.stdout : STDOUT::IO # STDOUT is no longer in 1.0 if !isempty(tv) Base.show_delim_array(io, tv, '{', ',', '}', false) end print(io, "(") join(io, [escape_string(isempty(d[2]) ? d[1] : d[1]*"::"*d[2]) for d in decls], ",", ",") Base.print(io, ")") end ## modified versionof show(io::IO, mt::MethodTable) function fun_args(f::Function) mt = Base.MethodList(methods(f).mt) mod = function_module(f) # Base.function_module deprecated in 0.7 if mod == Main mod = "nil" end print("(list \"$mod\" nil '(") for d in mt print("\"") ## method fun_args(d) print("\" ") end print("))") end function fun_args(s::AbstractString) try mod = VERSION >= v"1.0-" ? parentmodule(ESS) : @current_module() m = Core.eval(mod, parse(s)) if ! isa(m, String) fun_args(m) end catch print("(list nil nil nil)") end end function fun_args(t::DataType) print("(list nil nil '(") for d = fieldnames(t) print("\"$d\" ") end print("))") end ### OBJECT COMPLETION # Must print an output of the form: # # Cache Module # Write Module # add Function # free Function function components(m::Module) for v in sort(names(m, all=true, imported=true)) s = string(v) if !startswith(s, "#") && isdefined(m,v) println(rpad(s, 30), summary(Core.eval(m,v))) end end end function components(t::DataType) for v in sort(fieldnames(t)) println(rpad(string(v), 30), "field") end end function components(v) t = typeof(v) if isa(t, DataType) return components(t) end end ### MISC function main_modules(m::Module) for nm in names(m) if isdefined(m, nm) mod = Core.eval(m, nm) if isa(mod, Module) print("\"$nm\" ") end end end end if VERSION >= v"0.7-" main_modules() = main_modules(Base.parentmodule(@current_module())) else main_modules() = main_modules(@current_module()) end end ESS-24.01.1/etc/ess-sas-sh-command000077500000000000000000000043371455642170100164300ustar00rootroot00000000000000#!/bin/sh ### (C) 1997, Richard M. Heiberger. ### This file is part of ESS. ## This file is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2, or (at your option) ## any later version. ## This file 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. ## A copy of the GNU General Public License is available at ## https://www.r-project.org/Licenses/ # For executing SAS, and running it in the proper manner for ESS # (feeding output back into appropriate ESS buffers). #echo $0 $@ #sas $1 2>$2 $3 set -x stdout=$1 stderr=$2 shift 2 set +x echo sas \$stdout 2\>$stderr $@ sas $stdout 2>$stderr $@ ## From the SAS online tech support: ## ## Redirecting the SAS Log and Output under UNIX. ## ## There are several ways of redirecting the SAS Log and Output under ## UNIX. ## ## To redirect the SAS Log, follow one of these steps: ## ## 1. ## In the source code, place the following line: ## ## proc printto log=stdout; ## ## to make a duplicate copy of the log in a file in addition ## to redirecting it to stdout, use this command to invoke ## SAS: ## ## sas -altlog doit.log doit.sas ## ## 2.Execute SAS in the background and use the UNIX 'tail' command ## to copy lines to stdout as they are added to the log. Use the ## command: ## ## sas doit.sas &; tail -f doit.log ## ## To redirect the SAS Log and Output under the Korn shell, use the ## following command: ## ## sas -stdio < doit.sas > doit.lst 2> doit.log ## ## To redirect the SAS Log and Output under the C-Shell, use the ## following command: ## ## (sas -stdio < doit.sas > doit.lst) >& doit.log ## From WWW.SAS.COM: ## How can I make SAS in batch mode behave like interactive SAS, ## continue running my SAS job, and not enter syntax check mode when ## it encounters an error? ## ## You can specify the NOSYNTAXCHECK option when you invoke your SAS ## program. ESS-24.01.1/etc/icons/000077500000000000000000000000001455642170100142045ustar00rootroot00000000000000ESS-24.01.1/etc/icons/README000066400000000000000000000022421455642170100150640ustar00rootroot00000000000000 Creating pixmaps: * spluslogo.xpm was dontated by David Smith at Insightful. * Other icons were created by SJE, using mostly `kiconedit' and hand-editing. * Transparency Need to add backgrounToolBarColor for XEmacs to show okay. e.g. /usr/share/xemacs-21.4.12/etc/toolbar/folder-cap-up.xpm has header: "X c Gray75 s backgroundToolBarColor", whereas I have set "c None" to indicate the background pixel; this line seems to work for both toolbars: ". c None s backgroundToolBarColor", * splus_letters_small.xpm 2010-05-18 & -21: SJE made this new Splus icon from the splus_letters_large.xpm (then image001.png from Louis Bajuk-Yorgan @tibco.com) file that Rich provided. I had to move the cross over to the left by one pixel, to then allow the image to be cropped to 48x48 (cropping performed in gimp). kiconedit was then used to rescale the icon to 24x24. Finally, background transparency added manually to the file, as noted above. 2010-05-21: updated file based on new image from TIBCO. Original 51x38 cropped to 50x38 in xv, then shrunk to 25x19 in kiconedit. Transparency added, and removed a lot of the extra white pixels into background colours manually in kiconedit. ESS-24.01.1/etc/icons/rbuffer.xpm000066400000000000000000000014241455642170100163660ustar00rootroot00000000000000/* XPM */ static char *rbuffer[]={ "24 24 3 1", ". c None s backgroundToolBarColor", "a c #000000", "# c #1532ed", "........................", "...............#........", "...............##.......", ".....#############......", ".....##############.....", ".....#############......", "...............##.......", "...............#........", "........................", "........................", "........................", "...aaaaaaaaaaaaaaaaaa...", "........................", "........................", "...aaaaaaaaaaaaaaaaaa...", "........................", "........................", "...aaaaaaaaaaaaaaaaaa...", "........................", "........................", "...aaaaaaaaaaaaaaaaaa...", "........................", "........................", "...aaaaaaaaaaaaaaaaaa..."}; ESS-24.01.1/etc/icons/rfunction.xpm000066400000000000000000000017701455642170100167460ustar00rootroot00000000000000/* XPM */ static char *rfunction[]={ "24 24 18 1", "B c #000000", "k c #181818", "Q c #1f1f1f", "z c #232323", "L c #313131", "Z c #3c3c3c", "O c #404040", "a c #5e5e5e", "W c #676767", "U c #757575", "N c #848484", "P c #969696", "0 c #a0a0a0", ". c None s backgroundToolBarColor", "G c #b9b9b9", "I c #c6c6c6", "T c #d5d5d5", "# c #1532ed", "........................", "...............#........", "...............##.......", ".....#############......", ".....##############.....", ".....#############......", "...............##.......", "...............#........", "........................", "........................", "........................", "..............az..zU....", "....ILBBz...GkP....aO...", "....zU......BG......LP..", "....BG.....UO.......0z..", "..BBBBBBP..zP.......GB..", "....BG.....BG........BI.", "....BG.....BG........BI.", "....BG.....LP.......GB..", "....BG.....NO.......PL..", "....BG......Q0......z0..", "....BG......TQU0..0ZW...", "..............NL..Z0....", "........................"}; ESS-24.01.1/etc/icons/rline.xpm000066400000000000000000000014221455642170100160420ustar00rootroot00000000000000/* XPM */ static char *rline[]={ "24 24 3 1", ". c None s backgroundToolBarColor", "a c #000000", "# c #1532ed", "........................", "...............#........", "...............##.......", ".....#############......", ".....##############.....", ".....#############......", "...............##.......", "...............#........", "........................", "........................", "........................", "........................", "........................", "........................", "........................", "........................", "........................", "...aaaaaaaaaaaaaaaaaa...", "........................", "........................", "........................", "........................", "........................", "........................"}; ESS-24.01.1/etc/icons/rregion.xpm000066400000000000000000000014241455642170100164000ustar00rootroot00000000000000/* XPM */ static char *rregion[]={ "24 24 3 1", ". c None s backgroundToolBarColor", "a c #000000", "# c #1532ed", "........................", "...............#........", "...............##.......", ".....#############......", ".....##############.....", ".....#############......", "...............##.......", "...............#........", "........................", "........................", "........................", "........................", "........................", "........................", "...aaaaaaaaaaaaaaaaaa...", "........................", "........................", "...aaaaaaaaaaaaaaaaaa...", "........................", "........................", "...aaaaaaaaaaaaaaaaaa...", "........................", "........................", "........................"}; ESS-24.01.1/etc/icons/splus_letter_small.xpm000066400000000000000000000066711455642170100206610ustar00rootroot00000000000000/* XPM */ static char *dummy[]={ "25 19 151 2", "Qt c None s backgroundToolBarColor", "#M c #044b83", "#R c #044c86", "#t c #044c87", "ae c #044d87", "an c #044e7f", ".o c #044e81", "#l c #044e8d", "ak c #044f84", ".B c #044f88", "#m c #044f8e", "am c #045188", ".j c #04518b", ".O c #045191", "#6 c #04528f", "#O c #045388", ".k c #04538c", "#U c #04538e", "#Y c #045392", ".l c #045489", "## c #04548c", "#i c #045490", "#v c #045492", "#. c #04558e", "#C c #045593", "#k c #04568d", "#B c #045695", "#G c #045698", ".Y c #045795", ".R c #045890", "#j c #04598f", ".4 c #045995", "aj c #054e7b", "al c #054e89", "#h c #054e8d", "#S c #055188", "#V c #05518d", ".m c #055282", ".K c #055284", ".5 c #055583", ".t c #055791", "#u c #055894", ".n c #064e86", "#s c #074d76", ".p c #074e83", "a. c #074f89", "#a c #074f8a", "af c #075389", "#9 c #07548e", ".A c #075592", ".F c #075594", "#1 c #075a99", ".c c #094d79", ".9 c #094f89", ".J c #095681", "#A c #0b568d", ".s c #0c4f85", "#5 c #0c5188", "#w c #0d5486", ".b c #0e4e7d", ".N c #105287", ".X c #105685", "#H c #115789", "#Z c #13508a", "#2 c #135287", "#F c #195c8a", ".i c #1a5c8b", "#8 c #1b5684", "ai c #1b5a81", "ad c #1c5d87", "#P c #1d5c8c", "#r c #1d5f8a", "#N c #1f5b7d", "ao c #1f5c85", "#0 c #205a86", "#n c #206292", ".u c #216794", ".d c #245b81", ".G c #256390", ".3 c #265f85", "a# c #266287", "#x c #296286", "#b c #2a5f96", "#g c #2b6395", ".a c #2c658f", ".Q c #307195", ".E c #326897", ".S c #356f98", ".Z c #35789b", "ag c #396c94", "#I c #3a6a78", "#z c #3f7497", ".1 c #3f7c9e", "#J c #427585", "aa c #42768f", "#X c #447ca1", ".C c #457b9a", ".z c #457ba8", "ac c #48778f", ".q c #4e86b0", "#7 c #4f86b5", ".6 c #50829b", "#q c #538db5", "#D c #538eb3", ".e c #547f91", "ab c #5487a1", "#T c #58859c", "ah c #5983a7", "#c c #5a7d99", ".2 c #5b809c", ".P c #5d94bb", "#K c #6c91a0", "#4 c #6c99ba", "#L c #6c9cb7", "#o c #7097a7", "ap c #739eb3", ".v c #73a7c0", ".0 c #7cacc3", "#y c #7faac6", ".# c #82a0a8", "#Q c #84aec8", ".I c #86a8bd", ".L c #89b3cd", "#d c #8aa7b6", "as c #8db2cc", ".y c #8db9cd", ".h c #8eb5c9", ".8 c #8eb9d3", "#W c #8fb2c9", "at c #91b7c8", "#3 c #94b4cb", "ar c #95b7cb", ".T c #979798", ".U c #99999a", "#f c #99b9cd", ".g c #9b9b9b", ".V c #9c9c9c", ".r c #9cc2d4", ".w c #a7c8d0", ".x c #a9c8d1", "#p c #a9cbda", ".f c #abc5cd", "#E c #abcad6", "aq c #b1d0e0", "au c #b3d2e2", ".7 c #b8cfd6", "#e c #baced7", ".W c #d4e0e4", ".H c #d7e7ed", ".M c #dae6ef", ".D c #eef8f8", "QtQtQtQt.#.a.b.c.d.e.fQtQtQtQtQtQtQtQt.g.gQtQtQtQt", "QtQt.h.i.j.k.l.m.n.o.p.qQtQtQtQtQtQtQt.g.gQtQtQtQt", "Qt.r.s.t.u.v.w.x.y.z.A.B.CQtQtQtQtQtQt.g.gQtQtQtQt", ".D.E.F.G.HQtQtQtQtQt.I.J.K.LQtQtQtQtQt.g.gQtQtQtQt", ".M.N.O.PQtQtQtQtQtQtQt.Q.R.SQt.g.T.U.g.g.g.V.V.g.g", ".W.X.Y.ZQtQtQtQtQtQtQt.0.1.2Qt.g.g.g.g.g.g.g.g.g.g", "Qt.3.4.5.6.7QtQtQtQtQtQtQtQtQtQtQtQtQt.g.gQtQtQtQt", "Qt.8.9#.###a#b#c#d#eQtQtQtQtQtQtQtQtQt.g.gQtQtQtQt", "QtQt#f#g#h#i#j#k#l#m#n#oQtQtQtQtQtQtQt.g.gQtQtQtQt", "QtQtQtQt#p#q#r#s#t#u#v#w#xQtQtQtQtQtQt.g.gQtQtQtQt", "QtQtQtQtQtQtQtQt#y#z#A#B#C#DQtQtQtQtQtQtQtQtQtQtQt", "QtQtQtQtQtQtQtQtQtQt#E#F#G#HQtQtQtQtQtQtQtQtQtQtQt", "#I#J#KQtQtQtQtQtQtQtQt#L.B#MQtQtQtQtQtQtQtQtQtQtQt", "#N#O#PQtQtQtQtQtQtQtQt#Q#R#SQtQtQtQtQtQtQtQtQtQtQt", "#T#U#V#WQtQtQtQtQtQtQt#X#Y#ZQtQtQtQtQtQtQtQtQtQtQt", "Qt#0#1#2#3QtQtQtQtQt#4#5#6#7QtQtQtQtQtQtQtQtQtQtQt", "QtQt#8#9a.a#aaabacadaeafagQtQtQtQtQtQtQtQtQtQtQtQt", "QtQtQtahaiajakalamanaoapQtQtQtQtQtQtQtQtQtQtQtQtQt", "QtQtQtQtQtaqarasatauQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt"}; ESS-24.01.1/etc/icons/splus_letters_large.png000066400000000000000000000102551455642170100207770ustar00rootroot00000000000000‰PNG  IHDR3&işŁsRGB@Ŕ}Ĺ pHYsÄÄ•+tEXtSoftwareMicrosoft Officeí5q-IDATXõY pTWvm-HH`›@Ć/˙ ?KĘĂN<éµ ţĂg lAľřödÍݲň4Řič0˝^čůóëf2 ŔC×=¦ť,v×n`Ń–SĄńc˛śT†€ Ľ†ĽOż@ă˝6ą],a3ni¬®¬ˇÝsFýZZlČŮĽż™‹~ăSđŘÖĂoB:ŇłłŞŽăJ—gŐMG+olćŤúCůÇ, aS5'Ç.6«P»vă&ŞŞ«QHă}žđĺȦM›”ńb¬—cb°”l‹gÄcÂtâ†k­ýWĂĽ”JĘ@`r1=“«Vu¤V‚3÷­čTµŽőŐČ!ąĂP0nąŁpIý0¨ t8Č8RłŽ6µbéÇu·őR·ĂârćŔ'‡q±ůž Ď–ŽNś>ó'4ś<‰Ó§Oă$ç“Ţm»víę'¶oß®jŹďş††ś:u őőő8{ö,ɧ…ÔL0šnáĺ),Ă߇%y=ü“Ö!0.ŹÇ.@Bv5¶ś<Źď:îăî1%Źś*¤t¨CnqCŚdeôńŤ»›ńÜ*_L!oťyŐʶęŁe™:ÔÍf?RgLížŐŔkk>BhäôJ’‹ňfĺJ ‚GNĹżü!3ÖmEií9˝Ü†F2µîň°ś«‡±Rू۬6čD(űşěs^0†ËÝÎs® eO ŰT!$ˇ%9"űߪyďéąň^ ¨\Ąo;ÝČjM›Í¤%ŁM*…_â:„&fˇ™ČžAŃŮř§[0mŐ!äUGőŢŁ8xîľąqw;ď÷(ô7k—Űf(QÉ ÉC,’nḽŢt+|rF†ŻĆČöáÇ™kkkUŃě-a|  >”`Dr›hć ´ígđ|r,ż›O)˘!8AÂ-A±9ŽáIí¶†ÍĂ“#ŢÁsăfá_§g`Ââ|LĎŢŠü}gQűÍ=|K÷đž7ôÄp´ńĹVĺK—°ˇËĆW{WtQâItź0ë­ĺzO‹é°j¦Ă‹·;ČßyŻľąˇ#—°Ř­bÍB —’ĘŃ/ą AÉ ż‰śŔs"*ÇĺÁ2šŞ:śŢź‰ç¦#>˙3©ĂÉËbňl Ć&‘Ă-9ĺĹěĆC*řĉÝ4-”˝wď^%4}é­<`śşć˛{‹!ÜárîąĐŠ9Ąźă•©E8*ýÂ)ďÇJZN!ąý“¨’É|±«@AťKµĚö`<‹nř _€gĆÎŔYʜķmvzĘ©ŘŐ‰ÉĎĽ1Há.gwĽ÷4N€‰Đ”’››‹µk×*EŕSÍ=ŐuŻŔ!ťĄG˘P’8řa­ĆN'ö_lDÚGµ”˶`v†$иĹěo–Ćß͙߄|M(@PB)&U KŕÇÜz,Š-Âčyx&qf•ÖŕěÍv6FÓ ‡T˝2 €ž`„nwěŘť;wbëÖ­ĘS= @ĽŮ;4=`2ś\-;+ąÁmęZUD śçźĘSwđ^ő ŚZ¶3eŹyÁC§ĂÄôgß30f5‚ăsŕ?Ň…^Âö᱉ôÖĐŮx:f)VîýJI™vd×)}\mÝ`z·˛-šëŇĄKJŹ}ýő×JŹůrĄgâ?ŇWëôJ; {»G©ÁfâJ1eÜÄö÷ě]+ö]ľŞúóXµë(ćTěCdĆüő µQ ŘĚ µ“ KOĄ°L¬P Ü2:˙¸pv_ľ©şN—Łkw[-ŕź“óÂ\â  ł/•_Ý`¬ôŚňD§"6Ën7MwuQgQČ}L3ř2›·­¶y‡°Ő]ńyĎßD^M&ŻŢ‚—ŢHGČŘĹĚĄUlđŠôz5˝•K°K1­t®Ú¸˘ň|ý®—ď~úO@<*Ľ~čgX4uo_˘NĎ Lš+==ĺ2:•Ä—3†——\će×îÝǦ#g±¬Ź'2źĆSţÇW ůdů!~ýN ö^lň†ÎÖn{·˝C€9Ĺ#”ő¦A:4ěJzZą":Í4şŕ´¶¨ÔŠPw—‚+÷žhęDLF5üFĚ'Adc@bI! Cb>Dţž3\ Ĺ盏—Ţ´űżxĚű›+µ9˱°¬)›*‘Zą5uő*´\NŃ_4Oj…G:3DLEăn@l-ž6k—ÁŐ˘ęüĘťĆÓěTý˘W¨˘+ –‚EU‡TÂŤźläOýYžťś˘=ů6BĂßĆ2ÔSQs05łBĺ„Çď\q§U}ŚP˛€¤ŘIÓ,CzE¬đ0»ĽEŐ|ý~·xŁŞ;~QĚ*ËďçăÝő{ŃÖ·~óň˘ÍZhlĄ ^ä2ŽNAřÂő¸ÚÖĘdc( 5G‡ŞCk˘ö¦”4™nĂPgŻC°±%¶34żĽceîlf®¤°Řf"”j<0l!ÁÔţ˙I.=¤…„ĎfĎd(¬„?«ý‹¬ü;˙t6I<†™[>`8íŞŹQ$@c좯$żdŰ —’&˝×IJŐ ĽöňmĽňn©ú†L%”P„ţáK°dÓçŢ0s?ú+ŕ˙Lîéíg±¬ęŃ«:©P­bŽ…UŢ—JpË÷.—Čv‡ŕđ’„ÝTv÷}‹Ó{ľěĐ)</ß(NăDż­ÄČ‘UsvßŐ}ě!K}«©EĄd!hl*‚âóŐ—ËLĽ<-[Ź]A«Ł›VŘ‹¸h¸¨+2ÓNĆ3@ÎÖˇIw+&ě ŰŮíş'_ú:gśN«fĄl±r•îóŮÇ›:0»řsüíäµx> .dependencies;\ done ## @for f in obsolete/*.el; do \ ## echo "$$(basename $${f}c):$${f}c" >> .dependencies;\ ## done -include .dependencies .el.elc: $(COMPILE) $< ##obsolete/%.elc: obsolete/%.el ## $(COMPILE-SIMPLE) $< JULIA-REPO=https://raw.githubusercontent.com/JuliaEditorSupport/julia-emacs/master ## Should happen before building ESS; definitely *NOT* after unpacking tarball : $(JULIAS): test -f ../etc/.IS.RELEASE || $(DOWNLOAD) $(JULIA-REPO)/julia-mode.el > julia-mode.el test -f ../etc/.IS.RELEASE || $(DOWNLOAD) $(JULIA-REPO)/julia-mode-latexsubs.el > julia-mode-latexsubs.el julia-%.elc: julia-%.el $(COMPILE-SIMPLE) $< ess-autoloads.el: @printf "\nGenerating $@\n" $(EMACSBATCH) --eval "(progn\ (setq make-backup-files nil)\ (setq generated-autoload-file (expand-file-name \"$@\"))\ (setq find-file-visit-truename t)\ (update-directory-autoloads default-directory))" ESS-24.01.1/lisp/ess-bugs-d.el000066400000000000000000000375471455642170100156000ustar00rootroot00000000000000;;; ess-bugs-d.el --- ESS[BUGS] dialect -*- lexical-binding: t; -*- ;; Copyright (C) 2008-2022 Free Software Foundation, Inc. ;; Author: Rodney Sparapani ;; Maintainer: ESS-help ;; This file is part of GNU Emacs. ;;; License: ;; ;; 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 ;; ;;; Code: (require 'ess-bugs-l) (require 'ess-utils) (require 'ess-inf) (require 'ess-mode) (defvar ess-bugs-command "OpenBUGS" "Default BUGS program in PATH.") (make-local-variable 'ess-bugs-command) (defvar ess-bugs-monitor '("") "Default list of variables to monitor.") (make-local-variable 'ess-bugs-monitor) (defvar ess-bugs-thin 1 "Default thinning parameter.") (make-local-variable 'ess-bugs-thin) (defvar ess-bugs-chains 1 "Default number of chains.") (make-local-variable 'ess-bugs-chains) (defvar ess-bugs-burnin 10000 "Default burn-in.") (make-local-variable 'ess-bugs-burnin) (defvar ess-bugs-update 10000 "Default number of updates after burnin.") (make-local-variable 'ess-bugs-update) (defvar ess-bugs-system nil "Default whether BUGS recognizes the system command.") (defvar ess-bugs-font-lock-keywords (list ;; .bug files (cons "#.*\n" font-lock-comment-face) (cons "^[ \t]*\\(model\\|var\\)\\>" font-lock-keyword-face) (cons (concat "\\ " ess-bugs-file-root ".bog 2>&1 " ;; ess-bugs-batch-post-command "' > " ess-bugs-file-root ".bsh") ;; (comint-send-input) ;; (insert "at -f " ess-bugs-file-root ".bsh now") ;; (comint-send-input) (insert "echo '" ess-bugs-batch-pre-command " " bugs-command " < " ess-bugs-file-root ".bmd > " ess-bugs-file-root ".bog 2>&1 " ess-bugs-batch-post-command "' | at now") (comint-send-input) )) (defun ess-bugs-na-bug () "ESS[BUGS]: Perform Next-Action for .bug" (if (equal 0 (buffer-size)) (ess-bugs-switch-to-suffix ".bug") ;else (ess-save-and-set-local-variables) (ess-bugs-switch-to-suffix ".bmd" ess-bugs-chains ess-bugs-monitor ess-bugs-thin ess-bugs-burnin ess-bugs-update)) ) ;;;###autoload (define-derived-mode ess-bugs-mode ess-mode "ESS[BUGS]" "Major mode for BUGS." (setq-local comment-start "#") (setq font-lock-defaults '(ess-bugs-font-lock-keywords nil t)) (setq ess-language "S") ; mimic S for ess-smart-underscore (unless (when (fboundp 'w32-shell-dos-semantics) (w32-shell-dos-semantics)) (add-hook 'comint-output-filter-functions #'ess-bugs-exit-notify-sh))) ;;;###autoload (add-to-list 'auto-mode-alist '("\\.[Bb][Uu][Gg]\\'" . ess-bugs-mode)) ;;;###autoload (add-to-list 'auto-mode-alist '("\\.[Bb][Oo][Gg]\\'" . ess-bugs-mode)) ;;;###autoload (add-to-list 'auto-mode-alist '("\\.[Bb][Mm][Dd]\\'" . ess-bugs-mode)) (defun ess-sci-to-dec () "For BUGS/S family: Express +/-0.000E+/-0 or +/-0.0e+/-00 as a decimal." (interactive) (setq buffer-read-only nil) (save-excursion (goto-char 0) (save-match-data (let ((ess-temp-replacement-string nil) (ess-temp-replacement-9 0) (ess-temp-replacement-diff 0)) (while (search-forward-regexp "-?[0-9][.][0-9][0-9]?[0-9]?[Ee][+-][0-9][0-9]?" nil t) (setq ess-temp-replacement-string (int-to-string (string-to-number (match-string 0)))) (setq ess-temp-replacement-diff (- (match-end 0) (match-beginning 0))) (save-match-data (setq ess-temp-replacement-9 (string-match "99999999999$" ess-temp-replacement-string)) (if (not ess-temp-replacement-9) (setq ess-temp-replacement-9 (string-match "000000000001$" ess-temp-replacement-string)))) (if ess-temp-replacement-9 (setq ess-temp-replacement-string (substring ess-temp-replacement-string 0 ess-temp-replacement-9))) (setq ess-temp-replacement-diff (- ess-temp-replacement-diff (string-width ess-temp-replacement-string))) (while (> ess-temp-replacement-diff 0) (setq ess-temp-replacement-string (concat ess-temp-replacement-string " ")) (setq ess-temp-replacement-diff (- ess-temp-replacement-diff 1))) (replace-match ess-temp-replacement-string)))))) (provide 'ess-bugs-d) ;;; ess-bugs-d.el ends here ESS-24.01.1/lisp/ess-bugs-l.el000066400000000000000000000241541455642170100155760ustar00rootroot00000000000000;;; ess-bugs-l.el --- ESS[BUGS] languages -*- lexical-binding: t; -*- ;; Copyright (C) 2006-2020 Free Software Foundation, Inc. ;; Author: Rodney Sparapani ;; Maintainer: ESS-help ;; This file is part of GNU Emacs ;;; License: ;; ;; 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 ;; ;;; Code: (require 'shell) (require 'ess-utils) (defvar ess-bugs-command) (defvar ess-bugs-chains) (defvar ess-jags-command) (defvar ess-jags-chains) (defvar ess-bugs-default-bins) (declare-function ess-bugs-na-bug "ess-bugs-d") (declare-function ess-jags-na-bug "ess-jags-d") (declare-function ess-bugs-na-bmd "ess-bugs-d") (declare-function ess-jags-na-jmd "ess-jags-d") (defgroup ess-bugs nil "ESS: BUGS." :group 'ess :prefix "ess-") (defcustom ess-bugs-batch-method (if (and ess-microsoft-p (fboundp 'w32-shell-dos-semantics) (w32-shell-dos-semantics)) 'dos 'sh) "Method used by `ess-bugs-batch'. The default is based on the value of the Emacs variable `system-type' and, on Windows machines, the function `w32-shell-dos-semantics'. \\='sh if *shell* runs a Bourne-like or a C-like Unix shell \\='dos if *shell* runs a DOS-like Windows shell Unix users will get \\='sh by default. Windows users running a DOS-like *shell* will get \\='dos by default, while those running a Unix-like *shell* will get \\='sh by default. Users whose default is not \\='sh, but are accessing a remote machine with `telnet' or `ssh', should have the following in their init file: (setq-default ess-bugs-batch-method \\='sh)" :group 'ess-bugs :type '(choice (const sh :tag "Bourne/C-like Unix Shell") (const dos :tag "DOS-like Windows shell"))) (defcustom ess-bugs-batch-post-command (if (equal ess-bugs-batch-method 'sh) "&" " ") "ESS[BUGS]: Modifiers at the end of the batch BUGS command line." :group 'ess-bugs :type 'string ) (defcustom ess-bugs-batch-pre-command (if (equal ess-bugs-batch-method 'sh) "nohup nice time" (if ess-microsoft-p "start")) "ESS[BUGS]: Modifiers at the beginning of the batch BUGS command line." :group 'ess-bugs :type 'string ) (defcustom ess-bugs-default-burn-in "500" "ESS[BUGS]: Burn-in iterations to discard." :group 'ess-bugs :type 'string ) (defcustom ess-bugs-default-update "1000" "ESS[BUGS]: Iterations to store." :group 'ess-bugs :type 'string ) (defvar ess-bugs-batch-command ";" "ESS[BUGS]: The name of the command to run BUGS in batch mode." ) (defvar ess-bugs-file "." "ESS[BUGS]: BUGS file with PATH.") (defvar ess-bugs-file-root "." "ESS[BUGS]: Root of BUGS file.") (defvar ess-bugs-file-suffix "." "ESS[BUGS]: Suffix of BUGS file.") (defvar ess-bugs-file-dir "." "ESS[BUGS]: Directory of BUGS file.") (defvar ess-bugs-file-data "..." "ESS[BUGS]: BUGS data file.") (defcustom ess-bugs-inits-suffix ".in" "ESS[BUGS]: BUGS init file suffix." :group 'ess-bugs :type 'string ) (defcustom ess-bugs-data-suffix ".dat" "ESS[BUGS]: BUGS data file suffix." :group 'ess-bugs :type 'string ) (defcustom ess-bugs-mode-hook nil "ESS[BUGS]: List of functions to call upon entering mode." :group 'ess-bugs :type 'hook) (defvar ess-bugs-monitor-vars " " "ESS[BUGS]: List of BUGS variables to be written out to a file.") (defvar ess-bugs-stats-vars " " "ESS[BUGS]: List of BUGS variables to be summarized with statistics.") (defvar ess-bugs-mode-map (let ((map (make-sparse-keymap))) (define-key map (quote [f2]) #'ess-revert-wisely) (define-key map "\C-c\C-c" #'ess-bugs-next-action) (define-key map "=" #'ess-bugs-hot-arrow) ;; (define-key map "_" #'ess-bugs-hot-arrow) map) "ESS[BUGS]: Keymap for mode.") (defvar ess-bugs-syntax-table (let ((table (make-syntax-table))) (modify-syntax-entry ?\\ "." table) (modify-syntax-entry ?# "<" table) (modify-syntax-entry ?\n ">" table) (modify-syntax-entry ?\( "()" table) (modify-syntax-entry ?\) ")(" table) (modify-syntax-entry ?. "w" table) table) "ESS[BUGS]: Syntax table for mode.") (defun ess-bugs-file () "ESS[BUGS]: Set internal variables dealing with BUGS files. Set `ess-bugs-file', `ess-bugs-file-root', `ess-bugs-file-suffix' and `ess-bugs-file-dir'." (let ((ess-bugs-temp-string (buffer-name))) (setq ess-bugs-file (expand-file-name ess-bugs-temp-string)) (setq ess-bugs-file-dir (convert-standard-filename (file-name-directory ess-bugs-file))) (setq ess-bugs-file-root (file-name-nondirectory (file-name-sans-extension ess-bugs-file))) (if (fboundp 'file-name-extension) (setq ess-bugs-file-suffix (file-name-extension ess-bugs-temp-string)) ;;else (setq ess-bugs-file-suffix (car (last (split-string ess-bugs-temp-string "[.]"))))) (setq ess-bugs-file-suffix (downcase (car (split-string (concat "." ess-bugs-file-suffix) "[<]")))) (setq ess-bugs-file (concat ess-bugs-file-dir ess-bugs-file-root ess-bugs-file-suffix)) ) ) (defun ess-bugs-exit-notify-sh (string) "ESS[BUGS]: Detect completion or failure of submitted job and notify the user." (let* ((exit-done "\\[[0-9]+\\] *\\+* *\\(Exit\\|Done\\)[^\r\n]*") (beg (string-match exit-done string))) (if beg (message "%s" (substring string beg (match-end 0)))))) (defun ess-bugs-hot-arrow () "ESS[BUGS]: Substitute <- for = key press" (interactive) (insert " <- ")) (defun ess-bugs-next-action () "ESS[BUGS/JAGS]: Perform the appropriate next action." (interactive) (ess-bugs-file) (cond ((equal ".bug" ess-bugs-file-suffix) (ess-bugs-na-bug)) ((equal ".jag" ess-bugs-file-suffix) (ess-jags-na-bug)) ((equal ".bmd" ess-bugs-file-suffix) (ess-save-and-set-local-variables) (ess-bugs-na-bmd ess-bugs-command ess-bugs-chains)) ((equal ".jmd" ess-bugs-file-suffix) (ess-save-and-set-local-variables) (ess-jags-na-jmd ess-jags-command ess-jags-chains))) ) (defun ess-bugs-sci-to-round-4-dp () "ESS[BUGS]: round output from +/-0.000E+/-0 to 4 decimal places." (interactive) (setq buffer-read-only nil) (save-excursion (goto-char 0) (save-match-data (let ((ess-bugs-replacement-string nil) (ess-bugs-replacement-9 0) (ess-bugs-replacement-diff 0)) (while (search-forward-regexp "-?[0-9][.][0-9][0-9][0-9]E[+-][0-9]" nil t) (setq ess-bugs-replacement-string (int-to-string (string-to-number (match-string 0)))) (setq ess-bugs-replacement-diff (- (match-end 0) (match-beginning 0))) (save-match-data (setq ess-bugs-replacement-9 (string-match "99999999999$" ess-bugs-replacement-string)) (if (not ess-bugs-replacement-9) (setq ess-bugs-replacement-9 (string-match "000000000001$" ess-bugs-replacement-string)))) (if ess-bugs-replacement-9 (setq ess-bugs-replacement-string (substring ess-bugs-replacement-string 0 ess-bugs-replacement-9))) (setq ess-bugs-replacement-diff (- ess-bugs-replacement-diff (string-width ess-bugs-replacement-string))) (while (> ess-bugs-replacement-diff 0) (setq ess-bugs-replacement-string (concat ess-bugs-replacement-string " ")) (setq ess-bugs-replacement-diff (- ess-bugs-replacement-diff 1))) (replace-match ess-bugs-replacement-string)))))) ;;; ESS[BUGS-Shell] for running BUGS interactively (defgroup ess-bugs-shell nil "ESS: BUGS-Shell." :group 'ess-bugs :prefix "ess-") (defcustom ess-bugs-shell-buffer-name "BUGS" "ESS[BUGS-Shell]: The name of the BUGS-Shell buffer." :group 'ess-bugs-shell :type 'string) (defcustom ess-bugs-shell-command "OpenBUGS" "ESS[BUGS-Shell]: The name of the command to run BUGS interactively. Set to the name of the batch BUGS script that comes with ESS or to the name of BUGS command. Make sure it is in your PATH or add path to the command name." :group 'ess-bugs-shell :type 'string) (defcustom ess-bugs-shell-default-output-file-root "bugs" "ESS[BUGS-Shell]: Default value for the root of output files." :group 'ess-bugs-shell :type 'string) (defcustom ess-bugs-shell-mode-hook nil "ESS[BUGS-Shell]: List of functions to call upon entering mode." :group 'ess-bugs-shell :type 'hook) (defun ess-bugs-shell () "Create a buffer with BUGS running as a subprocess." (interactive) (pop-to-buffer-same-window (concat "*" ess-bugs-shell-buffer-name "*")) (make-comint ess-bugs-shell-buffer-name ess-bugs-shell-command nil ess-bugs-default-bins ess-bugs-shell-default-output-file-root) (comint-mode) (setq shell-dirtrackp t major-mode 'bugs-shell-mode mode-name "ESS[BUGS-Shell]" comint-prompt-regexp "^Bugs> *") (make-local-variable 'font-lock-defaults) (setq font-lock-defaults '(ess-bugs-font-lock-keywords nil t)) (run-mode-hooks 'ess-bugs-shell-mode-hook) ) (provide 'ess-bugs-l) ;;; ess-bugs-l.el ends here ESS-24.01.1/lisp/ess-custom.el000066400000000000000000002623561455642170100157270ustar00rootroot00000000000000;;; ess-custom.el --- Customize variables for ESS -*- lexical-binding: t; -*- ;; Copyright (C) 1997-2024 Free Software Foundation, Inc. ;; Author: Rodney Sparapani ;; Maintainer: ESS-help ;; Keywords: languages ;; This file is part of GNU Emacs ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; ;; This file 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. ;; ;; A copy of the GNU General Public License is available at ;; https://www.r-project.org/Licenses/ ;; This file is part of ESS ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; ;; This file 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. ;; ;; A copy of the GNU General Public License is available at ;; https://www.r-project.org/Licenses/ ;;; Commentary: ;; This file holds defcustoms for ESS. It is required by ess-utils.el, ;; which in turn is required by almost every other ESS file. ;;; Code: (require 'comint) ;; FIXME: When Emacs is started from Cygwin shell in Windows, ;; we have (equal window-system 'x) -and should use "--ess" in *d-r.el (defvar ess-microsoft-p (memq system-type '(ms-dos windows-nt)) "Value is t if the OS is one of Microsoft's, nil otherwise.") ;; Customization Groups (defgroup ess nil "ESS: Emacs Speaks Statistics." :group 'languages :link '(info-link "(ESS)") :link '(url-link "https://ess.r-project.org/")) (defgroup ess-edit nil "ESS: editing behavior, including comments/indentation." :group 'ess :prefix "ess-") (defgroup ess-proc nil "ESS: process control." :group 'ess :prefix "ess-") (defgroup ess-command nil "ESS: Commands for various things." :group 'ess :prefix "ess-") (defgroup ess-help nil "ESS: help functions." :group 'ess :prefix "ess-") (defgroup ess-hooks nil "ESS: hooks for customization." :group 'ess :prefix "ess-") (defgroup ess-S nil "ESS: S Languages." :group 'ess :prefix "ess-") (defgroup ess-SPLUS nil "ESS: S-PLUS Dialect of S." :group 'ess-S :prefix "ess-") (defgroup ess-R nil "ESS: R Dialect of S." :group 'ess-S :prefix "ess-") (defgroup ess-Julia nil "ESS: Julia." :group 'ess :prefix "julia-") (defgroup ess-sas nil "ESS: SAS." :group 'ess :prefix "ess-") (defgroup ess-roxy nil "Mode for editing in-code Roxygen documentation." :group 'ess :group 'convenience :group 'ess-extras :prefix "ess-" :group 'tools) (defgroup ess-extras nil "Extra utilities for ESS." :group 'ess :prefix "ess-") (defgroup ess-faces nil "Faces and face options for ESS modes." :group 'ess :group 'faces :prefix "ess-") ; User changeable variables ;;*;; Options and Initialization ;;;###autoload (defcustom ess-lisp-directory (file-name-directory (or load-file-name buffer-file-name)) "Directory containing ess-site.el(c) and other ESS Lisp files." :group 'ess :type 'directory :package-version '(ess . "VERSION")) (defcustom ess-etc-directory ;; Try to detect the `etc' folder only if not already set up by distribution (let (dir) (dolist (d '("./etc/" "../../etc/ess/" "../etc/" "../etc/ess/")) (setq d (expand-file-name d ess-lisp-directory)) (when (file-directory-p d) (setq dir d))) dir) "Location of the ESS etc/ directory. The ESS etc directory stores various auxiliary files that are useful for ESS, such as icons." :group 'ess :type 'directory :package-version '(ess . "VERSION")) ;; Depending on how ESS is loaded the `load-path' might not contain ;; the `lisp' directory. For this reason we need to add it before we ;; start requiring ESS files ;;;###autoload (add-to-list 'load-path (directory-file-name ess-lisp-directory)) ;; Add ess-lisp-directory/obsolete to load-path; files here will ;; automatically warn that they are obsolete when loaded. ;;;###autoload (add-to-list 'load-path (directory-file-name (expand-file-name "obsolete" ess-lisp-directory))) (unless (file-directory-p ess-etc-directory) (display-warning 'ess (format "Could not find directory `ess-etc-directory': %s" ess-etc-directory) :error)) ;; Menus and pulldowns. (defcustom ess-imenu-use-p (fboundp 'imenu) "Non-nil means use imenu facility. This value can be overridden by mode-specific variables, such as `ess-imenu-use-S'." :group 'ess :type 'boolean) (defcustom ess-imenu-use-S ess-imenu-use-p "Non-nil means include an Imenu menu item in S buffers." :group 'ess :type 'boolean) (defcustom ess-auto-width-visible nil "When non-nil, echo width setting in the inferior buffer. See `ess-auto-width'. Be warned that ESS can set the width a lot." :group 'ess :type 'boolean :package-version '(ess . "VERSION")) (defcustom ess-auto-width nil "When non-nil, set the width option when the window configuration changes. When \\='frame, set the width to the frame width. When \\='window, set the width to the window width. If an integer, set the width to that integer. If it's a negative integer, set the width to the window's width minus that number. Anything else is treated as \\='window." :group 'ess :type '(choice (const :tag "Do nothing" :value nil) (const :tag "Frame width" :value frame) (const :tag "Window width" :value window) (integer :tag "Integer value")) :package-version '(ess . "VERSION")) (defcustom ess-handy-commands '(("change-directory" . ess-change-directory) ("install.packages" . ess-install-library) ("library" . ess-library) ("objects[ls]" . ess-execute-objects) ("help-apropos" . ess-display-help-apropos) ("help-index" . ess-display-package-index) ("help-object" . ess-display-help-on-object) ("search" . ess-execute-search) ("set-width" . ess-execute-screen-options) ("setRepos" . ess-setRepositories) ("sos" . ess-sos) ("vignettes" . ess-display-vignettes) ) "An alist of custom ESS commands. These are available for call by function `ess-handy-commands' and `ess-smart-comma' function." :group 'ess :type 'alist) (defvar-local ess--local-handy-commands nil "Store handy commands locally.") (defcustom ess-describe-at-point-method nil "Whether `ess-describe-object-at-point' should use a tooltip. If nil display in an electric buffer. If \\='tooltip display in a tooltip. See also `tooltip-hide-delay' and variable `tooltip-delay'." :group 'ess-utils :type '(choice (const :tag "buffer" :value nil ) (const tooltip))) (defvaralias 'ess-R-describe-object-at-point-commands 'ess-r-describe-object-at-point-commands) (defcustom ess-r-describe-object-at-point-commands '(("str(%s)") (".ess_htsummary(%s, hlength = 20, tlength = 20)") ("summary(%s, maxsum = 20)")) "A list of commands cycled by `ess-describe-object-at-point'. %s is substituted with the name at point. The value of each element is nil and is not used in current implementation." :group 'ess-R :type 'alist) (defcustom ess-S-describe-object-at-point-commands ess-R-describe-object-at-point-commands "An alist of commands cycled by `ess-describe-object-at-point'. %s is substitute with the name at point. The value is not used as yet." :group 'S+ :type 'alist) (defcustom ess-can-eval-in-background t "If non-nil ESS can perform caching and other background activities. This allows ESS to call the subprocess on idle time." :group 'ess :type 'boolean) (defcustom ess-user-full-name (user-full-name) "The full name of the user." :group 'ess :type 'string) (defcustom ess-blink-region t "If t evaluated region is highlighted for a shortwhile. See also `ess-blink-delay'" :group 'ess :type 'boolean) (defcustom ess-blink-delay .3 "Number of seconds to highlight the evaluated region." :group 'ess :type 'number) (defcustom ess-ask-for-ess-directory t "When non-nil ask the process directory when ESS process starts. When set to nil, and the process is invoked with an universal argument, the directory is prompted for." :group 'ess :type 'boolean) (defcustom ess-ask-about-transfile nil "Non-nil means ask about a transcript file before running ESS." :group 'ess :type 'boolean) (defcustom ess-display-buffer-reuse-frames t "Non-nil means \\[display-buffer] reuses existing frames. See `display-buffer-reuse-frames'." :group 'ess :type 'boolean) (defvar-local ess-language nil "Determines the language to use for the current buffer. See also `ess-dialect'.") (defvar-local ess-dialect nil "String version of the dialect being run for the inferior process. This, plus `ess-language', should be able to determine the exact version of the statistical package being executed in the particular buffer.") (defvaralias 'ess-directory-function 'ess-startup-directory-function) (defcustom ess-startup-directory-function nil "Function to return the directory that ESS is run from. Value of `ess-startup-directory' has precedence over this function." :group 'ess :type '(choice (const nil) function)) (defvaralias 'ess-directory 'ess-startup-directory) (defcustom ess-startup-directory nil "The directory to run ESS processes from. If a string it should be a directory from which to start the process. If a symbol, the symbol's value should be a directory. For example, the following setting would always start the process in the directory of the current file: (setq ess-startup-directory ''default-directory) If `ess-startup-directory' is nil (the default) and `ess-startup-directory-function' is non-nil, the value returned by `ess-startup-directory-function' is used as a directory. If `ess-startup-directory-function' is nil, then the current project as returned by `project-current' is used. For files which mark an R project see `ess-r-project'. For example you can add .Rprofile to a sub-directory of a project to mark it as R sub-project. Finally, if not in a project (`project-current' returned nil) the `default-directory' is used. It is normally the directory of the current file. See also `ess-ask-for-ess-directory'." :group 'ess :type '(choice (const nil) directory symbol)) (defcustom ess-history-directory nil "Directory to pick up `ess-history-file' from. If this is nil, the history file is relative to the startup directory of the inferior process (see `ess-startup-directory')." :group 'ess :type '(choice (const nil) directory)) (defcustom ess-history-file t "File to pick up history from. nil means *no* history is read or written. t means something like \".Rhistory\". If this is a relative file name, it is relative to `ess-history-directory'. Consequently, if that is set explicitly, you will have one history file for all projects." :group 'ess :type '(choice (const :tag "Off" nil) (const :tag "On" t) file)) (defcustom ess-plain-first-buffername t "When non-nil, the first process buffer created does not have a number. In other words, it is R:foo rather than R:1:foo. Subsequent processes buffers are always numbered (e.g. R:2:foo." :group 'ess :type 'boolean) (define-obsolete-variable-alias 'ess-use-inferior-program-name-in-buffer-name 'ess-use-inferior-program-in-buffer-name "ESS 18.10") (defcustom ess-use-inferior-program-in-buffer-name nil "For R, use e.g., 'R-2.1.0' or 'R-devel' (the program name) for buffer name. Avoids the plain dialect name." :group 'ess :type 'boolean) (defcustom ess-use-ido t "If t ess will try to use ido completion whenever possible. By default ESS uses enables IDO flex matching. See `ido-enable-flex-matching' for details on flex matching and `ess-ido-flex-matching' on how to disable it for ESS, if you don't want it. See info node `(ido) Top' for more information about how ido works." :group 'ess :require 'ido :type 'boolean) (defcustom ess-tab-complete-in-script nil "If non-nil, TAB tries to complete if it does not indent in script buffers. See also `ess-first-tab-never-complete'." :group 'ess :type 'boolean) (make-obsolete-variable 'ess-tab-complete-in-script 'tab-always-indent "ESS 19.04" 'set) (define-obsolete-variable-alias 'ess-first-tab-never-completes-p 'ess-first-tab-never-complete "ESS 19.04") (defcustom ess-first-tab-never-complete 'symbol "If t, first TAB never tries to complete in `ess-mode'. If \\='symbol first TAB doesn't try to complete if next char is a valid symbol constituent. If \\='symbol-or-paren don't complete if next char is closed paren )}] or symbol character. If \\='symbol-or-paren-or-punct don't complete if next char is punctuation +-=% etc, or closed paren or symbol. If \\='unless-eol - first TAB completes only at end of line. If nil first TAB always tries to complete (this might be too aggressive and dangerous)." :group 'ess :type '(choice (const nil) (const symbol) (const symbol-or-paren) (const symbol-or-paren-or-punct) (const unless-eol) (const t))) (defcustom ess-use-eldoc t "If t, activate eldoc in `ess-mode' and `inferior-ess-mode' buffers. If \\='script-only activate in `ess-mode' buffers only. See also `ess-eldoc-show-on-symbol'." :group 'ess-extras :type '(choice (const t) (const script-only) (const nil))) (defcustom ess-eldoc-show-on-symbol nil "If non-nil, show help string whenever the point is on a symbol. If nil show only when the point is in a function call, i.e. after (." :group 'ess-extras :type 'boolean) (defcustom ess-eldoc-abbreviation-style 'normal "Controls how `eldoc' displays information that does not fit on a line. A symbol which can be - nil: do nothing - mild: Replace TRUE, FALSE with T,F - normal: Try mild + shorten the default values longer than 10 characters. - strong: Try normal + completely remove default values except =F,=T,=d where d is a digit. - aggressive (or t): Try strong + truncate the doc string to fit into minibuffer. The default style is \\='normal. Ess-eldoc also honors the value of `eldoc-echo-area-use-multiline-p'. If this variable is not t (the default), doc strings are truncated to fit into minibufer. This allows the use of different abbreviation styles with the truncation." :group 'ess :type '(choice (const nil) (const mild) (const normal) (const strong) (const aggressive) (const t))) (defcustom ess-use-flymake t "If non-nil activate flymake in `ess-mode' buffers. If \\='process, only check if the buffer has an inferior process." :group 'ess :type '(choice (const :tag "Always" t) (const :tag "With running inferior process" process) (const :tag "Never" nil)) :package-version '(ess . "VERSION")) (defcustom ess-use-auto-complete t "If non-nil, activate auto-complete support. If t, activate auto-complete support in `ess-mode' and `inferior-ess-mode' buffers. If \\='script-only activate in `ess-mode' buffers only. If non-nil add `ac-source-R' and `ac-source-filename' to the `ac-sources' buffer local variable. ESS defines three AC sources `ac-source-R',`ac-source-R-objects' and `ac-source-R-args'. See auto-complete package documentation (http://cx4a.org/software/auto-complete/) for how to install your custom sources." :group 'ess-extras :type '(choice (const t) (const script-only) (const nil))) (make-obsolete-variable 'ess-use-auto-complete "Auto-complete is unmaintained; use company-mode instead" "ESS 19.04" 'set) (defcustom ess-use-company t "If t, activate company support in `ess-mode' and `inferior-ess-mode' buffers. If non-nil add `company-R-args' and `company-R-objects' to the `company-backends'. If \\='script-only activate in `ess-mode' buffers only." :group 'ess-extras :type '(choice (const t) (const script-only) (const nil))) (defcustom ess-company-arg-prefix-length nil "Minimum prefix for ess company function argument completion." :group 'ess-extras :type '(choice (const :tag "Default" nil) integer)) (defcustom ess-use-tracebug t "If t, load `ess-tracebug' when R process starts." :group 'ess-extras :type 'boolean) (defcustom ess-ido-flex-matching t "If t, ido for ESS completion uses flex matching. See `ido-enable-flex-matching' for details. If you have an old computer, or you load lot of packages, you might want to set this to nil." :group 'ess :type 'boolean) (defvar ess--completing-hist nil "Variable to store completion history. Used by `ess-completion-read' command.") (defvar-local ess-smart-operators () "List of smart operators to be used in ESS and IESS modes. Not to be set by users. It is redefined by mode specific settings, such as `ess-r-smart-operators'.") (defvaralias 'ess-R-smart-operators 'ess-r-smart-operators) (defvar ess-r-smart-operators nil "If nil, don't use any of smart operators. If t, use all. If an explicit list of operators, use only those operators. In current version of ESS, it controls the behavior of `ess-smart-comma' only, but will be enriched in the near future.") (defvar ess-no-skip-regexp "[ \t\n]*\\'" "If `ess-next-code-line' sees this line, it doesn't jump over. Used to avoid annoying jumping by ess-eval.*-and-step to end of buffer or end chunks etc.") (make-obsolete-variable 'ess-smart-S-assign-key nil "ESS 18.10") (defcustom ess-assign-list (cons (or (bound-and-true-p ess-S-assign) " <- ") '(" <<- " " = " " -> " " ->> ")) "List of assignment operators. `ess-cycle-assign' uses this list. These strings must contain spaces on either side." ;; Note that spaces on either side is not strictly true (as in the ;; function won't error), but matching <-/<<- is broken without ;; them. :type '(repeat string) :group 'ess :package-version '(ess . "VERSION")) (defvar ess-S-assign) (make-obsolete-variable 'ess-S-assign 'ess-assign-list "ESS 18.10") (defcustom ess-r-prettify-symbols '(("<-" . (?\s (Br . Bl) ?\s (Bc . Bc) ?â†)) ("->" . (?\s (Br . Bl) ?\s (Bc . Bc) ?→)) ("->>" . (?\s (Br . Bl) ?\s (Br . Bl) ?\s (Bl . Bl) ?- (Bc . Br) ?- (Bc . Bc) ?> (Bc . Bl) ?- (Br . Br) ?>)) ("<<-" . (?\s (Br . Bl) ?\s (Br . Bl) ?\s (Bl . Bl) ?< (Bc . Br) ?- (Bc . Bc) ?- (Bc . Bl) ?< (Br . Br) ?-))) ;; Setup prettify-symbols-alist to show "pretty" arrows, but make ;; sure that they arrows use the same amount of spacing as <- and ;; <<- to ensure indentation does not change when ;; prettify-symbols-mode is turned on/off. "Alist of symbols prettifications, see `prettify-symbols-alist'. This gets appended to `prettify-symbols-alist', so set it to nil if you want to disable R specific prettification." :group 'ess-R :type '(alist :key-type string :value-type symbol) :package-version '(ess . "VERSION")) ;;*;; Variables concerning editing behavior (defcustom ess-filenames-map t "If non-nil, filenames and objects are the same in an attached directory. This is not true for DOS and other OS's with limited filename lengths. Even if this is set incorrectly, the right things will probably still happen, however." :group 'ess-edit :type 'boolean) (defcustom ess-keep-dump-files t "Variable controlling whether to delete dump files after a successful load. If nil: always delete. If `ask', confirm to delete. If `check', confirm to delete, except for files created with `ess-dump-object-into-edit-buffer'. Anything else, never delete. This variable only affects the behavior of `ess-load-file'. Dump files are never deleted if an error occurs during the load." :group 'ess-edit :type '(choice (const :tag "Check" :value check) (const :tag "Ask" :value ask) (const :tag "Always keep" :value t) (const :tag "Always delete" :value nil))) (defcustom ess-delete-dump-files nil "Non-nil means delete dump files after they are created. This applies to dump files created with `ess-dump-object-into-edit-buffer', only. Boolean flag which determines what to do with the dump files generated by \\[ess-dump-object-into-edit-buffer], as follows: If non-nil: dump files are deleted after each use, and so appear only transiently. The one exception to this is when a loading error occurs, in which case the file is retained until the error is corrected and the file re-loaded. If nil: dump files are not deleted, and backups are kept as usual. This provides a simple method for keeping an archive of S functions in text-file form. Auto-save is always enabled in dump-file buffers to enable recovery from crashes. This is useful to prevent source files being created for objects you don't actually modify. Once the buffer is modified and saved however, the file is not subsequently deleted unless `ess-keep-dump-files' is nil, and the file is successfully loaded back into S." :group 'ess-edit :type 'boolean) (defcustom ess-fill-calls t "If non-nil, refilling inside a call arranges arguments. In other words, refilling a paragraph inside a function or indexing call will arrange the arguments according to `fill-column' as in: fun_call(argument1, argument2, argument3, argument4) Refilling repeatedly cycles through different styles and eventually to the original formatting. The second style formats according to one argument per line: fun_call(argument1, argument2, argument3, argument4) When `ess-fill-calls-newlines' is t, the second style becomes: fun_call( argument1, argument2, argument3, argument4 ) Setting `ess-offset-arguments' to `prev-line' or `prev-call' activates a third style. It keeps one argument per line except for the first N arguments. N is controlled with a prefix. For example, calling \\[fill-paragraph] three times sets N to 1 while calling \\[fill-paragraph] twice then \\[universal-argument] 2 \\[fill-paragraph] sets N to 2. Here what the default produces: fun_call(argument1, argument2, argument3, argument4, argument5 ) This style is useful for refilling R6 or ggproto class definitions. The blinking of the refilled region can be disabled with `ess-blink-refilling'." :group 'ess-edit :type 'boolean) (defcustom ess-fill-continuations t "Controls filling of continuations. If non-nil, refilling a paragraph inside a continuation of statements (expressions separated by operators) will arrange all its elements, never going past `fill-column'. lm(outcome ~ pred1 + pred2 + pred3 + pred4, data) Refilling repeatedly cycles through different styles and eventually to the original formatting. The second style lay out the statements according to one expression per line: lm(outcome ~ pred1 + pred2 + pred3 + pred4, data) The blinking of the refilled region can be disabled with `ess-blink-refilling'." :group 'ess-edit :type 'boolean) (defcustom ess-fill-calls-newlines nil "When non-nil, refilling may place newlines before and after delimiters. When non-nil, the second refilling style produces newlines after and before the opening and closing delimiters. This is intended for example for dplyr-style code: fun_call( argument1, argument2, argument3, argument4 ) Note that this setting is temporary and likely to be replaced in a future ESS version by a more comprehensive and flexible way to set refill styles." :group 'ess-edit :type 'boolean) (defcustom ess-blink-refilling t "When non-nil, refilling blinks the filling region." :group 'ess-edit :type 'boolean) (define-obsolete-variable-alias 'ess-mode-silently-save 'ess-save-silently "ESS 19.04") (defcustom ess-save-silently 'auto "If non-nil, possibly save buffers without asking. If t, save without asking. If \\='auto, save without asking if either `compilation-ask-about-save' or variable `auto-save-visited-mode' is non-nil. Affects `ess-save-file'." :group 'ess-edit :type '(choice (const :tag "Do not save without asking." :value nil) (const :tag "Use compilation-ask-about-save and auto-save-visited-mode." :value auto) (const :tag "Save without asking." :value t)) :package-version '(ess . "VERSION")) ;;*;; Variables controlling editing ;;;*;;; Edit buffer processing (defcustom ess-function-template " <- function( )\n{\n\n}\n" "If non-nil, function template used when editing nonexistent objects. The edit buffer will contain the object name in quotes, followed by this string. Point will be placed after the first parenthesis or bracket." :group 'ess-edit :type 'string) ;;;*;;; Indentation parameters (define-obsolete-variable-alias 'ess-tab-always-indent 'tab-always-indent "ESS 19.04") (define-obsolete-variable-alias 'ess-indent-level 'ess-indent-offset "15.09") (defvar ess-indent-offset 2 "Main indentation offset that is commonly inherited by other offsets. See `ess-style-alist' for all available offsets.") ;;;###autoload (put 'ess-indent-offset 'safe-local-variable #'numberp) (defvar ess-offset-arguments 'open-delim "Indent for arguments of function calls or indexing brackets. This variables has an effect only when the ( or [ are not directly followed by a new line. See `ess-offset-arguments-newline' for indentation after closing newline. When set to `open-delim', arguments are indented relative to the opening parenthesis of the closest function call: object <- call(argument, other_call(argument, other_argument)) When set to `prev-call', arguments are indented relative to the closest function call: object <- call(argument, other_call(argument, other_argument)) When set to `prev-line', arguments are indented relative to the preceding line: object <- call(argument, other_call(argument, other_argument)) This setting can also be set to a list containing the the offset type and the offset size, such as `'(prev-call 2)'. Otherwise, `ess-indent-offset' is used as a default. See `ess-style-alist' for other offsets controlling indentation.") (define-obsolete-variable-alias 'ess-arg-function-offset-new-line 'ess-offset-arguments-newline "15.09") (defvar ess-offset-arguments-newline 'prev-call "Indent of arguments when ( or [ is followed by a new line. When set to `open-delim', arguments on a new line are indented relative to the opening parenthesis of the closest function call: object <- call(argument, other_call( argument, other_argument )) When set to `prev-call', arguments on a new line are indented relative to the closest function call: object <- call(argument, other_call( argument, other_argument )) You can control the details of indentation at `prev-call' with `ess-indent-from-lhs' and `ess-indent-from-chain-start'. When set to `prev-line', arguments on a new line are indented relative to the preceding line: object <- call(argument, other_call( argument, other_argument )) This setting can also be set to a list containing the the offset type and the offset size, such as `'(prev-call 2)'. Otherwise, `ess-indent-offset' is used as a default. See `ess-style-alist' for other offsets controlling indentation.") (defvar ess-offset-block 'prev-line "Controls indentation for blocks. A block is usually declared with braces but a statement wrapped in anonymous parentheses is also considered a block. This offset can be either `prev-call', `prev-line' or `open-delim'. When set to `open-delim', blocks are indented relative to the opening parenthesis of the closest function call: call(argument, other_call(parameter = { stuff }, { stuff })) call(argument, lapply(data, function(x) { body })) When set to `prev-call', blocks are indented relative to the closest function call: call(argument, other_call(parameter = { stuff }, { stuff })) call(argument, lapply(data, function(x) { body })) You can control the details of indentation at `prev-call' with `ess-indent-from-lhs' and `ess-indent-from-chain-start'. When set to `prev-line', blocks are indented relative to the preceding line: call(argument, other_call(parameter = { stuff }, { stuff })) call(argument, lapply(data, function(x) { body })) This setting can also be set to a list containing the the offset type and the offset size, such as `'(prev-call 2)'. Otherwise, `ess-indent-offset' is used as a default. See `ess-style-alist' for other offsets controlling indentation.") (define-obsolete-variable-alias 'ess-first-continued-statement-offset 'ess-offset-continued "15.09") (define-obsolete-variable-alias 'ess-continued-statement-offset 'ess-offset-continued "15.09") (defvar ess-offset-continued 'straight "This setting controls indentation of continued statements. That is, consecutive statements separated by operators. When set to \\='straight, continued statements are indented as follows: object %>% some_function() %>% other_function() When set to \\='cascade: object %>% some_function() %>% other_function() The \\='straight and \\='cascade settings are actually equivalent to \\='(straight . t) and \\='(cascade . t), where t represents the base indent size. More generally, you can supply \\='(straight . N) to control the size of indentation. See `ess-style-alist' for for an overview of ESS indentation.") (defvar ess-align-nested-calls '("ifelse") "List of strings for which `ess-offset-arguments-newline' is ignored. These calls will be vertically aligned instead. For example, if `ifelse' is a member of the list, nested ifelse calls are indented like this: object <- ifelse(condition1, out1, ifelse(condition2, out2, out3)) See `ess-style-alist' for for an overview of ESS indentation.") (defvar ess-align-arguments-in-calls '("function[ \t]*(") "A list of regexes where `ess-offset-arguments' is ignored. List of regexes specifying the calls where `ess-offset-arguments' should have no effect on function declarations. The arguments of those calls will be aligned from the opening parenthesis. By default, function declarations are overridden. If for example `ess-offset-arguments' is set to `prev-line', then function calls are normally indented as in: some_function(argument1, argument2, argument3 ) However, the parameters of function declarations will be vertically aligned: fun <- function(argument1, argument2 argument3) { body } See `ess-style-alist' for further details.") (defvar ess-align-continuations-in-calls t "Whether continuations inside calls are indented from the opening delimiter. This produces the following indentation: 10 + (1 + 2 + 3 + 4) object[variable1 + variable2] if (test1 || test2 || test3 || test4) { any(test5 & test6) } instead of 10 + (1 + 2 + 3 + 4) object[variable1 + variable2] if (test1 || test2 || test3 || test4) { any(test5 & test6) } Definition operators (`<-', `=', `:=' and `~') still trigger an indentation in all cases. Also, operators at top level and in curly brackets are not affected by this setting and always induce an offset: { var1 + var2 } See `ess-style-alist' for for an overview of ESS indentation.") (defvar ess-align-blocks '(control-flow) "List of block types for which `ess-offset-blocks' is ignored. The overridden blocks are vertically aligned. The list can contain either or both of the symbols `control-flow' and `fun-decl'. With `control-flow', if, else for and while blocks will always be aligned vertically. With `fun-decl', the body of a function declaration will always be aligned with the call to `function'.") (define-obsolete-variable-alias 'ess-arg-function-offset 'ess-indent-from-lhs "15.09") (defvar ess-indent-from-lhs '(arguments fun-decl-opening) "List of elements that are indented from the left side of an assignment. The list accepts the symbol `arguments' and `fun-decl-opening'. For arguments, this setting only has an effect for offsets set to `prev-call'. When set, this indentation is produced: some_function(parameter = other_function( argument )) object <- some_function( argument1, argument2 ) instead of: some_function(parameter = other_function( argument )) object <- some_function( argument1, argument2 ) `fun-decl-opening' refers to the opening curly following a function declaration. Setting it produces: object <- function(argument) { body } instead of: object <- function(argument) { body } This is useful when (a) you have a long function name and want to break a line after `<-' so that you have room to lay out the arguments within `fill-column' characters; (b) you still want to align the function body from the LHS to save horizontal space. See `ess-style-alist' for for an overview of ESS indentation.") (defvar ess-indent-from-chain-start t "When non-nil, chained calls are treated as if they were one call. Indentation will start from the first one. This setting only has an effect for offsets set to `prev-call' or block offsets set to `opening-delim'. If nil: some_function(other_function( argument )) If t: some_function(other_function( argument )) See `ess-style-alist' for for an overview of ESS indentation.") ;;added rmh 2Nov97 at request of Terry Therneau (define-obsolete-variable-alias 'ess-fancy-comments 'ess-indent-with-fancy-comments "15.09") (defcustom ess-indent-with-fancy-comments t "Non-nil means distinguish between #, ##, and ### for indentation. See `ess-style-alist' for for an overview of ESS indentation." :type 'boolean :group 'ess-edit) ;;;*;;; Editing styles (defvar ess-style-alist `((BSD (ess-indent-offset . 8) (ess-offset-arguments . ,(default-value 'ess-offset-arguments)) (ess-offset-arguments-newline . ,(default-value 'ess-offset-arguments-newline)) (ess-offset-block . prev-call) (ess-offset-continued . ,(default-value 'ess-offset-continued)) (ess-align-nested-calls . ,(default-value 'ess-align-nested-calls)) (ess-align-arguments-in-calls . ,(default-value 'ess-align-arguments-in-calls)) (ess-align-continuations-in-calls . ,(default-value 'ess-align-continuations-in-calls)) (ess-align-blocks . ,(default-value 'ess-align-blocks)) (ess-indent-from-lhs . ,(default-value 'ess-indent-from-lhs)) (ess-indent-from-chain-start . ,(default-value 'ess-indent-from-chain-start)) (ess-indent-with-fancy-comments . ,(default-value 'ess-indent-with-fancy-comments))) (C++ (ess-indent-offset . 4) (ess-offset-arguments . ,(default-value 'ess-offset-arguments)) (ess-offset-arguments-newline . ,(default-value 'ess-offset-arguments-newline)) (ess-offset-block . prev-call) (ess-offset-continued . ,(default-value 'ess-offset-continued)) (ess-align-nested-calls . ,(default-value 'ess-align-nested-calls)) (ess-align-arguments-in-calls . ,(default-value 'ess-align-arguments-in-calls)) (ess-align-continuations-in-calls . ,(default-value 'ess-align-continuations-in-calls)) (ess-align-blocks . ,(default-value 'ess-align-blocks)) (ess-indent-from-lhs . (arguments)) (ess-indent-from-chain-start . ,(default-value 'ess-indent-from-chain-start)) (ess-indent-with-fancy-comments . ,(default-value 'ess-indent-with-fancy-comments))) ;; CLB added rmh 2Nov97 at request of Terry Therneau (CLB (ess-indent-offset . ,(default-value 'ess-indent-offset)) (ess-offset-arguments . ,(default-value 'ess-offset-arguments)) (ess-offset-arguments-newline . ,(default-value 'ess-offset-arguments-newline)) (ess-offset-block . ,(default-value 'ess-offset-block)) (ess-offset-continued . (straight 4)) (ess-align-nested-calls . ,(default-value 'ess-align-nested-calls)) (ess-align-arguments-in-calls . ,(default-value 'ess-align-arguments-in-calls)) (ess-align-continuations-in-calls . ,(default-value 'ess-align-continuations-in-calls)) (ess-align-blocks . ,(default-value 'ess-align-blocks)) (ess-indent-from-lhs . ,(default-value 'ess-indent-from-lhs)) (ess-indent-from-chain-start . ,(default-value 'ess-indent-from-chain-start)) (ess-indent-with-fancy-comments . ,(default-value 'ess-indent-with-fancy-comments))) (GNU (ess-indent-offset . ,(default-value 'ess-indent-offset)) (ess-offset-arguments . ,(default-value 'ess-offset-arguments)) (ess-offset-arguments-newline . (prev-call 4)) (ess-offset-block . ,(default-value 'ess-offset-block)) (ess-offset-continued . ,(default-value 'ess-offset-continued)) (ess-align-nested-calls . ,(default-value 'ess-align-nested-calls)) (ess-align-arguments-in-calls . ,(default-value 'ess-align-arguments-in-calls)) (ess-align-continuations-in-calls . ,(default-value 'ess-align-continuations-in-calls)) (ess-align-blocks . ,(default-value 'ess-align-blocks)) (ess-indent-from-lhs . ,(default-value 'ess-indent-from-lhs)) (ess-indent-from-chain-start . ,(default-value 'ess-indent-from-chain-start)) (ess-indent-with-fancy-comments . ,(default-value 'ess-indent-with-fancy-comments))) (K&R (ess-indent-offset . 5) (ess-offset-arguments . ,(default-value 'ess-offset-arguments)) (ess-offset-arguments-newline . ,(default-value 'ess-offset-arguments-newline)) (ess-offset-block . prev-call) (ess-offset-continued . ,(default-value 'ess-offset-continued)) (ess-align-nested-calls . ,(default-value 'ess-align-nested-calls)) (ess-align-arguments-in-calls . ,(default-value 'ess-align-arguments-in-calls)) (ess-align-continuations-in-calls . ,(default-value 'ess-align-continuations-in-calls)) (ess-align-blocks . ,(default-value 'ess-align-blocks)) (ess-indent-from-lhs . ,(default-value 'ess-indent-from-lhs)) (ess-indent-from-chain-start . ,(default-value 'ess-indent-from-chain-start)) (ess-indent-with-fancy-comments . ,(default-value 'ess-indent-with-fancy-comments))) ;; added ajr 17.Feb'04 to match "common R" use (== DEFAULT apart from offset = 4) (RRR (ess-indent-offset . 4) (ess-offset-arguments . ,(default-value 'ess-offset-arguments)) (ess-offset-arguments-newline . ,(default-value 'ess-offset-arguments-newline)) (ess-offset-block . ,(default-value 'ess-offset-block)) (ess-offset-continued . ,(default-value 'ess-offset-continued)) (ess-align-nested-calls . ,(default-value 'ess-align-nested-calls)) (ess-align-arguments-in-calls . ,(default-value 'ess-align-arguments-in-calls)) (ess-align-continuations-in-calls . ,(default-value 'ess-align-continuations-in-calls)) (ess-align-blocks . ,(default-value 'ess-align-blocks)) (ess-indent-from-lhs . ,(default-value 'ess-indent-from-lhs)) (ess-indent-from-chain-start . ,(default-value 'ess-indent-from-chain-start)) (ess-indent-with-fancy-comments . ,(default-value 'ess-indent-with-fancy-comments))) (RRR+ (ess-indent-offset . 4) (ess-offset-arguments . ,(default-value 'ess-offset-arguments)) (ess-offset-arguments-newline . ,(default-value 'ess-offset-arguments-newline)) (ess-offset-block . open-delim) (ess-offset-continued . ,(default-value 'ess-offset-continued)) (ess-align-nested-calls . ,(default-value 'ess-align-nested-calls)) (ess-align-arguments-in-calls . ,(default-value 'ess-align-arguments-in-calls)) (ess-align-continuations-in-calls . ,(default-value 'ess-align-continuations-in-calls)) (ess-align-blocks . ,(default-value 'ess-align-blocks)) (ess-indent-from-lhs . (arguments)) (ess-indent-from-chain-start . nil) (ess-indent-with-fancy-comments . ,(default-value 'ess-indent-with-fancy-comments))) (RStudio (ess-indent-offset . ,(default-value 'ess-indent-offset)) (ess-offset-arguments . ,(default-value 'ess-offset-arguments)) (ess-offset-arguments-newline . prev-line) (ess-offset-block . ,(default-value 'ess-offset-block)) (ess-offset-continued . ,(default-value 'ess-offset-continued)) (ess-align-nested-calls . nil) (ess-align-arguments-in-calls . ,(default-value 'ess-align-arguments-in-calls)) (ess-align-continuations-in-calls . nil) (ess-align-blocks . nil) (ess-indent-from-lhs . (arguments)) (ess-indent-from-chain-start . ,(default-value 'ess-indent-from-chain-start)) (ess-indent-with-fancy-comments . nil)) (RStudio- (ess-indent-offset . ,(default-value 'ess-indent-offset)) (ess-offset-arguments . prev-line) (ess-offset-arguments-newline . prev-line) (ess-offset-block . ,(default-value 'ess-offset-block)) (ess-offset-continued . ,(default-value 'ess-offset-continued)) (ess-align-nested-calls . nil) (ess-align-arguments-in-calls . ,(default-value 'ess-align-arguments-in-calls)) (ess-align-continuations-in-calls . nil) (ess-align-blocks . nil) (ess-indent-from-lhs . (arguments)) (ess-indent-from-chain-start . ,(default-value 'ess-indent-from-chain-start)) (ess-indent-with-fancy-comments . nil)) (DEFAULT (ess-indent-offset . ,(default-value 'ess-indent-offset)) (ess-offset-arguments . ,(default-value 'ess-offset-arguments)) (ess-offset-arguments-newline . ,(default-value 'ess-offset-arguments-newline)) (ess-offset-block . ,(default-value 'ess-offset-block)) (ess-offset-continued . ,(default-value 'ess-offset-continued)) (ess-align-nested-calls . ,(default-value 'ess-align-nested-calls)) (ess-align-arguments-in-calls . ,(default-value 'ess-align-arguments-in-calls)) (ess-align-continuations-in-calls . ,(default-value 'ess-align-continuations-in-calls)) (ess-align-blocks . ,(default-value 'ess-align-blocks)) (ess-indent-from-lhs . ,(default-value 'ess-indent-from-lhs)) (ess-indent-from-chain-start . ,(default-value 'ess-indent-from-chain-start)) (ess-indent-with-fancy-comments . ,(default-value 'ess-indent-with-fancy-comments)))) "Predefined formatting styles for ESS code. Use `ess-set-style' to apply a style in all R buffers. The values of all styles except OWN are fixed. To change the value of variables in the OWN group, customize the variable `ess-own-style-list'. DEFAULT style picks default (aka global) values from ESS indentation variables. In addition, ESS provides many indentation styles, the most important being the RRR and the RStudio variants. RRR is the common R style that adheres closely to R internal standards. RRR+ is the same except it also aligns blocks in function calls with the opening delimiter, producing more indentation. The C++ style (named like this for historical reasons rather than any resemblance to existing C++ indentation schemes) is halfway between these two styles and indent block arguments from the start of the surrounding function's name. The RStudio style closely mimics the indentation of the RStudio editor. RStudio- is the same except it does not align arguments in function calls, which corresponds to the settings of some RStudio users. ESS indentation is fully specified by the following offsets and variables. See the documentation of these variables for examples. Offsets: - `ess-indent-offset': main offset inherited by other settings - `ess-offset-arguments': offset type for function and bracket arguments - `ess-offset-arguments-newline': offset type of arguments when ( or [ is followed by a new line. - `ess-offset-block': offset type for brace and anonymous parenthesis blocks - `ess-offset-continued': offset type for continuation lines in multiline statements Overrides (implies vertical alignment): - `ess-align-nested-calls': functions whose nested calls should be aligned. - `ess-align-arguments-in-calls': calls where `ess-offset-arguments' should be ignored - `ess-align-continuations-in-calls': whether to ignore `ess-offset-continued' in calls. - `ess-align-blocks': whether to ignore `ess-offset-blocks' for function declarations or control flow statements. Control variables: - `ess-indent-from-lhs': whether to indent arguments from left-hand side of an assignment or parameter declaration. - `ess-indent-from-chain-start': whether to indent arguments from the first of several consecutive calls. - `ess-indent-with-fancy-comments': whether to indent #, ## and ### comments distinctly.") (defun ess-add-style (key entries) "Add a new style to `ess-style-list'. The new style has KEY and ENTRIES. Remove any existing entry with the same KEY before adding the new one." (setq ess-style-alist (assq-delete-all key ess-style-alist)) (add-to-list 'ess-style-alist (cons key entries))) (defcustom ess-own-style-list (cdr (assoc 'RRR ess-style-alist)) "Indentation variables for your own style. Set `ess-style' to 'OWN to use these values. To change these values, use the customize interface. See the documentation of each variable for its meaning." :group 'ess-edit :type 'alist :initialize #'custom-initialize-set :set (lambda (symbol value) (set symbol value) (ess-add-style 'OWN value))) ;;;###autoload (put 'ess-style 'safe-local-variable #'symbolp) (define-obsolete-variable-alias 'ess-default-style 'ess-style "ESS 19.04") (defcustom ess-style 'RRR "Current ESS indentation style, see `ess-style-alist' for more. See the variable `ess-style-alist' for how these groups (RRR, DEFAULT, GNU, BSD, ...) map onto different settings for variables. OWN style is defined in `ess-own-style-list' and you can customize it to your needs. DEFAULT style picks default (aka global) values from ESS indentation variables. Prefer `ess-set-style' to set the current style. This variable has an effect if set before a buffer is visited (e.g. in your Emacs initialization file) or as a file or directory local variable (see Info node `(Emacs) File Variables'." :type '(choice (const OWN) (const GNU) (const BSD) (const C++) (const CLB) (const K&R) (const RRR) (const RRR+) (const RStudio) (const RStudio-) (const DEFAULT)) :group 'ess-edit :safe #'symbolp) ;;*;; Variables controlling behavior of dump files (defcustom ess-source-directory (or (getenv "TMPDIR") (getenv "TMP") (getenv "TEMP") temporary-file-directory) "Directory in which to place dump files. This can be a string (an absolute directory name ending in a slash) or a lambda expression of no arguments which will return a suitable string value. The lambda expression is evaluated with the process buffer as the current buffer. This always dumps to a sub-directory (\".Src\") of the current ess working directory (i.e. first elt of search list)." :group 'ess-edit :type 'directory :package-version '(ess . "VERSION")) (defvar ess-dump-filename-template nil "Internal. Initialized by dialects.") (defcustom ess-dump-filename-template-proto (concat (user-login-name) ".%s.S") "Prototype template for filenames of dumped objects. The ending `S' is replaced by the current \\[ess-suffix], to give `ess-dump-filename-template' when an inferior ESS process starts. By default, gives filenames like `user.foofun.S', so as not to clash with other users if you are using a shared directory. Other alternatives: \"%s.S\" ; Don't bother uniquifying if using your own directory(ies) \"dumpdir\"; Always dump to a specific filename. This makes it impossible to edit more than one object at a time, though. (make-temp-name \"scr.\") ; Another way to uniquify" ;; MM: The last 3-4 lines above suck (I don't understand them) -- FIXME -- :group 'ess-edit :type 'string) (defcustom ess-pre-run-hook nil "Hook to call before starting up ESS. Good for setting up your directory." :group 'ess-hooks :type 'hook) (defcustom ess-post-run-hook nil "Hook to call just after the ESS process starts up. Currently this should not be used to interact with the inferior process because this hook runs too early, before the inferior mode had a chance to properly start up the process. To interact with the process, you must use a mode-specific hook like `ess-r-post-run-hook'." :group 'ess-hooks :type 'hook) (defcustom ess-send-input-hook nil "Hook called just before line input is sent to the process." :group 'ess-hooks :type 'hook) ;; ---- ./ess-roxy.el : ------------ (defcustom ess-roxy-package "roxygen2" "The name of the R package to use for Roxygen." :group 'ess-roxy :type 'string) (defcustom ess-roxy-tags-noparam '("export" "noRd") "The tags used in roxygen fields that can be used alone. Used to decide highlighting and tag completion." :group 'ess-roxy :type '(repeat string)) (defcustom ess-roxy-tags-param '("author" "aliases" "concept" "details" "examples" "format" "keywords" "method" "exportMethod" "name" "note" "param" "include" "references" "return" "seealso" "source" "docType" "title" "TODO" "usage" "import" "exportClass" "exportPattern" "S3method" "inherit" "inheritParams" "inheritSection" "importFrom" "importClassesFrom" "importMethodsFrom" "useDynLib" "rawNamespace" "rdname" "section" "slot" "description" "md" "eval" "family") "The tags used in roxygen fields that require a parameter. Used to decide highlighting and tag completion." :group 'ess-roxy :type '(repeat string)) (defcustom ess-roxy-template-alist (list (cons "description" ".. content for \\description{} (no empty lines) ..") (cons "details" ".. content for \\details{} ..") (cons "title" "") (cons "param" "") (cons "return" "") (cons "author" ess-user-full-name)) "The tags and defaults to insert when creating empty templates. Param is a place holder for where to enter parameters. Description and details do not use @ tags, but are instead placed at the beginning of the entry (and should therefore also be at the beginning of this template to give syntactically correct roxygen entries)" :group 'ess-roxy :type '(alist :key-type string :value-type string)) (defcustom ess-roxy-fill-param-p nil "When non-nil `ess-roxy-update-entry' fills (wraps) parameters." :group 'ess-roxy :type '(choice (const :tag "Off" nil) (const :tag "On" t))) (defcustom ess-roxy-hide-show-p nil "Non-nil means ess-roxy uses function `hs-minor-mode' for block hiding with TAB." :group 'ess-roxy :type '(choice (const :tag "Off" nil) (const :tag "On" t))) (defcustom ess-roxy-start-hidden-p nil "Non-nil means all blocks should be hidden from start." :group 'ess-roxy :type '(choice (const :tag "Off" nil) (const :tag "On" t))) (defcustom ess-roxy-str "##'" "Prefix string to insert before each line in new roxygen blocks. In existing roxygen blocks, the prefix is taken from the line at point" :group 'ess-roxy :type 'string) (defvar ess-roxy-insert-prefix-on-newline t "When non-nil, `ess-roxy-newline' inserts the roxy prefix on newlines.") ; System variables ;; SJE -- this should not be defcustom - user does not set it. (defvaralias 'ess-current-process-name 'ess-local-process-name) (defvar-local ess-local-process-name nil "The name of the ESS process associated with the current buffer.") (put 'ess-local-process-name 'risky-local-variable t) (put 'ess-local-process-name 'permanent-local t) (defcustom ess-switch-to-end-of-proc-buffer t "If non-nil, \\\\[ess-switch-to-inferior-or-script-buffer] goes to the end of the process buffer." :group 'ess :type 'boolean) (defcustom ess-gen-proc-buffer-name-function 'ess-gen-proc-buffer-name:project-or-simple "Function used for generation of the buffer name of the new ESS processes. It should accept one argument PROC-NAME, a string specifying internal process name (R, R:2, etc). Provided default options are: `ess-gen-proc-buffer-name:simple' *proc* `ess-gen-proc-buffer-name:directory' *proc:dir* `ess-gen-proc-buffer-name:abbr-long-directory' *proc:abbr-long-dir* `ess-gen-proc-buffer-name:project-or-simple' *proc:project-root* or *proc* `ess-gen-proc-buffer-name:project-or-directory' *proc:project-root* or *proc:dir* Strategies based on projects default to built-in strategies if there is no project root in the current directory." :group 'ess :type '(choice (const :tag "*proc*" ess-gen-proc-buffer-name:simple) (const :tag "*proc:dir*" ess-gen-proc-buffer-name:directory) (const :tag "*proc:abbr-long-dir*" ess-gen-proc-buffer-name:abbr-long-directory) (const :tag "*proc:project-root* or *proc*" ess-gen-proc-buffer-name:project-or-simple) (const :tag "*proc:project-root* or *proc:dir*" ess-gen-proc-buffer-name:project-or-directory) function) :package-version '(ess . "VERSION")) (defcustom ess-kermit-command "gkermit -T" "Kermit command invoked by `ess-kermit-get' and `ess-kermit-send'." :group 'ess :type 'string) (defcustom ess-kermit-prefix "#" "String files must begin with to use kermit file transfer." :group 'ess :type 'string) (defcustom ess-kermit-remote-directory "." "Buffer local variable that designates remote directory of file." :group 'ess :type 'string) (make-variable-buffer-local 'ess-kermit-remote-directory) ;;*;; Regular expressions (defcustom ess-dumped-missing-re "\\(<-\nDumped\n\\'\\)\\|\\(<-\\(\\s \\|\n\\)*\\'\\)" "Regex determines if dumped objects are replaced by `ess-function-template'. If a dumped object's buffer matches this re, then it is replaced by `ess-function-template'." :group 'ess :type 'regexp) (defcustom ess-dump-error-re (if (string= ess-language "S") "\nDumped\n\\'" "[Ee]rror") "Regexp used to detect an error when loading a file." :group 'ess :type 'regexp) ; ess-inf: variables for inferior-ess. (defvar inferior-ess-own-frame nil "Non-nil means that inferior ESS buffers should start in their own frame. This variable is deprecated. please add an entry to `display-buffer-alist' instead. See Info node `(ess)Customizing startup'. For example: \(add-to-list \\='display-buffer-alist \\='(\"*R\" (display-buffer-reuse-window display-buffer-pop-up-frame)))") (make-obsolete-variable 'inferior-ess-own-frame 'display-buffer-alist "ESS 19.04") (make-obsolete-variable 'inferior-ess-frame-alist "It is ignored. Use `display-buffer-alist' and `pop-up-frame-alist' instead." "ESS 19.04") (make-obsolete-variable 'inferior-ess-same-window 'display-buffer-alist "ESS 19.04") (defcustom inferior-ess-jit-lock-chunk-size 10000 "Default for (buffer local) `jit-lock-chunk-size' in inferior ESS buffers." :group 'ess-proc :type 'integer) (defvaralias 'inferior-R-program 'inferior-ess-r-program) (define-obsolete-variable-alias 'inferior-R-program-name 'inferior-ess-r-program "ESS 18.10") (define-obsolete-variable-alias 'inferior-ess-r-program-name 'inferior-ess-r-program "ESS 18.10") (defcustom inferior-ess-r-program (if ess-microsoft-p "Rterm" "R") "Program name for invoking an inferior ESS with \\[R]." :group 'ess-R :type '(choice (string) file)) (defcustom inferior-R-args "" "String of arguments used when starting R. See also `ess-R-readline'." :group 'ess-R :type 'string) (defcustom ess-R-readline nil "When non-nil, use readline in R. nil indicates that \"--no-readline \" should be used as argument when starting R. This may very slightly speedup interaction. On the other hand, readline is necessary for expansion of \"~username/\" in paths. Note that readline interprets tabs (tabular characters) in R source files as asking for file name completion. This can mess up evaluation completely." :group 'ess-R :type 'boolean) (defvaralias 'inferior-R-objects-command 'inferior-ess-r-objects-command) (defcustom inferior-ess-r-objects-command "print(objects(pos=%d, all.names=TRUE), max=1e6)\n" "Format string for R command to get a list of objects at position %d. Used in e.g., \\[ess-execute-objects] or \\[ess-display-help-on-object]." :group 'ess-command :type 'string) (defvar ess-getwd-command nil "Command string retrieving the working directory from the process.") (defvar ess-setwd-command nil "Command string to set working directory. Should contain a formatting %s to be replaced by a path (as in `setwd(%s)\\n'.") (defcustom ess-program-files ;; 32 bit version (if (and ess-microsoft-p (fboundp 'w32-short-file-name)) (if (getenv "ProgramW6432") (w32-short-file-name (getenv "ProgramFiles(x86)"));; always 32 on 64 bit OS (w32-short-file-name (getenv "ProgramFiles"))) ;; always 32 on 32 bit OS nil) "Name for 32-bit programs. Safe (no embedded blanks) 8.3 name for 32-bit programs that works across internationalization." :group 'ess :type '(choice (string) (const nil))) (defcustom ess-program-files-64 ;; 64 bit version (when (and ess-microsoft-p (fboundp 'w32-short-file-name) (getenv "ProgramW6432")) (w32-short-file-name (getenv "ProgramW6432"))) "Name for 64-bit programs. Safe (no embedded blanks) 8.3 name for 64-bit programs that works across internationalization." :group 'ess :type '(choice (string) (const nil))) (defcustom ess-directory-containing-R nil "When non-nil, a directory containing R. nil means the search for all occurrences of R on the machine will use the default location of the R directory (inside \"c:/Program Files\" in English locale Windows systems). Non-nil values mean use the specified location as the directory in which \"R/\" is located. For example, setting `ess-directory-containing-R' to \"c:\" will tell ESS to search for R versions with path names of the form \"c:/R/R-x.y.z\". Currently only used when `ess-microsoft-p'. If you change the value of this variable, you need to restart Emacs for it to take effect. It also needs to be set before you load ess-site as its value is used once only when ESS is loaded." :group 'ess :type '(choice (directory) (const nil))) (defcustom ess-rterm-version-paths nil "Stores the full path file names of Rterm versions computed via \\[ess-find-rterm]. If you have versions of R in locations other than in ../../R-*/bin/Rterm.exe or ../../rw*/bin/Rterm.exe, relative to the directory in the variable `exec-path' containing your default location of Rterm, you will need to redefine this variable with a `custom-set-variables' statement in your site-start.el or .emacs file." :group 'ess-R :type '(repeat string)) (define-obsolete-variable-alias 'inferior-S3-program-name 'inferior-S3-program "ESS 18.10") (defcustom inferior-S3-program "/disk05/s/S" "Program name for invoking an inferior ESS with S3()." :group 'ess-S :type 'string) (define-obsolete-variable-alias 'inferior-S-elsewhere-program-name 'inferior-S-elsewhere-program "ESS 18.10") (defcustom inferior-S-elsewhere-program "sh" "Program name to invoke an inferior ESS with S on a different computer." :group 'ess-proc :type 'string) (defvaralias 'S+6-dialect-name 'S+-dialect-name) (defcustom S+-dialect-name "S+" "Name of `dialect' for S-PLUS 6.x and later. Easily changeable in a user's `.emacs'." :group 'ess-SPLUS :type 'string) (define-obsolete-variable-alias 'inferior-S+-program-name 'inferior-S+-program "ESS 18.10") (defcustom inferior-S+-program (if ess-microsoft-p (concat ess-program-files "/TIBCO/splus82/cmd/Splus.exe") "Splus") "Program name to invoke S+. On Unix/Linux, use the Splus executable. On Windows, the default value is correct for a default installation of S-Plus 8.1 and with bash as the shell. For any other version or location, change this value in ess-site.el or site-start.el. Use the 8.3 version of the path name. Use double backslashes if you use the msdos shell." :group 'ess-SPLUS :type '(choice (string) (file))) (defvaralias 'inferior-S+6-start-args 'inferior-S+-start-args) (defvaralias 'inferior-Splus-args 'inferior-S+-start-args) (defcustom inferior-S+-start-args "" "String of arguments used when starting S. These arguments are currently passed only to S+6 and higher." :group 'ess-SPLUS :type 'string) (defcustom inferior-Splus-objects-command "objects(where=%d)\n" "Format string for R command to get a list of objects at position %d. Used in e.g., \\[ess-execute-objects] or \\[ess-display-help-on-object]." :group 'ess-command :type 'string) (defcustom ess-S-quit-kill-buffers-p nil "Controls whether S buffers should also be killed once a process is killed. This is used only when an iESS process is killed using \\[ess-quit]. Possible values: nil - do not kill any S buffers associated with the process. t - kill S buffers associated with the process. ask - ask the user whether the S buffers should be killed." :group 'ess-S :type '(choice (const nil) (const t) (const ask))) (define-obsolete-variable-alias 'inferior-SAS-program-name 'inferior-SAS-program "ESS 18.10") (defcustom inferior-SAS-program "sas" "Program name for invoking an inferior ESS with SAS()." :group 'ess-sas :type '(choice (string) (file))) (defvaralias 'R-editor 'ess-r-editor) (defcustom ess-r-editor "emacsclient" "Editor called by R process with `edit()' command." :group 'ess :type 'string) (defvaralias 'R-pager 'ess-r-pager) (defcustom ess-r-pager 'nil ; Usually nil is correct as ESS and page() cooperate. "Pager called by R process with `page()' command." :group 'ess :type '(choice (const nil) string)) (defcustom S-editor "emacsclient" "Editor called by S process with `edit()' command." :group 'ess :type 'string) (defcustom S-pager (if ess-microsoft-p "emacsclientw.exe" "emacsclient") "Pager called by S process with `page()' command." :group 'ess :type 'string) (defvar-local ess-editor nil "Editor command. Editor by which the process sends information to an Emacs buffer for editing and then to be returned to the process.") (defvar-local ess-pager nil "Pager by which the process sends information to an Emacs buffer.") (defvar-local inferior-ess-language-start nil "Initialization commands sent to the ESS process.") (define-obsolete-variable-alias 'inferior-ess-program-name 'inferior-ess-program "ESS 18.10") (defvar-local inferior-ess-program nil "Default program name for invoking `inferior-ess'. The other variables ...-program should be changed, for the corresponding program.") (make-obsolete-variable 'inferior-ess-start-args "Use the language specific variables like `inferior-R-args'" "ESS 19.04") (defvar inferior-ess-start-args "" "String of arguments passed to the ESS process. If you wish to pass arguments to a process, see e.g. `inferior-R-args'.") (defcustom inferior-ess-pager (if ess-microsoft-p "console" "cat") "Pager to use for reporting help files and similar things." :group 'ess-proc :type 'string) (defvar-local inferior-ess-primary-prompt "> " "Regular expression used by `ess-mode' to detect the primary prompt.") (defvar-local inferior-ess-secondary-prompt nil "Regular expression used by `ess-mode' to detect the secondary prompt. This is issued by S to continue an incomplete expression. Set to nil if language doesn't support secondary prompt.") (defvar ess-traceback-command nil "Command to generate error traceback.") ;; Need this to recognize prompts of the form + + + > > > ;; and "+ . + ", but not "Abcd. " (defvar inferior-S-prompt "[]a-zA-Z0-9.[]*[+ ]*> \\(?:[>+.] \\)*" "Regexp used in S and R inferior and transcript buffers for prompt navigation. Must not be anchored to BOL.") ;;*;; Variables controlling interaction with the ESS process (defcustom ess-execute-in-process-buffer nil "Non-nil means the ess-execute- commands output to the process buffer. Otherwise, they get their own temporary buffer." :group 'ess-proc :type 'boolean) (defcustom ess-eval-empty nil "Non-nil means `ess-eval-line*' will send empty lines to the ESS process." :group 'ess-proc :type 'boolean) (defvaralias 'ess-eval-visibly-p 'ess-eval-visibly) (defcustom ess-eval-visibly 'nowait "Non-nil means ess-eval- commands display commands in the process buffer. If \\='nowait, ESS shows input commands in the process buffer, but doesn't wait for the process. Thus all the output is printed after the input lines. If t, ESS waits after each line of the command for the process output. This results in a nice sequence of input and output but stalls Emacs on long output (like Sys.sleep(5) in R). If nil, ESS doesn't print input commands and doesn't wait for the process. This variable also affect the evaluation of input code in iESS. The effect is similar to the above. If t then ess waits for the process output, otherwise not." :group 'ess-proc :package-version '(ess . "VERSION") :type '(choice (const t) (const nowait) (const nil))) (defcustom ess-eval-deactivate-mark (fboundp 'deactivate-mark); was nil till 2010-03-22 "Non-nil means that after ess-eval- commands the mark is deactivated." :group 'ess-proc :type 'boolean) (defcustom ess-use-R-completion t "Non-nil means use R-builtin completion mechanism when available." :group 'ess-proc :type 'boolean) (defcustom ess-sleep-for-shell (if ess-microsoft-p 5 1) "Pause before sending output to the shell." :group 'ess-proc :type 'number) ; System variables ;; VS[06-04-2016]: fixme: move all inf vars into ess-inf.el. ;;*;; Variables relating to multiple processes (defvar-local ess--mode-line-process-indicator '("" ess-local-process-name) "List of ESS mode-line indicators. Local in process buffers and must start with a string. Changes of this variable are automatically reflected in mode-lines of the process and all associated with it buffers. Each symbol must evaluate to one of the standard mode line objects. See info node `(elisp)Mode Line Data'). Add a symbol with `add-to-list' and remove with `delq'. Note that the symbols which are part of this list should better have \\='risky-local-variable property set to t, otherwise the text properties are not displayed. External utilities such as `ess-tracebug' and `ess-developer' customize this variable to indicate changes in the process status.") (put 'ess--mode-line-process-indicator 'risky-local-variable t) (defvar-local ess--local-mode-line-process-indicator '("") "List of local process indicators. See `ess--mode-line-process-indicator' for how to set it. This is an internal variable used by tools like `ess-developer' and `ess-tracebug'.") (put 'ess--local-mode-line-process-indicator 'risky-local-variable t) ;;*;; Inferior ESS commands (defvar-local ess-load-command "source('%s')\n" "Dialect specific format-string for building the ess command to load a file. This format string should use %s to substitute a file name and should result in an ESS expression that will command the inferior ESS to load that file.") (defvar-local ess-eval-command nil "Dialect specific format-string for building the command to evaluate a string. It is usually faster to send a string to remote processes than a file. The latter involves Tramp and can be quite slow. When possible, a dialect should implement that command and use it preferentially. This format string should use %s as a placeholder for the string to be evaluated and, optionally, %f for the file name to be reported in the error references. The resulting command should not echo code or print any transitory output. See also `ess-eval-visibly-command' and `ess-eval-visibly-noecho-command'.") (defvar-local ess-build-eval-message-function nil "Dialect-specific function for formatting an evaluation message.") (defcustom inferior-ess-dump-command "dump(\"%s\",file=\"%s\")\n" "Format-string for building the ess command to dump an object into a file. Use first %s to substitute an object name. Use second %s to substitute the dump file name." :group 'ess-command :type 'string) (defvar-local inferior-ess-help-command "help(\"%s\")\n" "Format-string for building the ESS command to ask for help on an object. This format string should use %s to substitute an object name.") (defcustom inferior-ess-r-help-command ".ess.help('%s')\n" "Format-string for building the R command to ask for help on an object. This format string should use %s to substitute an object name. If set, changes will take effect when next R session is started." :group 'ess-command :type 'string) (defvar-local inferior-ess-exit-command "q()\n" "Format-string for building the ess command to exit. This format string should use %s to substitute an object name.") (defvar-local inferior-ess-search-list-command nil "`ess-language' command that prints out the search list; i.e. the list of directories and (recursive) objects that `ess-language' uses when it searches for objects. Really set in -customize-alist in ess[dl]-*.el") (defcustom inferior-ess-safe-names-command "tryCatch(base::print(base::names(%s), max=1e6), error=function(e){})\n" "Format string for ESS command to extract names from an object *safely*. %s is replaced by an \"object name\" -- usually a list or data frame, but in R also e.g., `package:stats'." :group 'ess-command :type 'string) ;;*;; Regular expressions (defvar-local inferior-ess-prompt nil "The regular expression used for recognizing prompts. It is always used in transcript mode. In inferior ess mode it is used only if `comint-use-prompt-regexp' is t. If not set in language's customize-alist it is constructed at run time from `inferior-ess-primary-prompt' and `inferior-ess-secondary-prompt'.") (defvar-local ess-change-sp-regexp "" "The regexp for matching the S/R/.. commands that change the search path.") (defvar ess-S+-change-sp-regexp "\\(attach(\\([^)]\\|$\\)\\|detach(\\|collection(\\|library(\\|module(\\|source(\\)" "The regexp for matching the S-plus commands that change the search path.") (defvaralias 'ess-R-change-sp-regexp 'ess-r-change-sp-regexp) (defvar ess-r-change-sp-regexp "\\(attach(\\([^)]\\|$\\)\\|detach(\\|library(\\|require(\\|source(\\)" "The regexp for matching the R commands that change the search path.") ;;*;; Process-dependent variables (defvar-local ess-sl-modtime-alist nil "Alist of modification times for all ess directories accessed this session.") (defvar-local ess-prev-load-dir/file nil "Cached value for `ess-load-file'. This symbol saves the (directory . file) pair used in the last `ess-load-file' command. Used for determining the default in the next one.") (defvar-local ess-object-list nil ;; This is a list of the currently known object names. It is ;; current only for one command entry; it exists under the ;; assumption that the list of objects doesn't change while entering ;; a command. "Cache of object names.") (defvar-local ess-help-topics-list nil ;; List of currently known help topics. "Cache of help topics.") ;;*;; Miscellaneous system variables ;; SJE: Wed 29 Dec 2004 - following 3 ess-object* variables can be removed ;; soon if no-one needs the completion code. (defvar ess-object-name-db-file "ess-namedb" "File containing definitions for `ess-object-name-db'.") (defvar ess-object-name-db-file-loaded '() "List of programs whose name-db file has been loaded.") (defvar-local ess-object-name-db nil "Alist of lists of object names, with directory names as keys. The file ess-namedb.el is loaded (if it exists) to define this variable. See also function `ess-create-object-name-db'.") ;;;*;;; Font-lock support ;; "Reserved Words" -- part 1 -- (defvar ess-RS-constants '("TRUE" "FALSE" "NA" "NULL" "Inf" "NaN")) (defvar ess-R-constants (append ess-RS-constants '("NA_integer_" "NA_real_" "NA_complex_" "NA_character_"))) (defvar ess-S-constants (append ess-RS-constants '("T" "F"))) (defvar ess-R-keywords '("if" "else" "repeat" "while" "function" "for" "in" "next" "break" "switch" "function" "return" "on.exit" "stop" ".Defunct" "tryCatch" "withRestarts" "invokeRestart" "recover" "browser") "Reserved words or special functions in the R language.") (defvar ess-S-keywords (append ess-R-keywords '("terminate"))) ;; only some of these keywords "look like functions but are not": (defvar ess-S-non-functions '("if" "for" "function" "while")) ;; first the common ones (define-obsolete-variable-alias 'ess-S-modifyiers 'ess-S-modifiers "18.10") (defvar ess-S-modifiers '("library" "attach" "detach" "source" "module" "message" "warning")) (define-obsolete-variable-alias 'ess-R-modifyiers 'ess-R-modifiers "18.10") (defvar ess-R-modifiers '("library" "attach" "detach" "source" "require" "setwd" "options" "par" "load" "rm" "message" "warning" ".Deprecated" "signalCondition" "withCallingHandlers")) (defvar ess-R-message-prefixes '("Error:" "Error in" "Warning:" "Warning in" "Warning messages")) (defvar ess-S-message-prefixes (append ess-R-message-prefixes '("Syntax error:" "Dumped"))) (defvar ess-R-assign-ops ;; don't want "=" here which is not only for assign '("<<-" "<-" "->" "->>")) (defvar ess-S-assign-ops ess-R-assign-ops) (defvar ess-R-function-name-regexp (concat "\\(" "\\sw+" "\\)" "[ \t]*" "\\(<-\\)" "[ \t\n]*" "function\\b")) (defvar ess-S-function-name-regexp ess-R-function-name-regexp) (defvar ess-font-lock-keywords nil "A name of the dialect specific font-lock keywords in the current buffer. See `ess-R-font-lock-keywords' for an example. This is an internal variable.") (defvar ess-fl-keyword:fun-calls (cons "\\(\\sw+\\)[\t ]*(" '(1 ess-function-call-face keep)) "Font lock for function calls.") (defvar ess-fl-keyword:numbers (cons "\\b\\.?[0-9]+[.eEL]?[0-9]*\\b" 'ess-numbers-face) "Font lock for numbers.") (defvar ess-fl-keyword:delimiters (cons "\\s(\\|\\s)" 'ess-paren-face) "Font lock for parenthesis.") (defvar ess-fl-keyword:= (cons "=" 'ess-paren-face) "Font lock for equal sign (=).") (defvar ess-fl-keyword:operators (cons "[-=+*> ;; Created: 01-10-2012 (ESS 12.09) ;; This file is part of GNU Emacs. ;;; License: ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see ;; ;;; Commentary: ;; start the inferior with M-x gretl. ;;; Code: (require 'compile); for compilation-* below (require 'ess-r-mode) (add-to-list 'auto-mode-alist '("\\.inp\\'" . ess-gretl-mode)) (defvar gretl-syntax-table (let ((table (make-syntax-table))) (modify-syntax-entry ?_ "w" table) ; underscores in words (modify-syntax-entry ?@ "w" table) (modify-syntax-entry ?# "<" table) ; # single-line comment start (modify-syntax-entry ?\n ">" table) ; \n single-line comment end (modify-syntax-entry ?\{ "(} " table) (modify-syntax-entry ?\} "){ " table) (modify-syntax-entry ?\[ "(] " table) (modify-syntax-entry ?\] ")[ " table) (modify-syntax-entry ?\( "() " table) (modify-syntax-entry ?\) ")( " table) (modify-syntax-entry ?\r " " table) (modify-syntax-entry ?+ "." table) (modify-syntax-entry ?- "." table) (modify-syntax-entry ?= "." table) (modify-syntax-entry ?* "." table) (modify-syntax-entry ?/ "." table) (modify-syntax-entry ?> "." table) (modify-syntax-entry ?< "." table) (modify-syntax-entry ?& "." table) (modify-syntax-entry ?| "." table) (modify-syntax-entry ?! "." table) (modify-syntax-entry ?\\ "\\" table) (modify-syntax-entry ?\' "." table) (modify-syntax-entry ?\` "w" table) (modify-syntax-entry ?\" "\"" table) (modify-syntax-entry ?. "w" table) (modify-syntax-entry ?_ "w" table) (modify-syntax-entry ?\% "." table) (modify-syntax-entry ?\# "<" table) (modify-syntax-entry ?\n ">" table) table) "Syntax table for `ess-gretl-mode'.") ;; syntax table that holds within strings (defvar ess-gretl-mode-string-syntax-table (let ((table (make-syntax-table))) table) "Syntax table for `ess-gretl-mode' that holds within strings.") (defcustom gretl-continuation-offset 4 "Extra indentation applied to Gretl continuation lines." :type 'integer :group 'ess-gretl) (defvar gretl-continuation-regexp "[^#%\n]*\\(\\\\\\|\\.\\.\\.\\)\\s-*\\(\\s<.*\\)?$") (defcustom gretl-continuation-string "\\" "Character string used for Gretl continuation lines. Normally \\." :type 'string :group 'ess-gretl) ;; (defconst gretl-string-regex ;; "\"[^\"]*?\\(\\(\\\\\\\\\\)*\\\\\"[^\"]*?\\)*\"") (defconst gretl-function-header-regexp (concat "^\\s-*\\<\\(function\\)\\>" "\\([^=;\n]*=[ \t]*\\|[ \t]*\\)\\(\\w+\\)\\>") "Regexp to match a Gretl function header. The string `function' and its name are given by the first and third parenthetical grouping.") ;; (defconst ess-function-call-regexp ;; "\\s\"?\\(\\(\\sw\\|\\s_\\)+\\(<-\\)?\\)\\s\"?*\\s-*(" ;; "Regexp for function names") (defvar gretl-command-words '("add" "adf" "anova" "append" "ar" "ar1" "arbond" "arch" "arima" "biprobit" "break" "boxplot" "chow" "clear" "coeffsum" "coint" "coint2" "corr" "corrgm" "cusum" "data" "dataset" "delete" "diff" "difftest" "discrete" "dpanel" "dummify" "duration" "elif" "else" "end" "endif" "endloop" "eqnprint" "equation" "estimate" "fcast" "foreign" "fractint" "freq" "function" "funcerr" "garch" "genr" "gmm" "gnuplot" "graphpg" "hausman" "heckit" "help" "hsk" "hurst" "if" "include" "info" "intreg" "kalman" "kpss" "labels" "lad" "lags" "ldiff" "leverage" "levinlin" "logistic" "logit" "logs" "loop" "mahal" "makepkg" "meantest" "mle" "modeltab" "modprint" "modtest" "mpols" "negbin" "nls" "normtest" "nulldata" "ols" "omit" "open" "orthdev" "outfile" "panel" "pca" "pergm" "textplot" "poisson" "print" "printf" "probit" "pvalue" "quantreg" "qlrtest" "qqplot" "quit" "rename" "reset" "restrict" "rmplot" "run" "runs" "scatters" "sdiff" "set" "setinfo" "setobs" "setmiss" "shell" "smpl" "spearman" "sprintf" "square" "sscanf" "store" "summary" "system" "tabprint" "tobit" "tsls" "var" "varlist" "vartest" "vecm" "vif" "wls" "xcorrgm" "xtab" "debug" "return" "catch" "for" "foreach" "while" "const" "3sls" "liml" "fiml" "sur" "params" "deriv" "orthog" "weights" "series" "scalar") "Commands in Gretl (these names are also reserved).") (defvar gretl-genr-functions '("abs" "sin" "cos" "tan" "asin" "acos" "atan" "sinh" "cosh" "tanh" "asinh" "acosh" "atanh" "log" "ln" "log10" "log2" "exp" "sqrt" "diff" "ldiff" "sdiff" "lags" "int" "round" "ceil" "floor" "sort" "dsort" "sortby" "ranking" "orthdev" "nobs" "firstobs" "lastobs" "uniform" "normal" "cum" "missing" "ok" "misszero" "lrvar" "quantile" "median" "gini" "zeromiss" "sum" "mean" "min" "max" "sd" "var" "sst" "cnorm" "dnorm" "qnorm" "gammafun" "lngamma" "digamma" "resample" "pnobs" "pmin" "pmax" "pmean" "psd" "hpfilt" "bkfilt" "bwfilt" "fracdiff" "boxcox" "cov" "corr" "movavg" "I" "zeros" "ones" "seq" "replace" "muniform" "mnormal" "sumc" "sumr" "meanc" "meanr" "sdc" "minc" "maxc" "minr" "maxr" "iminc" "imaxc" "iminr" "imaxr" "fft" "ffti" "cmult" "cdiv" "mcov" "mcorr" "mxtab" "cdemean" "cholesky" "psdroot" "inv" "invpd" "ginv" "diag" "transp" "vec" "vech" "unvech" "upper" "lower" "rows" "cols" "det" "ldet" "tr" "onenorm" "infnorm" "rcond" "rank" "qform" "mlag" "qrdecomp" "eigensym" "eigengen" "nullspace" "princomp" "mexp" "fdjac" "BFGSmax" "obsnum" "isseries" "isscalar" "islist" "isstring" "isnull" "nelem" "pdf" "cdf" "invcdf" "pvalue" "critical" "randgen" "urcpval" "values" "mshape" "svd" "mols" "mpols" "mrls" "mread" "mwrite" "selifc" "selifr" "polroots" "dummify" "wmean" "wvar" "wsd" "xpx" "filter" "kfilter" "ksmooth" "ksimul" "trimr" "getenv" "argname" "obslabel" "readfile" "grab" "strstr" "strncmp" "strlen" "sscanf" "varname" "varnum" "tolower" "colnames" "rownames" "ljungbox" "msortby" "lincomb" "imhof" "toepsolv" "diagcat" "xmin" "xmax" "corrgm" "mcovg" "fcstats" "bessel" "fraclag" "mreverse" "deseas" "pergm" "irr" "npv" "logistic" "weekday" "kdensity" "monthlen" "epochday" "setnote" "invmills" "polyfit" "chowlin" "varsimul" "strsplit" "inlist" "errmsg" "isconst" "irf" "inbundle") "Builtin functions for Gretl's genr command.") (defvar gretl-option-flags '("addstats" "all" "anova" "append" "arch" "arma-init" "asymptotic" "auto" "autocorr" "auxiliary" "balanced" "bartlett" "between" "bootstrap" "both" "breusch-pagan" "byobs" "by" "c" "close" "coded" "cols" "column" "comfac" "complete" "conditional" "contiguous" "continue" "continuous" "control" "covariance" "cross" "cross-section" "crt" "csv" "ct" "ctt" "cubes-only" "dat" "database" "dataset" "db" "degrees" "dhansen" "difference" "diffuse" "discrete" "dpdstyle" "drop-empty" "drop-first" "drop-last" "dummy" "dynamic" "equal" "exit" "exponential" "fcp" "fixed-effects" "from-file" "full" "func" "gamma" "geomean" "gls" "gmm" "gnu-R" "gnu-octave" "gph" "gzipped" "hausman-reg" "hessian" "hilu" "impulse-responses" "input" "inst" "integrate" "intervals" "inverse-fit" "iterate" "jackknife" "jbera" "jitter" "jmulti" "kendall" "lags" "lagselect" "lbfgs" "lillie" "liml" "linear-fit" "list" "loess-fit" "log" "loglogistic" "lognormal" "logs" "matrix" "matrix-diff" "medians" "ml" "model1" "multi" "multinomial" "nc" "next" "no-corc" "no-dates" "no-df-corr" "no-gradient-check" "no-header" "no-missing" "no-scaling" "no-stats" "normal" "normality" "notches" "numerical" "odbc" "omit-obs" "one-scale" "opg" "orthdev" "other" "out-of-sample" "output" "overwrite" "p-values" "panel" "panel-vars" "plot" "pooled" "preserve" "print-final" "progress-bar" "progressive" "pwe" "quadratic-fit" "quiet" "quit" "radians" "random" "random-effects" "rank-sum" "raw" "rc" "replace" "restrict" "restructure" "reverse" "robust" "rolling" "row" "rtf" "save" "save-all" "save-ehat" "save-xbeta" "scalars" "seasonals" "send-data" "sign" "signed-rank" "silent" "simple" "simple-print" "single-yaxis" "skip-df" "spearman" "special-time-series" "squares" "squares-only" "stacked-cross-section" "stacked-time-series" "static" "stdresid" "suppress-fitted" "swilk" "system" "t-ratios" "tall" "test-down" "tex" "time-dummies" "time-series" "to-file" "to_file" "traditional" "trend" "two-step" "unequal-vars" "uniform" "unit-weights" "variance-decomp" "vcv" "verbose" "wald" "weibull" "weights" "white" "white-nocross" "with-impulses" "with-lines" "write" "www" "x-12-arima" "y-diff-only" "z-scores" "zeros") "Gretl option flags.") (defvar gretl-internal-vars '("Fstat" "T" "ahat" "aic" "bic" "chisq" "coeff_ci" "coeff" "compan" "datatype" "df" "dwpval" "ec" "ehat" "error" "ess" "fcast" "fcerr" "gmmcrit" "hausman" "hqc" "h" "jalpha" "jbeta" "jvbeta" "kalman_llt" "kalman_lnl" "kalman_s2" "kalman_t" "kalman_uhat" "llt" "lnl" "mnlprobs" "ncoeff" "nobs" "nscan" "nvars" "obs" "pd" "pvalue" "rho" "rlnl" "rsq" "s00" "s01" "s11" "sample" "sargan" "sigma" "stderr" "stopwatch" "sysA" "sysB" "sysGamma" "t1" "t2" "test" "trsq" "uhat" "unit" "vcv" "version" "vma" "windows" "xlist" "xtxinv" "yhat" ) "Model- and dataset-related variables.") (defconst gretl-block-start-keywords (list "loop" "foreign" "function" "gmm" "if" "system" "mle" "nls" "restrict")) (defconst gretl-block-other-keywords (list "else" "elif")) (defconst gretl-block-end-keywords (list "end" "endif" "endloop")) (defvar gretl-keywords (append gretl-block-start-keywords gretl-block-other-keywords gretl-block-end-keywords '("break")) "Reserved words in Gretl.") (defun gretl-at-keyword (kw-list) ; not a keyword if used as a field name, X.word, or quoted, :word (and (or (= (point) 1) (and (not (equal (char-before (point)) ?.)) (not (equal (char-before (point)) ?:)))) (not (ess-inside-string-or-comment-p (point))) (not (ess-inside-brackets-p (point))) (member (current-word) kw-list))) (defconst gretl-font-lock-keywords (list ;; Fontify all builtin keywords. (cons (concat "\\<\\(" (regexp-opt gretl-keywords) "\\)\\>") 'font-lock-keyword-face) ;; Fontify all option flags. (cons (concat "[ \t]--\\(" (regexp-opt gretl-option-flags) "\\)") 'font-lock-constant-face) ;; Fontify all command words. (cons (concat "\\<\\(" (regexp-opt gretl-command-words) "\\)\\>") 'font-lock-builtin-face) ;; Fontify all builtin operators. (cons "\\(&\\||\\|<=\\|>=\\|==\\|<\\|>\\|!=\\|!\\)" (if (boundp 'font-lock-builtin-face) 'font-lock-builtin-face 'font-lock-preprocessor-face)) ;; Fontify all internal variables. (cons (concat "\\$\\(" (regexp-opt gretl-internal-vars) "\\)\\>") 'font-lock-variable-name-face) ;; Fontify all genr functions. (cons (concat "\\<\\(" (regexp-opt gretl-genr-functions) "\\)\\>") 'font-lock-variable-name-face) ;; Fontify all function declarations. (list gretl-function-header-regexp '(1 font-lock-keyword-face) '(3 font-lock-function-name-face nil t))) "Additional Gretl expressions to highlight.") (defvar gretl-block-begin-regexp (concat "\\<\\(" (regexp-opt gretl-block-start-keywords) "\\)\\>")) (defvar gretl-block-else-regexp (concat "\\<\\(" (regexp-opt gretl-block-other-keywords) "\\)\\>")) (defvar gretl-block-end-regexp (concat "\\<\\(" (regexp-opt gretl-block-end-keywords) "\\)\\>")) (defvar gretl-block-begin-or-end-regexp (concat gretl-block-begin-regexp "\\|" gretl-block-end-regexp)) (defvar gretl-block-else-or-end-regexp (concat gretl-block-else-regexp "\\|" gretl-block-end-regexp)) (defvar gretl-basic-offset 4) (defvar gretl-block-match-alist '(("loop" . ("endloop")) ("if" . ("else" "elif" "endif")) ("nls" . ("end")) ("mle" . ("end")) ("gmm" . ("end")) ("foreign" . ("end")) ("restrict" . ("end")) ("kalman" . ("end")) ("system" . ("end"))) "Alist with Gretl's matching block keywords. Has Gretl's begin keywords as keys and a list of the matching else or end keywords as associated values.") ; get the position of the last open block (defun gretl-last-open-block-pos (min) (let ((count 0)) (while (not (or (> count 0) (<= (point) min))) (backward-word 1) (setq count (cond ((gretl-at-keyword gretl-block-start-keywords) (+ count 1)) ((and (zerop (string-match "\\(?:e\\(?:l\\(?:if\\|se\\)\\|nd\\(?:if\\|loop\\)?\\)\\)" (current-word))) (not (ess-inside-comment-p)) (not (ess-inside-brackets-p))) (- count 1)) (t count)))) (if (> count 0) (point) nil))) (defun gretl-last-open-block (min) (let ((pos (gretl-last-open-block-pos min))) (and pos (progn (goto-char pos) (+ gretl-basic-offset (current-indentation)))))) ; return indent implied by a special form opening on the previous line, if any (defun gretl-form-indent () (forward-line -1) (end-of-line) (backward-sexp) (if (gretl-at-keyword gretl-block-other-keywords) (+ gretl-basic-offset (current-indentation)) (if (char-equal (char-after (point)) ?\() (progn (backward-word 1) (let ((cur (current-indentation))) (if (gretl-at-keyword gretl-block-start-keywords) (+ gretl-basic-offset cur) nil))) nil))) (defun gretl-indent-line () "Indent current line of gretl code." (interactive) (end-of-line) (indent-line-to (or (and (ess-inside-string-p (line-beginning-position)) 0) (save-excursion (ignore-errors (gretl-form-indent))) (save-excursion (let ((endtok (progn (beginning-of-line) (forward-to-indentation 0) (gretl-at-keyword gretl-block-end-keywords)))) (ignore-errors (+ (gretl-last-open-block (point-min)) (if endtok (- gretl-basic-offset) 0))))) ;; previous line ends in = (save-excursion (if (and (not (equal (point-min) (line-beginning-position))) (progn (forward-line -1) (end-of-line) (backward-char 1) (equal (char-after (point)) ?=))) (+ gretl-basic-offset (current-indentation)) nil)) ;; take same indentation as previous line (save-excursion (forward-line -1) (current-indentation)) 0)) (when (gretl-at-keyword gretl-block-end-keywords) (forward-word 1))) ;; (defun gretl-send-string-function (process string visibly) ;; (let ((gretl-process (get-process "gretlcli"))) ;; (process-send-string process (format ess-load-command file))) ;; (defun gretl-send-string-function (process string visibly) ;; (let ((file (concat temporary-file-directory "gretl_eval_region.inp"))) ;; (with-temp-file file ;; (insert string)) ;; (process-send-string process (format ess-load-command file)))) (defun gretl--get-words-from-command (command start-reg end-reg proc) (with-current-buffer (ess-command command nil nil nil nil proc) (goto-char (point-min)) (let ((beg (or (re-search-forward start-reg nil t) (point-min))) (end (progn (goto-char (point-max)) (or (re-search-backward end-reg) (point-max)))) acum) (goto-char beg) (skip-chars-forward "\n") (while (re-search-forward "[^ \t\n]+" end t) (push (match-string-no-properties 0) acum)) acum))) (cl-defmethod ess-help-get-topics (proc &context (ess-dialect "gretl")) (delete-dups (append gretl-command-words gretl-genr-functions gretl-block-end-keywords gretl-block-other-keywords gretl-block-start-keywords (gretl--get-words-from-command "help\n" "are:" "^For" proc) (gretl--get-words-from-command "help functions\n" "Accessors:" "^Functions" proc) (gretl--get-words-from-command "help functions\n" "^Functions" "^For" proc) ))) ;; (defvar ess-gretl-error-regexp-alist '(gretl-in gretl-at) ;; "List of symbols which are looked up in `compilation-error-regexp-alist-alist'.") ;; (add-to-list 'compilation-error-regexp-alist-alist ;; '(gretl-in "^\\s-*in [^ \t\n]* \\(at \\(.*\\):\\([0-9]+\\)\\)" 2 3 nil 2 1)) ;; (add-to-list 'compilation-error-regexp-alist-alist ;; '(gretl-at "^\\s-*\\(at \\(.*\\):\\([0-9]+\\)\\)" 2 3 nil 2 1)) (defvar gretl-customize-alist '((comint-use-prompt-regexp . t) (inferior-ess-primary-prompt . "\\? ") (inferior-ess-secondary-prompt . "\\ ") (inferior-ess-prompt . "\\? ") (ess-local-customize-alist . gretl-customize-alist) (inferior-ess-program . "gretlcli") (ess-load-command . "open \"%s\"\n") ;; (ess-dump-error-re . "in \\w* at \\(.*\\):[0-9]+") ;; (ess-error-regexp . "\\(^\\s-*at\\s-*\\(?3:.*\\):\\(?2:[0-9]+\\)\\)") ;; (ess-error-regexp-alist . ess-gretl-error-regexp-alist) ;; (inferior-ess-objects-command . inferior-gretl-objects-command) ;; (inferior-ess-search-list-command . "search()\n") ;; inferior-ess-help-command . gretl-help-command) (inferior-ess-help-command . "help %s\n") (ess-language . "gretl") (ess-dialect . "gretl") (ess-suffix . "inp") (ess-dump-filename-template . (replace-regexp-in-string "S$" ess-suffix ; in the one from custom: ess-dump-filename-template-proto)) (ess-change-sp-regexp . nil );ess-r-change-sp-regexp) (ess-help-sec-regex . ess-help-r-sec-regex) (ess-help-sec-keys-alist . ess-help-r-sec-keys-alist) (ess-function-pattern . ess-r-function-pattern) (ess-object-name-db-file . "ess-r-namedb.el" ) ;; (ess-imenu-mode-function . nil) (ess-smart-operators . ess-r-smart-operators) (inferior-ess-exit-command . "exit\n") ;;harmful for shell-mode's C-a: -- but "necessary" for ESS-help? (inferior-ess-language-start . nil) (ess-STERM . "iESS") ) "Variables to customize for Gretl -- set up later than Emacs initialization.") ;; (defcustom inferior-gretl-program "gretlcli" ;; "*The program to use for running gretl scripts." ;; :type 'string ;; :group 'ess-gretl) ;; (defvar ess-gretl-versions '("gretcli") ;; "List of partial strings for versions of Julia to access within ESS. ;; Each string specifies the start of a filename. If a filename ;; beginning with one of these strings is found on `exec-path', a M-x ;; command for that version of Julia is made available. ") (defcustom inferior-gretl-args "" "String of arguments used when starting gretl." :group 'ess-gretl :type 'string) ;;;###autoload (define-derived-mode ess-gretl-mode ess-mode "ESS[gretl]" "Major mode for editing gretl source. See `ess-mode' for more help." ;;(setq imenu-generic-expression R-imenu-generic-expression) (ess-setq-vars-local gretl-customize-alist) (setq font-lock-defaults `(,gretl-font-lock-keywords)) (setq-local paragraph-start (concat "\\s-*$\\|" page-delimiter)) (setq-local paragraph-separate (concat "\\s-*$\\|" page-delimiter)) (setq-local paragraph-ignore-fill-prefix t) (setq-local comment-start "# ") (setq-local comment-add 1) (setq-local comment-start-skip "\\s<+\\s-*") (setq-local comment-column 40) (setq-local indent-line-function #'gretl-indent-line) (setq-local ess-local-customize-alist gretl-customize-alist) (when (fboundp 'ess-add-toolbar) (ess-add-toolbar))) (defvar ess-gretl-post-run-hook nil "Functions run in process buffer after Gretl starts.") ;;;###autoload (defun gretl (&optional start-args) "Call `gretl', Optional prefix (C-u) allows to set command line arguments, such as --vsize. This should be OS agnostic. If you have certain command line arguments that should always be passed to gretl, put them in the variable `inferior-gretl-args'." (interactive "P") ;; get settings, notably inferior-ess-r-program : ;; (if (null inferior-gretl-program) ;; (error "'inferior-gretl-program' does not point to 'gretl-release-basic' executable") (ess-write-to-dribble-buffer ;; for debugging only (format "\n(Gretl): ess-dialect=%s, buf=%s" ess-dialect (current-buffer))) (let* ((r-start-args (concat inferior-gretl-args " " ; add space just in case (if start-args (read-string (concat "Starting Args [other than `" inferior-gretl-args "'] ? ")) nil))) (inf-buf (inferior-ess r-start-args gretl-customize-alist))) (setq-local indent-line-function #'gretl-indent-line) (setq-local gretl-basic-offset 4) (setq indent-tabs-mode nil) (goto-char (point-max)) ;; (if inferior-ess-language-start ;; (ess-eval-linewise inferior-ess-language-start ;; nil nil nil 'wait-prompt))) (with-current-buffer inf-buf (run-mode-hooks 'ess-gretl-post-run-hook)) inf-buf)) ;;;; IMENU ;; (defvar gretl-imenu-generic-expression ;; '(("Function (_)" "^\\s-*function\\s-+\\(_[^ \t\n]*\\)" 1) ;; ("Function" "^\\s-*function\\s-+\\([^_][^ \t\n]*\\)" 1) ;; ("Const" "^\\s-*const \\([^ \t\n]*\\)" 1) ;; ("Type" "^\\s-*\\w*type\\w* \\([^ \t\n]*\\)" 1) ;; ("Load" " *\\(load\\)(\\([^ \t\n)]*\\)" 2) ;; ;; ("Classes" "^.*setClass(\\(.*\\)," 1) ;; ;; ("Coercions" "^.*setAs(\\([^,]+,[^,]*\\)," 1) ; show from and to ;; ;; ("Generics" "^.*setGeneric(\\([^,]*\\)," 1) ;; ;; ("Methods" "^.*set\\(Group\\|Replace\\)?Method(\"\\(.+\\)\"," 2) ;; ;; ;;[ ]*\\(signature=\\)?(\\(.*,?\\)*\\)," 1) ;; ;; ;; ;; ;; ;;("Other" "^\\(.+\\)\\s-*<-[ \t\n]*[^\\(function\\|read\\|.*data\.frame\\)]" 1) ;; ;; ("Package" "^.*\\(library\\|require\\)(\\(.*\\)," 2) ;; ;; ("Data" "^\\(.+\\)\\s-*<-[ \t\n]*\\(read\\|.*data\.frame\\).*(" 1))) ;; )) ;; (defun ess-imenu-gretl (&optional arg) ;; "Gretl Language Imenu support for ESS." ;; (interactive) ;; (setq imenu-generic-expression gretl-imenu-generic-expression) ;; (imenu-add-to-menubar "Imenu-gretl")) ;; (defun ess-imenu-gretl (&optional arg) ;; "Gretl Language Imenu support for ESS." ;; (interactive) ;; (setq imenu-generic-expression gretl-imenu-generic-expression) ;; (imenu-add-to-menubar "Imenu-jl")) (provide 'ess-gretl) ;;; ess-gretl.el ends here ESS-24.01.1/lisp/ess-help.el000066400000000000000000001073431455642170100153370ustar00rootroot00000000000000;;; ess-help.el --- Support for viewing ESS help files -*- lexical-binding: t; -*- ;; Copyright (C) 1989-2022 Free Software Foundation, Inc. ;; Author: David Smith ;; Created: 7 Jan 1994 ;; Maintainer: ESS-core ;; This file is part of GNU Emacs. ;;; License: ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see ;; ;;; Commentary: ;; Code for dealing with ESS help files. See README. where ;; is one of `S', `SAS', `Stata' or `XLispStat'. ;;; Code: ; Requires and autoloads (require 'cl-lib) (eval-when-compile (require 'tramp)) (require 'info) (require 'ess-mode) (require 'ess-inf) (require 'ess-utils) (require 'ansi-color) (declare-function ess-r-help-mode "ess-r-mode") (declare-function ess-stata-help-mode "ess-stata-lang") (defcustom ess-help-mode-hook nil "Functions to call when entering `ess-help-mode'." :group 'ess-hooks :type 'hook) (defvar ess--help-frame nil "Stores the frame used for displaying R help buffers.") (defvar ess-help--aliases-timeout 10 "The large timeout is necessary for some users (#1025, #1081).") ; ess-help-mode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; In this section: ;;;; ;;;; * The function ess-display-help-on-object ;;;; * The major mode ess-help-mode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (cl-defgeneric ess--help-major-mode () "Determine which help major mode to call, and call it. Uses `ess-dialect' to determine the appropriate help mode." (ess-help-mode)) (defun ess--help-get-bogus-buffer-substring (buffer &optional nr-first) "Return non-nil if BUFFER looks like a bogus ESS help buffer. Return the pair (match-beg. match-end) which can be used in error message. NR-FIRST is the number of characters at the start of the buffer to examine when deciding if the buffer if bogus. If nil, the first 150 characters of the buffer are searched." (if (not nr-first) (setq nr-first 150)) (with-current-buffer buffer (let ((PM (point-min)) (case-fold-search t) searching res) (setq res (or ;; evaluate up to first non-nil (or end): (< (- (point-max) PM) 80); buffer less than 80 chars (not (setq searching t)) ;; todo: move to customize-alist (progn (goto-char PM) ;; R: (re-search-forward "Error in help" nr-first t)) (progn (goto-char PM) ;; S-plus 5.1 : (re-search-forward "^cat: .*--" nr-first t)) (progn (goto-char PM) ;; S version 3 ; R : (re-search-forward "no documentation .+" nr-first t)) (progn (goto-char PM) ;; stata (re-search-forward "^help .*not found" nr-first t)))) (ess-write-to-dribble-buffer (format " |--> %s [searching %s]\n" res searching)) (when res (if searching (buffer-substring (match-beginning 0) (match-end 0)) (buffer-string)))))) (defun ess-help-get-local-help-buffers () (ess-force-buffer-current) (cl-remove-if-not (lambda (buffer) (let* ((pattern (concat "*help[" ess-current-process-name "](")) (name (buffer-name buffer)) (candidate (when (> (length name) (length pattern)) (substring name 0 (length pattern))) )) (when (string= pattern candidate) buffer))) (buffer-list))) (defvar-local ess-help-type nil "Type of help file, help, index, vignettes etc. Local in `ess-help' buffers.") (defvar-local ess-help-object nil "Name of the object the help is displayed for. Is name of the package for package index. Local in `ess-help' buffers.") (put 'ess-help-object 'permanent-local t) (defun ess-display-help-on-object (object &optional command) "Display documentation for OBJECT. If prefix ARG is given, force an update of the cached help topics and query the ESS process for the help file instead of reusing an existing buffer if it exists. Uses the variable `inferior-ess-help-command' for the actual help command. Prompts for the object name based on the cursor location for all cases except the S-Plus GUI. With S-Plus on Windows (both GUI and in an inferior Emacs buffer) the GUI help window is used. If COMMAND is supplied, it is used instead of `inferior-ess-help-command'." (interactive (progn (ess-force-buffer-current) (when current-prefix-arg (ess-help--reset-cache)) (list (ess-find-help-file "Help on")))) (let* ((hb-name (concat "*help[" ess-current-process-name "](" (replace-regexp-in-string "^\\?\\|`" "" object) ")*")) (old-hb-p (get-buffer hb-name)) (tbuffer (get-buffer-create hb-name))) (when (or (not old-hb-p) (ess-process-get 'sp-for-help-changed?) (ess--help-get-bogus-buffer-substring old-hb-p)) (ess-with-current-buffer tbuffer (ess--flush-help-into-current-buffer object command) (setq ess-help-object object) (ess--help-major-mode) (setq truncate-lines nil ess-help-type 'help))) (unless (ess--help-kill-bogus-buffer-maybe tbuffer) (ess-display-help tbuffer)))) (defun ess-help--reset-cache () "Reset all cached help files." (ess-process-put 'sp-for-help-changed? t) (ess-help--reset-cache-override)) (cl-defgeneric ess-help--reset-cache-override ()) (defun ess-help-revert-buffer (_ignore-auto _noconfirm) "Revert the current help buffer. This reloads the documentation. IGNORE-AUTO and NOCONFIRM are ignored." (ess-process-put 'sp-for-help-changed? t) (ess-display-help-on-object ess-help-object)) (defalias 'ess-help #'ess-display-help-on-object) (cl-defgeneric ess-build-help-command (object) "Build a string command for retrieving help on OBJECT." (format inferior-ess-help-command object)) (defun ess--flush-help-into-current-buffer (object &optional command) (let ((inhibit-modification-hooks t) (inhibit-read-only t)) (delete-region (point-min) (point-max)) (let ((command (if (and command (string-match-p "%s" command)) (format command object) command))) (ess-command (or command (ess-build-help-command object)) (current-buffer))) (ess-help-underline) (unless (string= ess-language "STA") (ess-nuke-help-bs)) (goto-char (point-min)) (set-buffer-modified-p 'nil))) (defun ess--help-kill-bogus-buffer-maybe (buffer) "Internal, try to kill bogus BUFFER with message. Return t if killed." (when ess-help-kill-bogus-buffers (let ((bog-mes (ess--help-get-bogus-buffer-substring buffer))) (when bog-mes ;; The following is giving erroneous messages when help is displayed in the browser ;; (when (< (length bog-mes) 10) ;;no message at all, how to treat this properly? ;; (setq bog-mes (format "No documentation found; %s" bog-mes))) (ess-write-to-dribble-buffer (format "(ess-help: kill bogus buffer %s ..\n" (buffer-name buffer))) (message "%s" (replace-regexp-in-string "\n" "" bog-mes)) ;; (ding) ;; don't ding, in julia a lot of doc strings are very short (kill-buffer buffer))))) (defun ess-display-help-in-browser () "Displaying HTML help where available, using \\[browse-url]." (interactive) (unless (string-match "^R" ess-dialect) (user-error "Sorry, not implemented for %s " ess-dialect)) (if (or (not ess-help-object) (not (eq ess-help-type 'help))) (message "No help topic found") (ess-command (format "help('%s', help_type='html')\n" ess-help-object)))) (defun ess--button-action (&optional button) "Provide help on object at the beginning of line. It's intended to be used in R-index help pages. Load the package if necessary. It is bound to RET and C-m in R-index pages." (let* ((string (button-label button)) (command (ess-build-help-command string))) (ess-display-help-on-object string command))) (cl-defgeneric ess-help-commands () "Return an alist of dialect specific retriever commands. Currently understood commands: - package-for-object - command to get the package of current help object - packages - command to get a list of available packages (REQUIRED) - package-index - command to get the package index (REQUIRED) - index-keyword-reg - regexp used to find keywords for linking in index listing only (1st subexpression is used) - index-start-reg - regexp from where to start searching for keywords in index listing" (user-error "Not implemented for %s " ess-dialect)) (cl-defmethod ess-help-commands (&context (ess-dialect "R")) '((package-for-object . "sub('package:', '', .ess.findFUN('%s'))\n") (packages . ".packages(all.available=TRUE)\n") (package-index . ".ess.help(package='%s', help.type='text')\n") (index-keyword-reg . "^\\([^ \t\n:]+\\)") (index-start-reg . "^Index:"))) (defun ess-display-package-index (&optional package) "Prompt for package name and display its index." (interactive (list (let* ((coms (ess-help-commands)) (all-packs (ess-get-words-from-vector (cdr (assoc 'packages coms)))) (pack (or (when (and ess-help-object (cdr (assoc 'package-for-object coms)) (eq ess-help-type 'help)) (car (ess-get-words-from-vector (format (cdr (assoc 'package-for-object coms)) ess-help-object)))) (car (member (ess-read-object-name-default) all-packs))))) (ess-completing-read "Index of" all-packs nil nil nil nil pack)))) (let ((coms (ess-help-commands))) (ess--display-indexed-help-page (format (cdr (assoc 'package-index coms)) package) (cdr (assoc 'index-keyword-reg coms)) (format "*help[%s](index:%s)*" ess-dialect package) 'index nil nil (cdr (assoc 'index-start-reg coms)) package))) (defun ess--display-indexed-help-page (command item-regexp title help-type &optional action help-echo reg-start help-object) "Internal function to display help pages with linked actions. COMMAND to produce the indexed help page, ITEM-REGEXP -- first subexpression is highlighted, TITLE of the help page, HELP-TYPE to be stored in `ess-help-type' local variable, ACTION is a function with no argument (default is `ess--button-action'), HELP-ECHO if given becomes the help-echo property of the button, REG-START gives the start location from where to search linkifying, and HELP-OBJECT becomes `ess-help-object'." (let ((inhibit-modification-hooks t) (alist ess-local-customize-alist) (pname ess-local-process-name) (buff (get-buffer-create title))) (ess-with-current-buffer buff (setq buffer-read-only nil) (delete-region (point-min) (point-max)) (setq ess-local-process-name pname) (ess--help-major-mode) (ess-setq-vars-local (eval alist t)) (setq ess-help-object help-object ess-help-sec-regex "\\(^\\s-.*\n\\)\\|\\(^\n\\)") (ess--foreground-command command buff) (ess-help-underline) (set-buffer-modified-p 'nil) (goto-char (point-min)) (when reg-start ;; go to the beginning of listing (re-search-forward reg-start nil t)) (when item-regexp ;;linkify the buffer (save-excursion (while (re-search-forward item-regexp nil t) (make-text-button (match-beginning 1) (match-end 1) 'mouse-face 'highlight 'action (or action #'ess--button-action) 'help-object (buffer-substring-no-properties (match-beginning 1) (match-end 1)) 'follow-link t 'help-echo (or help-echo "help on object"))))) (save-excursion ;; why R help adds all these spaces? (goto-char (point-min)) (when (re-search-forward "Index:\n\n" nil t) (let ((beg (point))) (forward-paragraph 1) (align-regexp beg (point) "\\(\\s-+\\)")))) (setq buffer-read-only t) (setq ess-help-type help-type) (setq truncate-lines nil)) (unless (ess--help-kill-bogus-buffer-maybe buff) (ess-display-help buff)))) (defun ess-display-help-apropos (&optional pattern) "Create an ess-apropos buffer with a *linked* list of apropos topics." (interactive "sPattern: ") (let (com regexp) (cond ((equal ess-dialect "R") (setq com "help.search('%s')\n" regexp "^\\([^ \t\n:]+::[^ \t\n:]+\\)[ \t\n]+")) ((equal ess-dialect "julia") (setq com "apropos(\"%s\")\n" regexp "^\\(\\(\\w\\|\\s_\\)+\\)(")) ((equal ess-dialect "stata") (setq com "hsearch %s\n" regexp "^[\t ]*[0-9]+\\.[\t ]+\\(.+\\)$")) (t (error "Not implemented for dialect %s" ess-dialect))) (ess--display-indexed-help-page (format com pattern) regexp (format "*ess-apropos[%s](%s)*" ess-current-process-name pattern) 'apropos))) (defun ess-display-demos () "Create an ess-demos buffer with a *linked* list of available demos." (interactive) (let (com regexp) (cond ((equal ess-dialect "R") (setq com "demo()\n" regexp "^\\([^ \n:]+\\) +")) (t (error "Not implemented for dialect %s" ess-dialect))) (ess--display-indexed-help-page com regexp (format "*ess-demos[%s]*" ess-current-process-name) 'demos #'ess--action-demo))) (defun ess--action-demo (&optional button) "Provide help on object at the beginning of line. It's intended to be used in R-index help pages. Load the package if necessary. It is bound to RET and C-m in R-index pages." (let* ((string (button-label button)) (command (cond ((equal ess-dialect "R") (format "demo('%s')\n" string)) (t (error "Not implemented for dialect %s" ess-dialect))))) (ess-eval-linewise command) (ess-switch-to-end-of-ESS))) (defun ess-display-vignettes (&optional all) "Display vignettes if available for the current dialect. With (prefix) ALL non-nil, use `vignette(*, all=TRUE)`, i.e., from all installed packages, which can be *very* slow." (interactive "P") (ess--display-vignettes-override all)) (cl-defgeneric ess--display-vignettes-override (_all) "Display vignettes for the current dialect. See `ess-display-vignettes' for ALL." (user-error "Sorry, not implemented for %s" ess-dialect)) (defun ess--action-open-in-emacs (pos) (display-buffer (find-file-noselect (get-text-property pos 'help-echo)))) (defun ess--action-R-open-vignette (pos) (ess-eval-linewise (format "vignette('%s', package='%s')\n" (get-text-property pos 'vignette) (get-text-property pos 'package)))) (defalias 'ess-help-quit #'quit-window) (make-obsolete 'ess-help-quit 'quit-window "16.04") (defun ess-display-help (buff) "Display buffer BUFF. If `ess-help-pop-to-buffer' is non-nil, call `pop-to-buffer', otherwise call `display-buffer' to display the buffer. You may control how help buffers are displayed by EITHER setting an entry in `display-buffer-alist' (see examples in info node `(ess) Controlling buffer display') OR setting the ESS-specific variables `ess-help-own-frame', `ess-help-reuse-window', `ess-help-frame-alist', and `ess-display-buffer-reuse-frames'." (let* ((action (cond (ess-help-own-frame '(display-buffer-reuse-window display-buffer-use-some-frame display-buffer-pop-up-frame)) (ess-help-reuse-window '(display-buffer-reuse-window ess-display-buffer-reuse-mode-window display-buffer-pop-up-window display-buffer-use-some-window)) (t '(display-buffer-pop-up-window display-buffer-use-some-window)))) (alist `((mode . (ess-help-mode ess-r-help-mode ess-stata-help-mode ess-julia-help-mode)) (reusable-frames . ,ess-display-buffer-reuse-frames) ;; `display-buffer-use-some-frame' uses this to ;; determine whether to use the frame or not. (frame-predicate . (lambda (f) (when (equal ess-help-own-frame 'one) ;; Note we're always returning ;; nil for `ess-help-own-frame' t. (frame-parameter f 'ess-help-frame)))) ;; If `display-buffer' makes a new frame, these are ;; given as frame parameters. (pop-up-frame-parameters . ,(append ess-help-frame-alist `((auto-hide-function . delete-frame) (ess-help-frame . ,(equal ess-help-own-frame 'one))))))) (display-alist `(,action . ,alist))) (if ess-help-pop-to-buffer (pop-to-buffer buff display-alist) (display-buffer buff display-alist)))) (defun ess-help-web-search (cmd) "Search the web for documentation on CMD." (interactive "sSearch for: ") (ess--help-web-search-override cmd)) (cl-defgeneric ess--help-web-search-override (_cmd) "Dialect-specific override for `ess-help-web-search', which see for CMD." (error "Not implemented for %s" ess-dialect)) (defun ess-manual-lookup () "Search manual for documentation." (interactive) (ess--manual-lookup-override)) (cl-defgeneric ess--manual-lookup-override () "Dialect-specific override for `ess-manual-lookup'." (error "Not implemented for %s" ess-dialect)) (defvar ess-doc-map (let (ess-doc-map) (define-prefix-command 'ess-doc-map) (define-key ess-doc-map "\C-e" #'ess-describe-object-at-point) (define-key ess-doc-map "e" #'ess-describe-object-at-point) (define-key ess-doc-map "\C-d" #'ess-display-help-on-object) (define-key ess-doc-map "d" #'ess-display-help-on-object) (define-key ess-doc-map "\C-i" #'ess-display-package-index) (define-key ess-doc-map "i" #'ess-display-package-index) (define-key ess-doc-map "\C-a" #'ess-display-help-apropos) (define-key ess-doc-map "a" #'ess-display-help-apropos) (define-key ess-doc-map "\C-v" #'ess-display-vignettes) (define-key ess-doc-map "v" #'ess-display-vignettes) (define-key ess-doc-map "\C-o" #'ess-display-demos) (define-key ess-doc-map "o" #'ess-display-demos) (define-key ess-doc-map "\C-w" #'ess-help-web-search) (define-key ess-doc-map "w" #'ess-help-web-search) (define-key ess-doc-map "\C-m" #'ess-manual-lookup) (define-key ess-doc-map "m" #'ess-manual-lookup) ess-doc-map) "ESS documentation map.") (defvar ess-help-mode-map (let ((map (make-keymap))) (define-key map "\C-m" #'next-line) (define-key map "h" #'ess-display-help-on-object) (define-key map "w" #'ess-display-help-in-browser) (define-key map "i" #'ess-display-package-index) (define-key map "a" #'ess-display-help-apropos) (define-key map "v" #'ess-display-vignettes) (define-key map "l" #'ess-eval-line-visibly-and-step) (define-key map "r" #'ess-eval-region-and-go) (define-key map "f" #'ess-eval-function-or-paragraph-and-step) (define-key map "n" #'ess-skip-to-next-section) (define-key map "p" #'ess-skip-to-previous-section) (define-key map "/" #'isearch-forward) (define-key map "x" #'ess-kill-buffer-and-go) (define-key map "k" #'kill-this-buffer) (define-key map "\C-c\C-s" #'ess-switch-process) (define-key map "\C-c\C-r" #'ess-eval-region) (define-key map "\C-c\M-r" #'ess-eval-region-and-go) (define-key map "\C-c\C-f" #'ess-eval-function) (define-key map "\M-\C-x" #'ess-eval-function) (define-key map "\C-c\M-f" #'ess-eval-function-and-go) (define-key map "\C-c\C-j" #'ess-eval-line) (define-key map "\C-c\C-n" #'ess-eval-line-visibly-and-step) (define-key map "\C-c\C-c" #'ess-eval-region-or-function-or-paragraph-and-step) (define-key map [(control return)] #'ess-eval-region-or-line-visibly-and-step) (define-key map "\C-c\M-j" #'ess-eval-line-and-go) (define-key map "\M-\C-a" #'ess-goto-beginning-of-function-or-para) (define-key map "\M-\C-e" #'ess-goto-end-of-function-or-para) (define-key map "\C-c\C-y" #'ess-switch-to-ESS) (define-key map "\C-c\C-z" #'ess-switch-to-end-of-ESS) (define-key map "\C-c\C-l" #'ess-load-file) (define-key map "\C-c\M-l" #'ess-load-file); alias, as in #'iESS#' where C-c C-l is comint-list-* (define-key map "\C-c\C-v" #'ess-display-help-on-object) (define-key map "\C-c\C-k" #'ess-request-a-process) (define-key map "\C-c\C-d" 'ess-doc-map) (define-key map "\C-c\C-e" 'ess-extra-map) (define-key map "\C-c\C-t" 'ess-dev-map) map) "Keymap for ESS help mode.") ;; One reason for the following menu is to the user about key strokes (defvar ess-help-mode-menu '("ESS-help" ["Search forward" isearch-forward t] ["Next section" ess-skip-to-next-section t] ["Previous section" ess-skip-to-previous-section t] ["Help on section skipping" ess-describe-sec-map t] ["Beginning of buffer" beginning-of-buffer t] ["End of buffer" end-of-buffer t] "-" ["Help on ..." ess-display-help-on-object t] ["Apropos of ..." ess-display-help-apropos t] ["Index of ..." ess-display-package-index t] ["Vignettes" ess-display-vignettes t] ["Open in browser" ess-display-help-in-browser t] "-" ["Eval line" ess-eval-line-and-step t] ["Eval paragraph & step" ess-eval-paragraph-and-step t] ["Eval region & go" ess-eval-region-and-go t] ["Switch to ESS process" ess-switch-to-ESS t] ["Switch to end of ESS proc." ess-switch-to-end-of-ESS t] ["Switch _the_ process" ess-switch-process t] "-" ["Kill buffer" kill-this-buffer t] ["Kill buffer & go" ess-kill-buffer-and-go t] "-" ["Handy commands" ess-handy-commands t]) "Menu used in ess-help mode.") (easy-menu-define ess-help-mode-menu-map ess-help-mode-map "Menu keymap for ess-help mode." ess-help-mode-menu) (define-derived-mode ess-help-mode special-mode "ESS Help" "Mode for viewing ESS help files." :group 'ess-help ;; FIXME ;; (if ess-mode-syntax-table ;;set in advance by ess-setq-local ;; (set-syntax-table ess-mode-syntax-table)) (setq-local revert-buffer-function #'ess-help-revert-buffer) (setq show-trailing-whitespace nil)) ;;*;; User commands defined in ESS help mode (defun ess-skip-to-help-section () "Jump to a section heading of a help buffer. The section selected is determined by the command letter used to invoke the command, as indicated by `ess-help-sec-keys-alist'. Use \\[ess-describe-sec-map] to see which keystrokes find which sections." (interactive) (let ((old-point (point)) (case-fold-search nil) (the-sec (cdr (assoc last-command-event ess-help-sec-keys-alist)))) (cl-assert the-sec nil (format "Invalid section key: %c" last-command-event)) (goto-char (point-min)) (if (re-search-forward (concat "^" the-sec) nil t) (progn (recenter) (beginning-of-line)) (message "No %s section in this help. Sorry." the-sec) (goto-char old-point)))) (defun ess-skip-to-next-section () "Jump to next section in ESS help buffer." (interactive) (let ((case-fold-search nil)) (when (looking-at-p ess-help-sec-regex) (forward-line)) (if (re-search-forward ess-help-sec-regex nil 'no-error) (beginning-of-line) (message "No more sections.")))) (defun ess-skip-to-previous-section () "Jump to previous section in ESS help buffer." (interactive) (let ((case-fold-search nil)) (if (re-search-backward ess-help-sec-regex nil 'no-error) (beginning-of-line) (message "No previous section.")))) (defun ess-kill-buffer-and-go nil "Kill the current buffer and switch back to the ESS process." (interactive) (kill-buffer (current-buffer)) (when (and ess-current-process-name (get-process ess-current-process-name)) (ess-switch-to-ESS nil))) (defun ess-describe-sec-map nil "Display help for the `s' key." (interactive) (let ((keys-alist ess-help-sec-keys-alist)) (describe-function 'ess-skip-to-help-section) (with-current-buffer "*Help*" (setq buffer-read-only nil) (goto-char (point-max)) (insert "\n\nCurrently defined keys are: Keystroke Section --------- -------\n") (dolist (cs keys-alist) (insert " " (car cs) " " (cdr cs) "\n"))))) (defun ess-helpobjs-at-point--read-obj () (let* ((obj (ess-read-object-name-default))) ;; Exclude numbers (unless (and obj (not (string-match "[[:alpha:]]" obj))) obj))) (defun ess-unqualify-symbol (object) (if (string-match "^[[:alnum:].]+::?" object) (substring object (match-end 0)) object)) (defun ess-helpobjs-at-point (slist) "Return a list (def obj fun). Obj is a name at point, fun is the name of the function call point is in, and def is either obj or fun (in that order) which has a a help file, i.e. it is a member of SLIST (string-list). nil otherwise." (let* ((obj (ess-helpobjs-at-point--read-obj)) (unqualified-obj (and obj (ess-unqualify-symbol obj))) ;; FIXME: probably should use syntactic logic here (fun (ignore-errors (save-excursion (save-restriction (narrow-to-region (max (point-min) (- (point) 1000)) (point-max)) (backward-up-list 1) (backward-char 1) (ess-read-object-name-default)))))) (list (or (car (member obj slist)) (when (member unqualified-obj slist) obj) (car (member fun slist))) obj fun))) (cl-defgeneric ess-help-get-topics (proc) "Return a list of help topics from PROC." (user-error "Not supported for %s (process: %s)" ess-dialect proc)) (defun ess-find-help-file (p-string) "Find help, prompting for P-STRING." (ess-make-buffer-current) (let* ((help-files-list (ess-help-get-topics ess-current-process-name)) (hlpobjs (delq nil (ess-helpobjs-at-point help-files-list)))) (ess-completing-read p-string (append hlpobjs help-files-list) nil nil nil nil (car hlpobjs)))) ;;*;; Utility functions (defun ess-get-help-files-list () "Return a list of files which have help available." (apply #'nconc (mapcar (lambda (str) (let ((dirname (concat str "/.Help"))) (and (file-directory-p dirname) (directory-files dirname)))) (ess-search-list)))) (defun ess-get-help-aliases-list () "Return a list of aliases which have help available." (message "Retrieving RDS aliases...") ;; ess-command locks display, make sure the above message is visible (redisplay t) (ess-write-to-dribble-buffer "Processing RDS files ...\n") ;; FIXME: This should be run asynchronously (prog1 (ess-get-words-from-vector ".ess.getHelpAliases()\n" nil nil nil ess-help--aliases-timeout) (message "Retrieving RDS aliases...done"))) (defun ess-nuke-help-bs () "Remove ASCII underlining and overstriking performed by ^H codes." ;; This function is a modification of nuke-nroff-bs in man.el from the ;; standard Emacs 18 lisp library. ;; Nuke underlining and overstriking (only by the same letter) (goto-char (point-min)) (while (search-forward "\b" nil t) (let* ((preceding (char-after (- (point) 2))) (following (following-char))) (cond ((= preceding following) ;; x\bx (delete-char -2)) ((= preceding ?\_) ;; _\b (delete-char -2)) ((= following ?\_) ;; \b_ (delete-region (1- (point)) (1+ (point))))))) (goto-char (point-min)) (let ((case-fold-search nil)); 'URL' != 'url' ('libcurl: ' on ?capabilities) (while (re-search-forward "\\bURL: " nil t); test with ?rtags ;; quick fix for C-x f confusion (getting into tramp) (delete-region (match-beginning 0) (match-end 0)))) ;; Crunch blank lines (goto-char (point-min)) (while (re-search-forward "\n\n\n\n*" nil t) (replace-match "\n\n")) ;; Nuke blanks lines at start. (goto-char (point-min)) (skip-chars-forward "\n") (delete-region (point-min) (point))) (defun ess-help-underline () "Replace _^H codes with underline face." (save-excursion (goto-char (point-min)) (while (search-forward "_" nil t) (backward-delete-char 2) (put-text-property (point) (1+ (point)) 'face 'underline)))) ;;*;; Link to Info (defun ess-goto-info (node) "Display node NODE from `ess-mode' info." (require 'info) (split-window) (Info-goto-node (concat "(ess)" node))) ;; describe object at point (defvar-local ess-describe-object-at-point-commands nil "Commands cycled by `ess-describe-object-at-point'. Dialect specific.") (defvar ess--descr-o-a-p-commands nil) (defun ess-describe-object-at-point () "Get info for object at point, & display it in an electric buffer or tooltip. If region is active use it instead of the object at point. This is an electric command (`ess--execute-electric-command'), which means that you can use the last key to cycle through the action set (in this case `C-e'). After invocation of this command all standard Emacs commands, except those containing `window' in their names, remove the electric *ess-describe* buffer. Use `other-window' to switch to *ess-describe* window. Customize `ess-describe-at-point-method' if you want to display the description in a tooltip. See also `ess-r-describe-object-at-point-commands' (and similar option for other dialects)." (interactive) (if (not ess-describe-object-at-point-commands) (message "Not implemented for dialect %s" ess-dialect) (ess-force-buffer-current) (let ((map (make-sparse-keymap)) (objname (or (and (use-region-p) (buffer-substring-no-properties (point) (mark))) (ess-symbol-at-point))) ess--descr-o-a-p-commands) ;; used in ess--describe-object-at-point (unless objname (error "No object at point ")) (define-key map (vector last-command-event) #'ess--describe-object-at-point) ;; todo: put digits into the map (let* ((inhibit-quit t) ;; C-g removes the buffer (buf (ess--execute-electric-command map (format "Press %s to cycle" (single-key-description last-command-event)) nil nil objname)) ;; read full command (keys (read-key-sequence-vector "")) (command (and keys (key-binding keys)))) (when (and (commandp command) (bufferp buf) (or (not (symbolp command)) ;; kill on lambdas (not (string-match "window" (symbol-name command))))) (kill-buffer buf)) ;; bury does not work here :( (Emacs bug?) (setq unread-command-events (append keys unread-command-events)))))) (defun ess--describe-object-at-point (_ev objname) (setq ess--descr-o-a-p-commands (or ess--descr-o-a-p-commands (symbol-value ess-describe-object-at-point-commands))) (let* ((com (format (car (pop ess--descr-o-a-p-commands)) objname)) (buf (get-buffer-create "*ess-describe*")) pos) (unless (eq ess-describe-at-point-method 'tooltip) ;; can take some time for the command to execute (display-buffer buf)) (sit-for .01) (ess-command (concat com "\n") buf) ;; erases buf (with-current-buffer buf (goto-char (point-min)) (insert (propertize (format "%s:\n\n" com) 'face 'font-lock-string-face)) (forward-line -1) (setq pos (point)) ;; set the keys that we are used to in help mode (special-mode) (let ((inhibit-read-only t)) (ansi-color-apply-on-region (point-min) (point-max)))) (if (eq ess-describe-at-point-method 'tooltip) (ess-tooltip-show-at-point (with-current-buffer buf (buffer-string)) 0 30) (display-buffer buf) (set-window-point (get-buffer-window buf) pos) ;; don't move window point buf))) (with-no-warnings ;; We're just backporting here, don't care about compiler warnings (defalias 'ess-display-buffer-reuse-mode-window ;; TODO: Remove once we drop support for Emacs 25 (if (fboundp 'display-buffer-reuse-mode-window) 'display-buffer-reuse-mode-window (lambda (buffer alist) (let* ((alist-entry (assq 'reusable-frames alist)) (alist-mode-entry (assq 'mode alist)) (frames (cond (alist-entry (cdr alist-entry)) ((if (eq pop-up-frames 'graphic-only) (display-graphic-p) pop-up-frames) 0) (display-buffer-reuse-frames 0) (t (last-nonminibuffer-frame)))) (inhibit-same-window-p (cdr (assq 'inhibit-same-window alist))) (windows (window-list-1 nil 'nomini frames)) (buffer-mode (with-current-buffer buffer major-mode)) (allowed-modes (if alist-mode-entry (cdr alist-mode-entry) buffer-mode)) (curwin (selected-window)) (curframe (selected-frame))) (unless (listp allowed-modes) (setq allowed-modes (list allowed-modes))) (let (same-mode-same-frame same-mode-other-frame derived-mode-same-frame derived-mode-other-frame) (dolist (window windows) (let ((mode? (with-current-buffer (window-buffer window) (cond ((memq major-mode allowed-modes) 'same) ((derived-mode-p allowed-modes) 'derived))))) (when (and mode? (not (and inhibit-same-window-p (eq window curwin)))) (push window (if (eq curframe (window-frame window)) (if (eq mode? 'same) same-mode-same-frame derived-mode-same-frame) (if (eq mode? 'same) same-mode-other-frame derived-mode-other-frame)))))) (let ((window (car (nconc same-mode-same-frame same-mode-other-frame derived-mode-same-frame derived-mode-other-frame)))) (when (window-live-p window) (prog1 (window--display-buffer buffer window 'reuse alist) (unless (cdr (assq 'inhibit-switch-frame alist)) (window--maybe-raise-frame (window-frame window)))))))))))) (provide 'ess-help) ;;; ess-help.el ends here ESS-24.01.1/lisp/ess-inf.el000066400000000000000000004305121455642170100151600ustar00rootroot00000000000000;;; ess-inf.el --- Support for running S as an inferior Emacs process -*- lexical-binding: t; -*- ;; Copyright (C) 1989-2023 Free Software Foundation, Inc. ;; Author: David Smith ;; Created: 7 Jan 1994 ;; Maintainer: ESS-core ;; This file is part of GNU Emacs. ;;; License: ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see ;; ;;; Commentary: ;; Code for handling running ESS processes. ;;; Code: (eval-when-compile (require 'cl-lib) (require 'tramp) (require 'subr-x)) (require 'ess-utils) (require 'ess) (require 'ess-tracebug) (require 'ansi-color) (require 'comint) (require 'compile) (require 'format-spec) (require 'overlay) (require 'project) ;; Don't require tramp at run time. It's an expensive library to load. ;; Instead, guard calls with (require 'tramp) and silence the byte ;; compiler. (declare-function tramp-sh-handle-expand-file-name "tramp-sh" (name &optional dir)) (declare-function tramp-dissect-file-name "tramp" (name &optional nodefault)) (declare-function tramp-tramp-file-p "tramp" (name)) (declare-function inferior-ess-r-mode "ess-r-mode" ()) (declare-function inferior-ess-julia-mode "ess-julia" ()) (declare-function inferior-ess-stata-mode "ess-stata-mode" ()) (declare-function extract-rectangle-bounds "rect" (start end)) (declare-function ess-mode "ess-mode" ()) (declare-function ess-complete-object-name "ess-r-completion" ()) ;; FIXME:This one should not be necessary (declare-function ess-display-help-on-object "ess-help" (object &optional command)) (declare-function ess-dump-object-into-edit-buffer "ess-mode" (object)) (defvar add-log-current-defun-header-regexp) ;; The following declares can be removed once we drop Emacs 25 (declare-function tramp-file-name-method "tramp") (declare-function tramp-file-name-user "tramp") (declare-function tramp-file-name-host "tramp") (declare-function tramp-file-name-localname "tramp") (declare-function tramp-file-name-hop "tramp") (defcustom inferior-ess-mode-hook nil "Hook for customizing inferior ESS mode. Called after `inferior-ess-mode' is entered and variables have been initialized." :group 'ess-hooks :type 'hook) (defvar inferior-ess-mode-syntax-table (let ((tab (copy-syntax-table comint-mode-syntax-table))) tab) "Syntax table for `inferior-ess-mode'.") (defun inferior-ess--set-major-mode (dialect) "Set major mode according to DIALECT." (cond ((string= "R" dialect) (progn (require 'ess-r-mode) (inferior-ess-r-mode))) ((string= "julia" dialect) (progn (require 'ess-julia) (inferior-ess-julia-mode))) ((string= "stata" dialect) (progn (require 'ess-stata-mode) (inferior-ess-stata-mode))) ;; FIXME: we need this horrible hack so that ;; inferior-ess-mode-syntax-table gets set for ;; languages that still rely on the old way of doing ;; things (before we used define-derived-mode for ;; inferior modes). (t (progn (setq-local inferior-ess-mode-syntax-table (eval (or (alist-get 'inferior-ess-mode-syntax-table ess-local-customize-alist) (alist-get 'ess-mode-syntax-table ess-local-customize-alist)) t)) (inferior-ess-mode))))) ;;*;; Process handling ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; In this section: ;;; ;;; * User commands for starting an ESS process ;;; * Functions called at startup ;;; * Process handling code ;;; * Multiple process implementation ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;*;; Starting a process (defun ess-proc-name (n name) "Return name of process N, as a string, with NAME prepended. If `ess-plain-first-buffername', then initial process is number-free." (concat name (if (not (and ess-plain-first-buffername (= n 1))) ; if not both first and plain-first add number (concat ":" (number-to-string n))))) (defvar-local inferior-ess--local-data nil "Program name and arguments used to start the inferior process.") (defvar inferior-ess--last-started-process-buffer nil "Useful in unit tests to check initialisation errors. In that case the command fails before it can return the process buffer to us. This global variable can be checked instead.") (defun inferior-ess (start-args customize-alist &optional no-wait) "Start inferior ESS process. Without a prefix argument, starts a new ESS process, or switches to the ESS process associated with the current buffer. With START-ARGS (perhaps specified via \\[universal-argument]), starts the process with those args. The current buffer is used if it is an `inferior-ess-mode' or `ess-transcript-mode' buffer. If `ess-ask-about-transfile' is non-nil, you will be asked for a transcript file to use. If there is no transcript file, the buffer name will be like *R* or *R2*, determined by `ess-gen-proc-buffer-name-function'. Takes the program name from the variable `inferior-ess-program'. See Info node `(ess)Customizing startup' and `display-buffer-alist' to control where and how the buffer is displayed. \(Type \\[describe-mode] in the process buffer for a list of commands.) CUSTOMIZE-ALIST is the list of dialect-specific variables. When non-nil, NO-WAIT tells ESS not to wait for the process to finish. This may be useful for debugging." ;; Use the current buffer if it is in inferior-ess-mode or ess-trans-mode ;; If not, maybe ask about starting directory and/or transcript file. ;; If no transfile, use buffer *S* ;; This function is primarily used to figure out the Process and ;; buffer names to use for inferior-ess. (run-hooks 'ess-pre-run-hook) (let* ((dialect (eval (cdr (assoc 'ess-dialect customize-alist)) t)) (process-environment process-environment) ;; Use dialect if not R, R program name otherwise (temp-dialect (if ess-use-inferior-program-in-buffer-name ;VS[23-02-2013]: FIXME: this should not be here (if (string-equal dialect "R") (file-name-nondirectory inferior-ess-r-program) dialect) dialect)) (inf-buf (inferior-ess--get-proc-buffer-create temp-dialect)) (proc-name (buffer-local-value 'ess-local-process-name inf-buf))) (with-current-buffer inf-buf ;; TODO: Get rid of this, we should rely on modes to set the ;; variables they need. (ess-setq-vars-local customize-alist) (inferior-ess--set-major-mode ess-dialect) ;; Set local variables after changing mode because they might ;; not be permanent (setq default-directory (inferior-ess--maybe-prompt-startup-directory proc-name temp-dialect)) (setq inferior-ess--local-data (cons inferior-ess-program start-args)) ;; Read the history file (when ess-history-file (setq comint-input-ring-file-name (expand-file-name (if (eql t ess-history-file) (concat "." ess-dialect "history") ess-history-file) ess-history-directory)) (comint-read-input-ring)) ;; Show the buffer ;; TODO: Remove inferior-ess-own-frame after ESS 19.04, then just have: ;; (pop-to-buffer inf-buf) (pop-to-buffer inf-buf (with-no-warnings (when inferior-ess-own-frame '(display-buffer-pop-up-frame)))) (let ((proc (inferior-ess--start-process inf-buf proc-name start-args))) (ess-make-buffer-current) (goto-char (point-max)) (unless no-wait (ess-write-to-dribble-buffer "(inferior-ess: waiting for process to start (before hook)\n") (ess-wait-for-process proc nil 0.01 t)) (unless (and proc (eq (process-status proc) 'run)) (error "Process %s failed to start" proc-name)) (setq-local font-lock-fontify-region-function #'inferior-ess-fontify-region) (setq-local ess-sl-modtime-alist nil) (run-hooks 'ess-post-run-hook) ;; User initialization can take some time ... (unless no-wait (ess-write-to-dribble-buffer "(inferior-ess): waiting for process (after hook)\n") (ess-wait-for-process proc))) (setq inferior-ess--last-started-process-buffer inf-buf) inf-buf))) (defun inferior-ess--get-proc-buffer-create (name) "Get a process buffer, creating a new one if needed. This always returns a process-less buffer. The variable `ess-local-process-name' is set in the buffer with the name of the next process to spawn. This name may be different from the buffer name, depending on how `ess-gen-proc-buffer-name-function' generated the latter from NAME." (let* ((proc-name (let ((ntry 1)) ;; Find the next non-existent process N (*R:N*) (while (get-process (ess-proc-name ntry name)) (setq ntry (1+ ntry))) (ess-proc-name ntry name))) (inf-name (funcall ess-gen-proc-buffer-name-function proc-name))) (let ((buf (cond ;; Try to use current buffer, if inferior-ess-mode but ;; no process ((and (not (comint-check-proc (current-buffer))) (derived-mode-p 'inferior-ess-mode)) ;; Don't change existing buffer name in this case. It ;; is very common to restart the process in the same ;; buffer. (setq proc-name ess-local-process-name) (current-buffer)) ;; Pick up a transcript file (ess-ask-about-transfile (let ((transfilename (read-file-name "Use transcript file (default none):" nil ""))) (if (string= transfilename "") (get-buffer-create inf-name) (find-file-noselect (expand-file-name transfilename))))) ;; Create a new buffer or take the *R:N* buffer if ;; already exists (it should contain a dead process) (t (get-buffer-create inf-name))))) ;; We generated a new process name but there might still be a ;; live process in the buffer in corner cases because of ;; `ess-gen-proc-buffer-name-function` or if the user renames ;; inferior buffers (when (comint-check-proc buf) (error "Can't start a new session in buffer `%s` because one already exists" inf-name)) (with-current-buffer buf (setq-local ess-local-process-name proc-name)) buf))) (defun ess--accumulation-buffer (proc) "Return, creating if needed, the accumulation buffer for PROC." (let ((abuf (process-get proc :accum-buffer))) (if (buffer-live-p abuf) abuf (let ((abuf (get-buffer-create (format " *%s:accum*" (process-name proc))))) (process-put proc :accum-buffer abuf) (with-current-buffer abuf (buffer-disable-undo) (setq-local inhibit-modification-hooks t)) abuf)))) (defvar-local inferior-ess-objects-command nil "The language/dialect specific command for listing objects. It is initialized from the corresponding inferior--objects-command and then made buffer local."); and the *--* ones are customized! (defvar-local ess-save-lastvalue-command nil "The command to save the last value. See S section for more details. Default depends on the ESS language/dialect and hence made buffer local") (defvar-local ess-retr-lastvalue-command nil "The command to retrieve the last value. See S section for more details. Default depends on the ESS language/dialect and hence made buffer local") (defun inferior-ess-fontify-region (beg end &optional verbose) "Fontify output by output to avoid fontification spilling over prompts. BEG and END signify the bounds, VERBOSE gets passed to `font-lock-default-fontify-region'." (let* ((buffer-undo-list t) (font-lock-dont-widen t) (font-lock-extend-region-functions nil) (pos1 beg) (pos2)) (when (< beg end) (with-silent-modifications ;; fontify chunks from prompt to prompt (while (< pos1 end) (goto-char pos1) (comint-next-prompt 1) (setq pos2 (min (point) end)) (save-restriction (narrow-to-region pos1 pos2) (font-lock-default-fontify-region pos1 pos2 verbose)) (setq pos1 pos2)) ;; highlight errors (setq compilation--parsed beg) `(jit-lock-bounds ,beg . ,end))))) (defun ess-gen-proc-buffer-name:simple (proc-name) "Function to generate buffer name by wrapping PROC-NAME in *proc-name*. See `ess-gen-proc-buffer-name-function'." (format "*%s*" proc-name)) (defun ess-gen-proc-buffer-name:directory (proc-name) "Return a buffer name by wrapping PROC-NAME in *PROC-NAME:DIR-NAME*. DIR-NAME is a short directory name. See `ess-gen-proc-buffer-name-function'." (format "*%s:%s*" proc-name (file-name-nondirectory (directory-file-name default-directory)))) (defun ess-gen-proc-buffer-name:abbr-long-directory (proc-name) "Return a buffer name in the form *PROC-NAME:ABBREVIATED-LONG-DIR-NAME*. PROC-NAME is a string representing an internal process name. ABBREVIATED-LONG-DIR-NAME is an abbreviated full directory name. Abbreviation is performed by `abbreviate-file-name'. See `ess-gen-proc-buffer-name-function'." (format "*%s:%s*" proc-name (abbreviate-file-name default-directory))) (defun ess-gen-proc-buffer-name:project-or-simple (proc-name) "Function to generate buffer name in the form *PROC-NAME:PROJECT-ROOT*. PROC-NAME is a string representing an internal process name. If no project directory has been found use `ess-gen-proc-buffer-name:simple'. See `ess-gen-proc-buffer-name-function'." (if-let ((p (project-current)) (proj (ess--project-root p))) (format "*%s:%s*" proc-name (file-name-nondirectory (directory-file-name proj))) (ess-gen-proc-buffer-name:simple proc-name))) (defun ess-gen-proc-buffer-name:project-or-directory (proc-name) "Function to generate buffer name in the form *PROC-NAME:PROJECT-ROOT*. PROC-NAME is a string representing an internal process name. PROJECT-ROOT is directory name returned by `ess--project-root' if defined. If no project directory has been found, use `ess-gen-proc-buffer-name:directory'. See `ess-gen-proc-buffer-name-function'." (if-let ((p (project-current)) (proj (ess--project-root p))) (format "*%s:%s*" proc-name (file-name-nondirectory (directory-file-name proj))) (ess-gen-proc-buffer-name:directory proc-name))) ;; This ensures that people who have this set in their init file don't ;; get errors about undefined functions after upgrading ESS: (define-obsolete-function-alias 'ess-gen-proc-buffer-name:projectile-or-simple #'ess-gen-proc-buffer-name:project-or-simple "ESS 19.04") (define-obsolete-function-alias 'ess-gen-proc-buffer-name:projectile-or-directory #'ess-gen-proc-buffer-name:project-or-directory "ESS 19.04") (defun inferior-ess-available-p (&optional proc) "Return non-nil if PROC is not busy." (when-let ((proc (or proc (ess-get-current-process)))) (unless (process-get proc 'busy) (or (ess-debug-active-p proc) ; don't send empty lines in debugger (when-let ((last-check (process-get proc 'last-availability-check))) (time-less-p (process-get proc 'last-eval) last-check)) (progn ;; Send an empty string and waiting a bit to make sure we are not busy. (process-send-string proc "\n") (inferior-ess-mark-as-busy proc) (process-put proc 'availability-check t) ;; Start with a very conservative waiting time and quickly average ;; down to the actual response. (let ((avresp (or (process-get proc 'average-response-time) 0.1)) (ts (current-time))) (when (accept-process-output proc (max 0.005 (* 2.0 avresp))) (let ((avresp (/ (+ (* 2.0 avresp) (float-time (time-subtract (current-time) ts))) 3.0))) (process-put proc 'average-response-time avresp))) (process-put proc 'last-availability-check ts)) (not (process-get proc 'busy))))))) (defun inferior-ess--set-status (proc string) "Internal function to set the status of process PROC. Return non-nil if the process is in a ready (not busy) state." ;; TODO: do it in one search, use starting position, use prog1 (let ((ready (string-match-p (concat "\\(" inferior-ess-primary-prompt "\\)\\'") string))) (process-put proc 'busy-end? (and ready (process-get proc 'busy))) ;; When "\n" inserted from inferior-ess-available-p, delete the prompt. (when (and ready (process-get proc 'availability-check) (string-match-p (concat inferior-ess-primary-prompt "\\'") string)) (process-put proc 'suppress-next-output? t)) (process-put proc 'availability-check nil) (when ready (process-put proc 'running-async? nil)) (process-put proc 'busy (not ready)) (process-put proc 'sec-prompt (when inferior-ess-secondary-prompt (string-match (concat "\\(" inferior-ess-secondary-prompt "\\)\\'") string))) ready)) (defun ess--command-delimited-output-info (buf delim) "Detect positions of accumulated output. Return positions after START, before END, after prompt. If any is not found, returns nil. The last position marks the start of new output, if any." (with-current-buffer buf (save-excursion (save-match-data (goto-char (point-min)) (when (re-search-forward (ess--delimiter-start-re delim) nil t) (let ((start (1+ (match-end 0)))) (when (re-search-forward (ess--delimiter-end-re delim) nil t) (when (not (equal (line-beginning-position) (match-beginning 0))) (error "Missing newline in command output")) (let ((end (max (1- (match-beginning 0)) start))) (goto-char (1+ (match-end 0))) (when (re-search-forward inferior-ess-primary-prompt nil t) (let* ((prompt-end (match-end 0)) (new (when (> (point-max) prompt-end) prompt-end))) (list start end new))))))))))) (defun ess--command-output-info (buf) "Detect positions of accumulated output. Like `ess--command-delimited-output-info' but detects prompts without the benefit of output delimiters. This is much less robust. This might leave parasite output at the start of BUF (e.g. `+' prompts with multiline commands). The result might be incomplete if the command output includes a line that ends with `> ' and which happens to be the last characters in a partial output (process output passed to filters is split in batches at arbitrary locations). In that case the rest of the output will be inserted in the process buffer instead of the command buffer." (with-current-buffer buf (save-excursion (save-match-data (goto-char (point-min)) (when (re-search-forward (concat inferior-ess-primary-prompt "\\(\n\\|\\'\\)") nil t) (goto-char (match-beginning 0)) (let ((end (max (1- (line-beginning-position)) (point-min))) (new (when (> (point-max) (line-end-position)) (1+ (line-end-position))))) (list (point-min) end new))))))) ;; Be careful that new output might come in after the closing ;; delimiter or prompt. This could happen when a background command is ;; interrupted asynchronously and the user has sent new inputs before ;; the process has finished interrupting. (defun ess--command-set-status (proc buf info) (with-current-buffer buf (unwind-protect (progn (let* ((beg (nth 0 info)) (end (nth 1 info)) (new (nth 2 info)) (output (buffer-substring beg end)) (new-output (when new (buffer-substring new (point-max))))) ;; Delete the start delimiter and anything before it. ;; This takes care of `+` continuation lines that occur ;; with multi-line commands. Delete anything after the ;; end delimiter, including the prompt and new output (delete-region (point-min) (point-max)) (insert output) new-output)) (process-put proc 'busy nil)))) (defun ess--delimiter-start-re (delim) (concat "\\(" delim "-START\r*$\\)")) (defun ess--delimiter-end-re (delim) (concat "\\(" delim "-END\r*\\)")) (defun ess--delimiter-error-start-re () "ESSR::ERROR \\(\"\\)") (defun ess--delimiter-error-end-re () "\\(\"\\)") (defun inferior-ess-mark-as-busy (proc) "Put PROC's busy value to t." (process-put proc 'busy t) (process-put proc 'sec-prompt nil)) (defun inferior-ess-run-callback (proc string) ;; callback is stored in 'callbacks proc property. Callbacks is a list that ;; can contain either functions to be called with two arguments PROC and ;; STRING, or cons cells of the form (func . suppress). If SUPPRESS is non-nil ;; next process output will be suppressed. (unless (process-get proc 'busy) ;; only one callback is implemented for now (let* ((cb (car (process-get proc 'callbacks))) (listp (not (functionp cb))) (suppress (and listp (consp cb) (cdr cb))) (cb (if (and listp (consp cb)) (car cb) cb))) (when cb (when ess-verbose (ess-write-to-dribble-buffer "executing callback ...\n")) (when suppress (process-put proc 'suppress-next-output? t)) (process-put proc 'callbacks nil) (condition-case-unless-debug err (funcall cb proc string) (error (message "%s" (error-message-string err)))))))) (defun ess--if-verbose-write-process-state (proc string &optional filter) "Write information about PROC, STRING, and FILTER to the dribble buffer." (ess-if-verbose-write (format "\n%s: --> busy:%s busy-end:%s sec-prompt:%s interruptable:%s <-- --> running-async:%s callback:%s suppress-next-output:%s <-- --> dbg-active:%s is-recover:%s <-- --> cmd-buffer:%s cmd-output-delimiter:%s <-- --> string:%s<--\n" (upcase (or filter "normal-filter")) (process-get proc 'busy) (process-get proc 'busy-end?) (process-get proc 'sec-prompt) (process-get proc 'interruptable?) (process-get proc 'running-async?) (if (process-get proc 'callbacks) "yes") (process-get proc 'suppress-next-output?) (process-get proc 'dbg-active) (process-get proc 'is-recover) (process-get proc 'cmd-buffer) (process-get proc 'cmd-output-delimiter) (if (> (length string) 150) (format "%s .... %s" (substring string 0 50) (substring string -50)) string)))) (defun inferior-ess-output-filter (proc string) "Standard output filter for the inferior ESS process PROC. Ring Emacs bell if process output starts with an ASCII bell, and pass the rest to `comint-output-filter'. Taken from octave-mod.el." (inferior-ess--set-status proc string) (ess--if-verbose-write-process-state proc string) (inferior-ess-run-callback proc string) (if (process-get proc 'suppress-next-output?) ;; works only for suppressing short output, for time being is enough (for callbacks) (process-put proc 'suppress-next-output? nil) (comint-output-filter proc (inferior-ess-strip-ctrl-g string)))) (defun inferior-ess-strip-ctrl-g (string) "Strip leading `^G' character. If STRING starts with a `^G', ring the Emacs bell and strip it. Depending on the value of `visible-bell', either the frame will flash or you'll hear a beep. Taken from octave-mod.el." (if (string-match "^\a" string) (progn (ding) (setq string (substring string 1)))) string) (defun ess-process-sentinel (proc message) "Sentinel for use with ESS processes PROC. This marks the process with a MESSAGE, at a particular time point." (let ((abuf (process-get proc :accum-buffer))) (when (buffer-live-p abuf) (kill-buffer abuf))) (let ((pbuf (process-buffer proc))) (when (buffer-live-p pbuf) (with-current-buffer pbuf (save-excursion (setq message (substring message 0 -1)) ; strip newline (set-buffer (process-buffer proc)) (comint-write-input-ring) (goto-char (point-max)) (insert-before-markers (format "\nProcess %s %s at %s\n" (process-name proc) message (current-time-string)))))))) ;; FIXME: This list is structured as '(("R:2") ("R")). It doesn't ;; appear the CDR are used. Can probably just be '("R:2" "R"). (defvar ess-process-name-list nil "Alist of active ESS processes.") (defun inferior-ess--start-process (buf proc-name switches) "Make a comint process in buffer BUF with process PROC-NAME. SWITCHES is passed to `comint-exec'. BUF is guaranteed to be a process-less buffer because it was created with `inferior-ess--get-proc-buffer-create'." (with-current-buffer buf (if (eq (buffer-size) 0) nil (goto-char (point-max)) (insert "\^L\n"))) (let ((process-environment (nconc (list "STATATERM=emacs" (format "PAGER=%s" inferior-ess-pager)) process-environment)) (tramp-remote-process-environment (nconc ;; it contains a pager already, so append (when (boundp 'tramp-remote-process-environment) (copy-sequence tramp-remote-process-environment)) (list "STATATERM=emacs" (format "PAGER=%s" inferior-ess-pager))))) (comint-exec buf proc-name inferior-ess-program nil (when switches (split-string switches)))) (let ((proc (get-buffer-process buf))) ;; Set the process hooks (set-process-sentinel proc #'ess-process-sentinel) (set-process-filter proc #'inferior-ess-output-filter) (inferior-ess-mark-as-busy proc) ;; Add this process to ess-process-name-list, if needed (let ((conselt (assoc proc-name ess-process-name-list))) (unless conselt (setq ess-process-name-list (cons (cons proc-name nil) ess-process-name-list)))) proc)) ;;*;; Requester functions called at startup (defun inferior-ess--get-startup-directory () "Return a startup directory." (let ((dir (or (when (boundp 'ess-startup-directory) (if (symbolp ess-startup-directory) (symbol-value ess-startup-directory) ess-startup-directory)) (and ess-startup-directory-function (funcall ess-startup-directory-function)) (when-let ((proj (project-current))) (ess--project-root proj)) default-directory))) (directory-file-name dir))) (defun inferior-ess--maybe-prompt-startup-directory (procname _dialect) "Possibly prompt for a startup directory. When `ess-ask-for-ess-directory' is non-nil, prompt. PROCNAME is the name of the inferior process (e.g. \"R:1\"), and DIALECT is the language dialect (e.g. \"R\")." (let ((default-dir (inferior-ess--get-startup-directory))) (if ess-ask-for-ess-directory (let ((prompt (format "%s starting project directory? " procname)) (display-buffer-overriding-action nil) ; hack to let helm display a buffer ) (ess-prompt-for-directory default-dir prompt)) default-dir))) (defun ess-prompt-for-directory (default prompt) "PROMPT for a directory, using DEFAULT as the usual." (let* ((def-dir (file-name-as-directory default)) (the-dir (expand-file-name (file-name-as-directory (read-directory-name prompt def-dir def-dir t nil))))) (if (file-directory-p the-dir) nil (error "%s is not a valid directory" the-dir)) the-dir)) ;;*;; General process handling code (defmacro ess-with-current-buffer (buffer &rest body) "Like `with-current-buffer' but with transfer of some essential local ESS vars like `ess-local-process-name'." (declare (indent 1) (debug t)) (let ((lpn (make-symbol "lpn")) (dialect (make-symbol "dialect")) (alist (make-symbol "alist"))) `(let ((,lpn ess-local-process-name) (,dialect ess-dialect) (,alist ess-local-customize-alist)) (with-current-buffer ,buffer (ess-setq-vars-local (eval ,alist t)) (setq ess-local-process-name ,lpn) (setq ess-dialect ,dialect) ,@body)))) (dolist (mode '(emacs-lisp-mode lisp-interaction-mode)) (font-lock-add-keywords mode '(("(\\(ess-with-current-buffer\\)\\s +\\(\\(\\w\\|\\s_\\)+\\)" (1 font-lock-keyword-face) (2 font-lock-variable-name-face))))) (defun ess-get-process (&optional name use-another) "Return the ESS process named by NAME. If USE-ANOTHER is non-nil, and the process NAME is not running (anymore), try to connect to another if there is one. By default (USE-ANOTHER is nil), the connection to another process happens interactively (when possible)." (setq name (or name ess-local-process-name)) (cl-assert name nil "No ESS process is associated with this buffer now") (update-ess-process-name-list) (cond ((assoc name ess-process-name-list) (get-process name)) ((= 0 (length ess-process-name-list)) (save-current-buffer (message "trying to (re)start process %s for language %s ..." name ess-language) (ess-start-process-specific ess-language ess-dialect) ;; and return the process: "call me again" (ess-get-process name))) ;; else: there are other running processes (use-another ; connect to another running process : the first one (let ((other-name (car (elt ess-process-name-list 0)))) ;; "FIXME": try to find the process name that matches *closest* (message "associating with *other* process '%s'" other-name) (ess-get-process other-name))) ((and (not noninteractive) (y-or-n-p (format "Process %s is not running, but others are. Switch? " name))) (ess-force-buffer-current (concat ess-dialect " process to use: ") 'force) (ess-get-process ess-current-process-name)) (t (error "Process %s is not running" name)))) (defun inferior-ess-default-directory () "Return the `default-directory' of the process." (ess-get-process-variable 'default-directory)) ;;--- Unfinished idea (ESS-help / R-help ) -- probably not worth it... ;;- (defun ess-set-inferior-program (filename) ;;- "Allows to set or change `inferior-ess-program', the program (file)name." ;;- (interactive "fR executable (script) file: ") ;;- ;; "f" : existing file {file name completion} ! ;;- (setq inferior-ess-program filename)) ;; the inferior-ess-program is initialized in the customize..alist, ;; e.g. from inferior-ess-r-program ... --> should change rather these. ;; However these really depend on the current ess-language! ;; Plan: 1) must know and use ess-language ;; 2) change the appropriate inferior--program ;; (how?) in R/S : assign(paste("inferior-",ESSlang,"-p...."), filename)) ;;*;; Multiple process handling code ;; FIXME: It seems the only effect of this function is to remove dead ;; processes from `ess-process-name-list'. Am I missing something? (defun ess-make-buffer-current nil "Make the process associated with the current buffer the current ESS process. Returns the name of the process, or nil if the current buffer has none." (update-ess-process-name-list) ;; (if ess-local-process-name ;; (setq ess-current-process-name ess-local-process-name)) ess-local-process-name) (defun ess-get-process-variable (var) "Return the variable VAR (symbol) local to ESS process called NAME (string)." (buffer-local-value var (process-buffer (ess-get-process ess-local-process-name)))) (defun ess-set-process-variable (var val) "Set variable VAR (symbol) local to ESS process called NAME (string) to VAL." (with-current-buffer (process-buffer (ess-get-process ess-local-process-name)) (set var val))) (defun ess-process-live-p (&optional proc) "Check if the local ess process is alive. Return nil if current buffer has no associated process, or process was killed. PROC defaults to `ess-local-process-name'" (when-let ((proc (or proc (ess-get-current-process)))) (process-live-p proc))) (defun ess-process-get (propname &optional proc) "Return the variable PROPNAME (symbol) of the current ESS process. PROC defaults to process with name `ess-local-process-name'." (process-get (or proc (get-process ess-local-process-name)) propname)) (defun ess-process-put (propname value &optional proc) "Set the variable PROPNAME (symbol) to VALUE in the current ESS process. PROC defaults to the process given by `ess-local-process-name'" (process-put (or proc (get-process ess-local-process-name)) propname value)) (defun ess-start-process-specific (language dialect) "Start an ESS process. Typically from a language-specific buffer, using DIALECT. LANGUAGE is ignored." (save-current-buffer (let ((dsymb (intern dialect))) (if (fboundp dsymb) (funcall dsymb) (error "No ESS processes running; not yet implemented to start (%s,%s)" language dialect))))) (defmacro ess--with-no-pop-to-buffer (&rest body) "Disable some effects of `pop-to-buffer'. Prevent `display-buffer' from performing an action and save the current buffer to prevent `pop-to-buffer' from setting a new current buffer." ;; `pop-to-buffer' might still raise windows and frames so it may be ;; better to have our own configurable `ess--pop-to-buffer' wrapper. (declare (indent 0) (debug (&rest form))) `(let ((display-buffer-overriding-action '(display-buffer-no-window (allow-no-window . t)))) (save-current-buffer ,@body))) (defun ess-request-a-process (message &optional noswitch ask-if-1) "Ask for a process, and make it the current ESS process. If there is exactly one process, only ask if ASK-IF-1 is non-nil. Also switches to the process buffer unless NOSWITCH is non-nil. Interactively, NOSWITCH can be set by giving a prefix argument. Returns the name of the selected process. MESSAGE may get passed to `ess-completing-read'." (interactive (list "Switch to which ESS process? " current-prefix-arg)) (update-ess-process-name-list) (let* ((ess-dialect (or ess-dialect (ess-completing-read "Set `ess-dialect'" (delete-dups (list "R" "S+" (or (bound-and-true-p S+-dialect-name) "S+") "stata" (or (bound-and-true-p STA-dialect-name) "stata") "julia" "SAS"))))) (pname-list (delq nil ;; keep only those matching dialect and `ess-gen-proc-buffer-name-function' (append (mapcar (lambda (lproc) (and (equal ess-dialect (buffer-local-value 'ess-dialect (process-buffer (get-process (car lproc))))) (not (equal ess-local-process-name (car lproc))) (car lproc))) ess-process-name-list) ;; append local only if running (when (assoc ess-local-process-name ess-process-name-list) (list ess-local-process-name))))) (num-processes (length pname-list)) proc auto-started?) (when (or (= 0 num-processes) (and (= 1 num-processes) (not (equal ess-dialect ;; don't auto connect if from different dialect (buffer-local-value 'ess-dialect (process-buffer (get-process (car pname-list)))))))) ;; Try to start "the appropriate" process, don't show the buffer ;; since we handle that explicitly with no-switch (ess-if-verbose-write "ess-request-a-process: Can't find a process, starting a new one\n") (ess--with-no-pop-to-buffer (ess-start-process-specific ess-language ess-dialect)) (setq num-processes 1 pname-list (car ess-process-name-list) auto-started? t)) ;; now num-processes >= 1 : (let* ((proc-buffers (mapcar (lambda (lproc) (buffer-name (process-buffer (get-process lproc)))) pname-list))) (setq proc (if (or auto-started? (and (not ask-if-1) (= 1 num-processes) (message "Using process `%s'" (car proc-buffers)))) (car pname-list) (unless (and ess-current-process-name (get-process ess-current-process-name)) (setq ess-current-process-name nil)) ;; ask for buffer name not the *real* process name: (let ((buf (ess-completing-read message (append proc-buffers (list "*new*")) nil t nil nil))) (if (not (equal buf "*new*")) (process-name (get-buffer-process buf)) ;; Prevent new process buffer from being popped ;; because we handle display depending on the value ;; of `no-switch` (ess-if-verbose-write "ess-request-a-process: User requested a new process\n") (ess--with-no-pop-to-buffer (ess-start-process-specific ess-language ess-dialect)) (caar ess-process-name-list)))))) ;; Always display buffer if auto-started but do not select it if ;; NOSWITCH is set (when (or auto-started? (not noswitch)) (let ((proc-buf (ess-get-process-buffer proc))) (if noswitch (display-buffer proc-buf) (pop-to-buffer proc-buf)) ;; If inferior startup has already finished, set screen ;; options again in case the post-run hook ran before a new ;; screen config was created by `pop-to-buffer' (#1243). (with-current-buffer proc-buf (ess--execute-screen-options-bg)))) proc)) (defun ess-force-buffer-current (&optional prompt force no-autostart ask-if-1) "Make sure the current buffer is attached to an ESS process. If not, or FORCE (prefix argument) is non-nil, prompt for a process name with PROMPT. If NO-AUTOSTART is nil starts the new process if process associated with current buffer has died. `ess-local-process-name' is set to the name of the process selected. `ess-dialect' is set to the dialect associated with the process selected. ASK-IF-1 asks user for the process, even if there is only one process running. Returns the inferior buffer if it was successfully forced, throws an error otherwise." (interactive (list (concat ess-dialect " process to use: ") current-prefix-arg nil)) (let ((proc-name (ess-make-buffer-current))) (cond ((and (not force) proc-name (get-process proc-name))) ;; Make sure the source buffer is attached to a process ((and ess-local-process-name (not force) no-autostart) (error "Process %s has died" ess-local-process-name)) ;; Request a process if `ess-local-process-name' is nil (t (let* ((prompt (or prompt "Process to use: ")) (proc (ess-request-a-process prompt 'no-switch ask-if-1))) (setq ess-local-process-name proc))))) (process-buffer (get-process ess-local-process-name))) (defalias 'inferior-ess-force #'ess-force-buffer-current) (defun ess-switch-process () "Force a switch to a new underlying process." (interactive) (ess-force-buffer-current "Process to use: " 'force nil 'ask-if-1)) (defun ess-get-current-process () (when ess-local-process-name (get-process ess-local-process-name))) (defun ess-get-current-process-buffer () (when-let ((proc (ess-get-current-process))) (process-buffer proc))) (defun ess-get-next-available-process (&optional dialect ignore-busy background) "Return first available (aka not busy) process of dialect DIALECT. DIALECT defaults to the local value of ess-dialect. Return nil if no such process has been found. If BACKGROUND is non-nil, only processes that are allowed to evaluate in the background are matched." (setq dialect (or dialect ess-dialect)) (when (and dialect (or (not background) ess-can-eval-in-background)) (let (proc) (catch 'found (dolist (p (cons ess-local-process-name (mapcar #'car ess-process-name-list))) (when p (setq proc (get-process p)) (when (and proc (process-live-p proc) (equal dialect (buffer-local-value 'ess-dialect (process-buffer proc))) ;; Check that we can evaluate in background ;; before checking for availability to ;; avoid issues with newline handshakes (or (not background) (ess-can-eval-in-background proc)) (or ignore-busy (inferior-ess-available-p proc))) (throw 'found proc)))))))) (defun ess-get-next-available-bg-process (&optional proc dialect ignore-busy) "Returns first avaiable process only if background evaluations are allowed. Same as `ess-get-next-available-process' but checks for `ess-can-eval-in-background'." (if proc (ess-can-eval-in-background proc) (ess-get-next-available-process dialect ignore-busy 'background))) ;;*;;; Commands for switching to the process buffer (defun ess-switch-to-ESS (eob-p) "Switch to the current inferior ESS process buffer. With (prefix) EOB-P non-nil, positions cursor at end of buffer." (interactive "P") (ess-force-buffer-current) (pop-to-buffer (buffer-name (process-buffer (get-process ess-current-process-name))) '(nil . ((inhibit-same-window . t)))) (when eob-p (goto-char (point-max)))) (defun ess-switch-to-end-of-ESS () "Switch to the end of the inferior ESS process buffer." (interactive) (ess-switch-to-ESS t)) (defun ess-switch-to-inferior-or-script-buffer (toggle-eob) "Switch between script and process buffer. This is a single-key command. Assuming that it is bound to C-c C-z, you can navigate back and forth between iESS and script buffer with C-c C-z C-z C-z ... If variable `ess-switch-to-end-of-proc-buffer' is t (the default) this function switches to the end of process buffer. If TOGGLE-EOB is given, the value of `ess-switch-to-end-of-proc-buffer' is toggled." (interactive "P") (let ((eob (if toggle-eob (not ess-switch-to-end-of-proc-buffer) ess-switch-to-end-of-proc-buffer))) (if (derived-mode-p 'inferior-ess-mode) (let ((dialect ess-dialect) (proc-name ess-local-process-name) (blist (buffer-list))) (while (and (pop blist) (with-current-buffer (car blist) (not (or (and (ess-derived-mode-p) (equal dialect ess-dialect) (null ess-local-process-name)) (and (ess-derived-mode-p) (equal proc-name ess-local-process-name))))))) (if blist (pop-to-buffer (car blist)) (message "Found no buffers for `ess-dialect' %s associated with process %s" dialect proc-name))) (ess-switch-to-ESS eob)) (when (called-interactively-p 'any) (set-transient-map (let ((map (make-sparse-keymap)) (key (vector last-command-event))) (define-key map key #'ess-switch-to-inferior-or-script-buffer) map))))) (defun ess-get-process-buffer (&optional name) "Return the buffer associated with the ESS process named by NAME." (process-buffer (ess-get-process (or name ess-local-process-name)))) (defun update-ess-process-name-list () "Remove names with no process." (let (defunct) (dolist (conselt ess-process-name-list) (let ((proc (get-process (car conselt)))) (unless (and proc (eq (process-status proc) 'run)) (push conselt defunct)))) (dolist (pointer defunct) (setq ess-process-name-list (delq pointer ess-process-name-list)))) (if (eq (length ess-process-name-list) 0) (setq ess-current-process-name nil))) ;;; Functions for evaluating code ;;*;; Utils for evaluation (defun ess-build-eval-command (string &optional visibly output file &rest args) "Format an evaluation command. Wrap STRING with `ess-quote-special-chars' and dispatch on `ess-build-eval-command--override'." (setq string (ess-quote-special-chars string)) (ess-build-eval-command--override string visibly output file args)) (cl-defgeneric ess-build-eval-command--override (string &optional _visibly _output file &rest _args) "Default method to build eval command." (and ess-eval-command (format-spec ess-eval-command `((?s . ,string) (?f . ,file))))) (cl-defgeneric ess-build-load-command (file &optional _visibly _output &rest _args) "Format a loading command. Dispatches on the dialect-specific `ess-build-load-command' and `ess-load-command', in that order." (and ess-load-command (format ess-load-command file))) (defun ess-wait-for-process (&optional proc sec-prompt wait force-redisplay timeout) "Wait for \\='busy property of the process to become nil. If SEC-PROMPT is non-nil return if secondary prompt is detected regardless of whether primary prompt was detected or not. If WAIT is non-nil wait for WAIT seconds for process output before the prompt check, default 0.002s. When FORCE-REDISPLAY is non-nil force redisplay. You better use WAIT >= 0.1 if you need FORCE-REDISPLAY to avoid excessive redisplay. If TIMEOUT is non-nil stop waiting for output after TIMEOUT seconds. Returns nil if TIMEOUT was reached, non-nil otherwise." (setq proc (or proc (get-process ess-local-process-name))) (setq wait (or wait 0.005)) (setq timeout (or timeout most-positive-fixnum)) (let ((start-time (float-time)) (elapsed 0)) (save-excursion (while (and (or (eq (process-status proc) 'run) (progn (when (process-buffer proc) (display-buffer (process-buffer proc))) (error "ESS process has died unexpectedly"))) (< elapsed timeout) (or (accept-process-output proc wait) (unless (and sec-prompt (process-get proc 'sec-prompt)) (process-get proc 'busy)))) (when force-redisplay (redisplay 'force)) (setq elapsed (- (float-time) start-time)) (when (> elapsed .3) (setq wait .3)))) (< elapsed timeout))) ;; This filter is active under `ess-command` (defun inferior-ess-ordinary-filter (proc string) (ess--if-verbose-write-process-state proc string "ordinary-filter") (let* ((cmd-buf (process-get proc 'cmd-buffer)) (cmd-delim (process-get proc 'cmd-output-delimiter))) (when (buffer-live-p cmd-buf) (ess--exit-protect (progn (with-current-buffer cmd-buf (goto-char (point-max)) (insert string)) (if-let ((info (if cmd-delim (ess--command-delimited-output-info cmd-buf cmd-delim) (ess--command-output-info cmd-buf)))) (let ((new-output (ess--command-set-status proc cmd-buf info))) (ess-if-verbose-write "ess-command (filter): Found prompt\n") (when (not (process-get proc 'busy)) ;; Store new output until restoration (when new-output (process-put proc 'pending-output new-output)) ;; Restore the user's process filter as soon as process is ;; available (funcall (process-get proc 'cmd-restore-function)) ;; Run callback with command output (when (process-get proc 'callbacks) (inferior-ess-run-callback proc (with-current-buffer cmd-buf (buffer-string)))))) (ess-if-verbose-write "ess-command (filter): Accumulating output\n"))) ;; Be defensive when something goes wrong. Restore process to a ;; usable state. (ess-if-verbose-write "ess-command (filter): Early exit\n") (process-put proc 'busy nil) (funcall (process-get proc 'cmd-restore-function)))))) (defvar ess-presend-filter-functions nil "List of functions to call before sending the input string to the process. Each function gets one argument, a string containing the text to be send to the subprocess. It should return the string sent, perhaps the same string that was received, or perhaps a modified or transformed string. The functions on the list are called sequentially, and each one is given the string returned by the previous one. The string returned by the last function is the text that is actually sent to the process. You can use `add-hook' to add functions to this list either globally or locally. The hook is executed in current buffer. Before execution, the local value of this hook in the process buffer is appended to the hook from the current buffer.") (defvar ess--inhibit-presend-hooks nil "If non-nil don't run presend hooks.") (defun ess--run-presend-hooks (process string) ;; run ess-presend-filter-functions and comint-input-filter-functions (if ess--inhibit-presend-hooks string ;;return modified string (let* ((pbuf (process-buffer process)) ;; also run proc buffer local hooks (functions (unless (eq pbuf (current-buffer)) (buffer-local-value 'ess-presend-filter-functions pbuf)))) (setq functions (append (delq t (copy-sequence functions)) ;; even in let, delq destructs ess-presend-filter-functions)) (while (and functions string) ;; cannot use run-hook-with-args here because string must be passed from one ;; function to another (if (eq (car functions) t) (let ((functions (default-value 'ess-presend-filter-functions))) (while (and functions string) (setq string (funcall (car functions) string)) (setq functions (cdr functions)))) (setq string (funcall (car functions) string))) (setq functions (cdr functions))) (with-current-buffer pbuf (run-hook-with-args 'comint-input-filter-functions string)) string))) (defun ess--concat-new-line-maybe (string) "Append \\n at the end of STRING if missing." (if (string-match "\n\\'" string (max (- (length string) 2) 0)) string (concat string "\n"))) (defvar ess--dbg-del-empty-p t "Internal variable to control removal of empty lines during the debugging. Let-bind it to nil before calling `ess-send-string' or `ess-send-region' if no removal is necessary.") (defun inferior-ess--interrupt-subjob-maybe (proc) "Internal. Interrupt the process if interruptable? process variable is non-nil. Hide all the junk output in temporary buffer." (when (process-get proc 'interruptable?) (let ((cb (cadr (process-get proc 'callbacks))) (buf (get-buffer-create " *ess-temp-buff*")) (old-filter (process-filter proc)) (old-buff (process-buffer proc))) (unwind-protect (progn (ess-if-verbose-write "interrupting subjob ... start") (process-put proc 'interruptable? nil) (process-put proc 'callbacks nil) (process-put proc 'running-async? nil) ;; this is to avoid putting junk in user's buffer on process ;; interruption (set-process-buffer proc buf) (set-process-filter proc #'inferior-ess-ordinary-filter) (interrupt-process proc) (when cb (ess-if-verbose-write "executing interruption callback ... ") (funcall cb proc)) ;; should be very fast as it inputs only the prompt (ess-wait-for-process proc) (ess-if-verbose-write "interrupting subjob ... finished") ) (set-process-buffer proc old-buff) (set-process-filter proc old-filter))))) ;;*;; Evaluation primitives (defun ess-send-string (process string &optional visibly message _type) "ESS wrapper for `process-send-string'. Run `comint-input-filter-functions' and current buffer's and PROCESS' `ess-presend-filter-functions' hooks on the input STRING. VISIBLY can be nil, t, \\='nowait or a string. If string the behavior is as with \\='nowait with the differences that inserted string is VISIBLY instead of STRING (evaluated command is still STRING). In all other cases the behavior is as described in `ess-eval-visibly'. STRING need not end with \\n. TYPE is a symbol indicating type of the string. MESSAGE is a message to display." ;; No support of `visibly' when there's no secondary prompt (let ((visibly (if (and (eq visibly t) (null inferior-ess-secondary-prompt)) 'nowait visibly)) (string (ess--run-presend-hooks process string))) (inferior-ess--interrupt-subjob-maybe process) (inferior-ess-mark-as-busy process) (process-put process 'last-eval (current-time)) (cond ;; Wait after each line ((eq visibly t) (let ((ess--inhibit-presend-hooks t)) (ess-eval-linewise string))) ;; Insert command and eval invisibly ((or (stringp visibly) (eq visibly 'nowait)) (with-current-buffer (process-buffer process) (save-excursion (goto-char (process-mark process)) (insert-before-markers (propertize (format "%s\n" (replace-regexp-in-string "\n" "\n+ " (if (stringp visibly) visibly string))) 'font-lock-face 'comint-highlight-input))) (process-send-string process (ess--concat-new-line-maybe string)))) (t (process-send-string process (ess--concat-new-line-maybe string)))) (when message (message "%s" message)))) (defun ess-send-region (process start end &optional visibly message type) "Low level ESS version of `process-send-region'. If VISIBLY call `ess-eval-linewise', else call `ess-send-string'. If MESSAGE is supplied, display it at the end. Run current buffer's and PROCESS' `ess-presend-filter-functions' hooks. TYPE is a symbol indicating type of the region." (cond ((ess-tracebug-p) (ess-tracebug-send-region process start end visibly message type)) (t (ess-send-region--override process start end visibly message type)))) (cl-defgeneric ess-send-region--override (process start end visibly message type) (ess-send-string process (buffer-substring start end) visibly message type)) ;;*;; Evaluation commands (defun ess-load-file--normalise-file (file) "Handle Tramp and system peculiarities." (require 'tramp) (let* ((file (if (tramp-tramp-file-p file) (tramp-file-name-localname (tramp-dissect-file-name file)) file)) (file (if ess-microsoft-p (ess-replace-in-string file "[\\]" "/") file))) (abbreviate-file-name file))) (defun ess-load-file--normalise-buffer (file) (when (ess-save-file file) (error "Buffer %s has not been saved" (buffer-name file))) (let ((source-buffer (get-file-buffer file))) (if source-buffer (with-current-buffer source-buffer (when (buffer-modified-p) (save-buffer)) (ess-force-buffer-current "Process to load into: ")) (ess-force-buffer-current "Process to load into: ")))) ;;;###autoload (defun ess-load-file (&optional filename) "Load FILENAME into an inferior ESS process. This handles Tramp when working on a remote." (interactive (list (or (and (ess-derived-mode-p) (buffer-file-name)) (expand-file-name (read-file-name "Load source file: " nil nil t))))) (ess-load-file--normalise-buffer filename) (setq filename (ess-load-file--normalise-file filename)) (ess-load-file--override filename) (message "Loaded %s" filename)) (cl-defgeneric ess-load-file--override (filename) (let ((command (ess-build-load-command filename nil t))) (ess-send-string (ess-get-process) command t))) ;; ;;; VS[03-09-2012]: Test Cases: ;; (ess-command "a<-0\n" nil nil nil nil (get-process "R")) ;; (ess-async-command-delayed "Sys.sleep(5);a<-a+1;cat(1:10)\n" nil ;; (get-process "R") (lambda (proc) (message "done"))) ;; (ess-async-command-delayed "Sys.sleep(5)\n" nil (get-process "R") ;; (lambda (proc) (message "done"))) ;; (process-get (get-process "R") 'running-async?) (defun ess-command--get-proc (proc no-prompt-check) (if proc (unless ess-local-process-name (setq ess-local-process-name (process-name proc))) (setq proc (ess-get-process ess-local-process-name))) (unless no-prompt-check (when (process-get proc 'busy) (user-error "ESS process not ready. Finish your command before trying again"))) proc) (defvar inferior-ess--output-delimiter-count 0) (defun inferior-ess--output-delimiter () (setq inferior-ess--output-delimiter-count (1+ inferior-ess--output-delimiter-count)) (format "ess-output-delimiter%s" inferior-ess--output-delimiter-count)) (defvar ess--command-default-timeout most-positive-fixnum) ;; NOTE: We might want to switch to something like `cl-defun' with ;; keyword arguments given the length of the signature. Would also ;; make it easier to deprecate arguments. (defun ess-command (cmd &optional out-buffer _sleep no-prompt-check wait proc force-redisplay timeout) "Send the ESS process CMD and delete the output from the ESS process buffer. If an optional second argument OUT-BUFFER exists save the output in that buffer. OUT-BUFFER is erased before use. CMD should have a terminating newline. Guarantees that the value of `.Last.value' will be preserved. `ess-command' is executes CMD in the background synchronously, meaning that the Emacs UI blocks while CMD is running. Make sure that CMD returns immediately. Blocking the UI for more than 0.1 seconds should generally be considered a bug. SLEEP is deprecated and no longer has any effect. WAIT, FORCE-REDISPLAY, and TIMEOUT are as in `ess-wait-for-process' and are passed to `ess-wait-for-process'. The default timeout is 30 seconds. The process is interrupted with `interrupt-process' when the timeout is reached or when an error occurs. PROC should be a process, if nil the process name is taken from `ess-local-process-name'. This command doesn't set \\='last-eval process variable. Note: for critical, or error prone code you should consider wrapping the code into: local({ olderr <- options(error=NULL) on.exit(options(olderr)) ... })" (let ((out-buffer (or out-buffer (get-buffer-create " *ess-command-output*"))) (proc (ess-command--get-proc proc no-prompt-check)) (delim (inferior-ess--output-delimiter)) (timeout (or timeout ess--command-default-timeout))) (with-current-buffer (process-buffer proc) (let* ((proc-forward-alist (ess--alist (ess-local-process-name inferior-ess-primary-prompt))) (format-command-alist (ess-process-get 'format-command-alist)) (use-delimiter (alist-get 'use-delimiter format-command-alist)) (rich-cmd (if-let ((cmd-fun (alist-get 'fun format-command-alist))) (funcall cmd-fun (ess--strip-final-newlines cmd) (cons 'output-delimiter delim)) cmd)) (early-exit t)) (ess-if-verbose-write (format "(ess-command '%s' ..)\n" cmd)) ;; Swap the process buffer with the output buffer before ;; sending the command (unwind-protect (condition-case err (progn ;; The process is restored from the filter once it's ;; available again (i.e. a prompt or delimiter is ;; detected). This handles the synchronous case when the ;; command runs to completion, as well as the ;; asynchronous case when an early exit occurs. The most ;; common cause of early exits are interrupts sent by ;; Emacs when the user types (see `when-no-input'). In ;; these cases we forward the interrupt to the process ;; and return to the caller right away. We can't restore ;; synchronously after an interrupt because the output ;; of the background command would spill into the ;; process buffer of the user when the process doesn't ;; interrupt in time. (process-put proc 'cmd-restore-function (ess--command-make-restore-function proc)) (when use-delimiter (process-put proc 'cmd-output-delimiter delim)) (process-put proc 'cmd-buffer out-buffer) (set-process-filter proc #'inferior-ess-ordinary-filter) (with-current-buffer out-buffer (ess-setq-vars-local proc-forward-alist) (setq buffer-read-only nil) (erase-buffer) (inferior-ess-mark-as-busy proc) (process-send-string proc rich-cmd) ;; Need time for ess-create-object-name-db on PC (if no-prompt-check (sleep-for 0.02) ; 0.1 is noticeable! (unless (ess-wait-for-process proc nil wait force-redisplay timeout) (error "Timeout during background ESS command `%s'" (ess--strip-final-newlines cmd)))) (setq early-exit nil))) (error (setq early-exit err)) (quit (setq early-exit err))) (if early-exit (ess--command-error-handler proc out-buffer use-delimiter delim early-exit) (with-current-buffer out-buffer (goto-char (point-min)) (when (re-search-forward (ess--delimiter-error-start-re) nil t) (let ((start (1+ (match-beginning 1)))) (when (re-search-forward (ess--delimiter-error-end-re) nil t) (let ((end (match-beginning 1))) (error "R error during background ESS command `%s'\nError: %s" (ess--strip-final-newlines cmd) (buffer-substring start end))))))))))) out-buffer)) (defun ess--command-error-handler (proc out-buffer use-delimiter delim early-exit) (let ((inhibit-quit t)) ;; In case of early exit send an interrupt to the ;; process to abort the command (with-current-buffer out-buffer (goto-char (point-min)) (when (and use-delimiter (not (re-search-forward (ess--delimiter-start-re delim) nil t))) ;; CMD probably failed to parse if the start delimiter ;; can't be found in the output. Disable the delimiter ;; before interrupt to avoid a freeze. (ess-write-to-dribble-buffer "Disabling output delimiter because CMD failed to parse\n") (process-put proc 'cmd-output-delimiter nil)) (goto-char (point-max)) (ess--interrupt proc))) ;; Can be `t` when early exit is caused e.g. by a throw instead of ;; an error or a quit. This happens in tests and within ;; `while-no-input'. (unless (eq early-exit t) (when (and (eq (car early-exit) 'quit) (y-or-n-p (concat "Background background command interrupted with a user quit.\n" "Would you like to disable background evaluations in this process?"))) (process-put proc 'bg-eval-disabled t)) (signal (car early-exit) (cdr early-exit)))) ;; (ess-process-get 'ess-format-command-alist) ;; "Alist of mode-specific parameters for formatting a command. ;; All elements are optional. ;; ;; - `fun': A formatting function for running a command. First ;; argument is the background command to run. Must include a ;; catch-all `&rest` parameter for extensibility. ;; ;; - `use-delimiter' : Whether to wait for an output sentinel. If ;; non-nil, `fun' should get the `cmd-output-delimiter' element of the ;; alist of parameters and ensure the sentinel is written to the ;; process output at the end of the command." (defun ess--command-make-restore-function (proc) (let ((old-pf (process-filter proc))) (lambda () (set-process-filter proc old-pf) (process-put proc 'cmd-output-delimiter nil) (process-put proc 'cmd-buffer nil) (when-let ((pending (process-get proc 'pending-output))) (process-put proc 'pending-output nil) (funcall old-pf proc pending))))) ;; TODO: Needs some Julia tests as well (defun ess--foreground-command (cmd &optional out-buffer _sleep no-prompt-check wait proc) "Same as `ess-command' but does not timeout. Currently blocks the Emacs UI. Eventually it would make sense to lock the inferior to prevent interactions and use `ess-async-command' with a callback." (let ((timeout most-positive-fixnum)) (ess-command cmd out-buffer nil no-prompt-check wait proc nil timeout))) (defun ess-boolean-command (com &optional buf wait) "Like `ess-command' but expects COM to print TRUE or FALSE. If TRUE (or true) is found return non-nil otherwise nil. Example (ess-boolean-command \"2>1\n\")" (with-current-buffer (ess-command com buf nil nil wait) (goto-char (point-min)) (let ((case-fold-search t)) (re-search-forward "true" nil t)))) (defun ess-string-command (com &optional buf wait) "Returns the output of COM as a string." (with-current-buffer (ess-command com buf nil nil wait) (buffer-substring (point-min) (point-max)))) (defun ess-async-command (com &optional buf proc callback interrupt-callback) "Asynchronous version of `ess-command'. COM, BUF, WAIT and PROC are as in `ess-command'. CALLBACK is a function of two arguments (PROC STRING) to run after the successful execution. When INTERRUPT-CALLBACK is non-nil, user evaluation can interrupt the job. INTERRUPT-CALLBACK should be either t or a function of one argument (PROC) to be called on interruption. NOTE: Currently this function should be used only for background jobs like caching. ESS tries to suppress any output from the asynchronous command, but long output of COM will most likely end up in user's main buffer." (setq proc (or proc (get-process ess-local-process-name))) (cond ((not (and proc (eq (process-status proc) 'run))) (error "Process %s is dead" proc)) ((process-get proc 'busy) (error "Process %s is busy" proc)) ((process-get proc 'running-async?) (error "Process %s is already running an async command" proc))) (when (eq interrupt-callback t) (setq interrupt-callback (lambda (_proc)))) (process-put proc 'callbacks (list (cons callback 'suppress-output) interrupt-callback)) (process-put proc 'interruptable? (and interrupt-callback t)) (process-put proc 'running-async? t) (ess-command com buf nil 'no-prompt-check .01 proc)) (defun ess-async-command-delayed (com buf proc &optional callback delay) "Delayed asynchronous ess-command. COM and BUF are as in `ess-command'. DELAY is a number of idle seconds to wait before starting the execution of the COM. On interruption (by user's evaluation) ESS tries to rerun the job after next DELAY seconds, and the whole process repeats itself until the command manages to run completely. DELAY defaults to `ess-idle-timer-interval' + 3 seconds. You should always provide PROC for delayed evaluation, as the current process might change, leading to unpredictable consequences. This function is a wrapper of `ess-async-command' with an explicit interrupt-callback." (let* ((delay (or delay (+ ess-idle-timer-interval 3))) (int-cb `(lambda (proc) (ess-async-command-delayed ,com ,buf proc ,callback ,delay))) (com-fun `(lambda () (when (eq (process-status ,proc) 'run) ; do nothing if not running (if (or (process-get ,proc 'busy) ; if busy, try later (process-get ,proc 'running-async?)) ;; idle timer doesn't work here (run-with-timer ,delay nil 'ess-async-command-delayed ,com ,buf ,proc ,callback ,delay)) (ess-async-command ,com ,buf ,proc ,callback ',int-cb))))) (run-with-idle-timer delay nil com-fun))) (defun ess-load-library () "Prompt and load dialect specific library/package/module. Note that in R these are called `packages' and the name of this function has nothing to do with R package mechanism, but it rather serves a generic, dialect independent purpose. It is also similar to `load-library' Emacs function." (interactive) (let ((ess-eval-visibly-p t) (packs (ess-installed-packages)) pack) (setq pack (ess-completing-read "Load" packs)) (ess-load-library--override pack) (ess--mark-search-list-as-changed))) (cl-defgeneric ess-installed-packages () "Return a list of installed packages.") (cl-defgeneric ess-load-library--override (pack) "Load library/package PACK.") ;;*;; Evaluating lines, paragraphs, regions, and buffers. (defun ess-eval-linewise (text &optional invisibly eob even-empty wait-last-prompt sleep-sec wait-sec) "Evaluate TEXT in the ESS process buffer as if typed in w/o tabs. Waits for prompt after each line of input, so won't break on large texts. If optional second arg INVISIBLY is non-nil, don't echo commands. If it is a string, just include that string. If optional third arg EOB is non-nil, display ESS process buffer after evaluation. If optional 4th arg EVEN-EMPTY is non-nil, also send empty text (e.g. an empty line). If 5th arg WAIT-LAST-PROMPT is non-nil, also wait for the prompt after the last line; if 6th arg SLEEP-SEC is a number, ESS will call `(\\[sleep-for] SLEEP-SEC)' at the end of this function. If the 7th arg WAIT-SEC is set, it will be used instead of the default .001s and be passed to \\[ess-wait-for-process]. Run `comint-input-filter-functions' and `ess-presend-filter-functions' of the associated PROCESS on the TEXT." (ess-force-buffer-current "Process to use: ") ;; Use this to evaluate some code, but don't wait for output. (let* ((deactivate-mark) ; keep local {do *not* deactivate wrongly} (inf-proc (ess-get-process ess-current-process-name)) (inf-buf (process-buffer inf-proc)) (win (get-buffer-window inf-buf t))) (setq text (ess--concat-new-line-maybe (ess--run-presend-hooks inf-proc text))) (with-current-buffer inf-buf (setq text (propertize text 'field 'input 'front-sticky t)) (goto-char (marker-position (process-mark inf-proc))) (when (stringp invisibly) (insert-before-markers (concat "*** " invisibly " ***\n"))) ;; dbg: ;; dbg (ess-write-to-dribble-buffer ;; dbg (format "(eval-visibly 2): text[%d]= '%s'\n" (length text) text)) (while (or (> (length text) 0) even-empty) (setq even-empty nil) (let* ((pos (string-match "\n\\|$" text)) (input (if (= (length text) 0) "\n" (concat (substring text 0 pos) "\n")))) (setq text (substring text (min (length text) (1+ pos)))) (goto-char (marker-position (process-mark inf-proc))) (when win (set-window-point win (process-mark inf-proc))) (unless invisibly ;; for consistency with comint :( (insert (propertize input 'font-lock-face 'comint-highlight-input)) (set-marker (process-mark inf-proc) (point))) (inferior-ess-mark-as-busy inf-proc) (process-send-string inf-proc input)) (when (or (> (length text) 0) wait-last-prompt) (ess-wait-for-process inf-proc t (or wait-sec 0.001)))) (when eob (display-buffer inf-buf)) ;; This used to be conditioned on EOB but this is no longer the ;; case since commit fd90550d in 2012 (probably an accident) (goto-char (marker-position (process-mark inf-proc))) (when win (with-selected-window win (goto-char (point)) ;; this is crucial to avoid resetting window-point (recenter (- -1 scroll-margin)))))) (when (numberp sleep-sec) (sleep-for sleep-sec))) ;;;*;;; Evaluate only (defun ess-eval-region--normalise-region (start end) "Clean the region from START to END for evaluation. This trims newlines at beginning and end of the region because they might throw off the debugger." (save-excursion (goto-char start) (skip-chars-forward "\n\t ") (setq start (point)) (unless mark-active (ess-blink-region start end)) (goto-char end) (skip-chars-backward "\n\t ") (setq end (point)) (cons start end))) (defun ess-eval-region (start end vis &optional message type) "Send the region from START to END to the inferior ESS process. VIS switches the meaning of `ess-eval-visibly'. If given, MESSAGE is `message'ed. TYPE is a symbol indicating what type of region this is. If command `rectangle-mark-mode' is active, send the lines of the rectangle separately to the inferior process." (interactive "r\nP") (ess-force-buffer-current "Process to use: ") (message "Starting evaluation...") (unless ess-local-customize-alist ;; External applications might call ess-eval-* functions; make it ;; easier for them (ess-setq-vars-local (symbol-value (ess-get-process-variable 'ess-local-customize-alist)))) (if (bound-and-true-p rectangle-mark-mode) ;; If we're in rectangle-mark-mode, loop over each line of the ;; rectangle. Send them separately. (let ((reclines (extract-rectangle-bounds (min (mark) (point)) (max (mark) (point))))) (mapc (lambda (l) (ess--eval-region (car l) (cdr l) vis message type)) reclines)) (ess--eval-region start end vis message type))) (defun ess--eval-region (start end vis &optional message type) "Helper function for `ess-eval-region', which see. START, END, VIS, MESSAGE, and TYPE described there." (let* ((se (ess-eval-region--normalise-region start end)) (start (car se)) (end (cdr se))) (let ((visibly (if vis (not ess-eval-visibly) ess-eval-visibly)) (message (or message "Eval region")) (proc (ess-get-process))) (save-excursion (ess-send-region proc start end visibly message type))) (when ess-eval-deactivate-mark (ess-deactivate-mark)) (list start end))) (defun ess-eval-buffer (&optional vis) "Send the current buffer to the inferior ESS process. VIS has same meaning as for `ess-eval-region'." (interactive "P") (ess-eval-region (point-min) (point-max) vis "Eval buffer" 'buffer)) (defun ess-eval-buffer-from-beg-to-here (&optional vis) "Send region from beginning to point to the inferior ESS process. VIS has same meaning as for `ess-eval-region'." (interactive "P") (ess-eval-region (point-min) (point) vis "Eval buffer till point")) (defun ess-eval-buffer-from-here-to-end (&optional vis) "Send region from point to end of buffer to the inferior ESS process. VIS has same meaning as for `ess-eval-region'." (interactive "P") (ess-eval-region (point) (point-max) vis "Eval buffer till end")) (defun ess-eval-function (&optional vis) "Send the current function to the inferior ESS process. Prefix arg VIS toggles visibility of ess-code as for `ess-eval-region'. Returns nil if not inside a function." (interactive "P") (ess-force-buffer-current) (save-excursion (ignore-errors ;; Evaluation is forward oriented (forward-line -1) (ess-next-code-line 1)) (let ((pos (point)) beg end msg) (end-of-defun) (beginning-of-defun) ;; While we are the beginning of the function, get the function ;; name. FIXME: should use our ess-function-pattern. (setq msg (format "Eval function: %s" (if (looking-at add-log-current-defun-header-regexp) (match-string 1) (buffer-substring (point) (line-end-position))))) (setq beg (point)) (end-of-defun) (setq end (point)) (when (or (< pos beg) (< end pos)) (error "Not in a function")) (if (ess-tracebug-p) (ess-tracebug-send-function (get-process ess-local-process-name) beg end vis msg) (ess-eval-region beg end vis msg))))) (defun ess-eval-paragraph (&optional vis) "Send the current paragraph to the inferior ESS process. Prefix arg VIS toggles visibility of ess-code as for `ess-eval-region'." (interactive "P") (let ((start-pos (point))) (if (= (line-beginning-position) (point-min)) (ess-next-code-line 0) ;; Evaluation is forward oriented (forward-line -1) (ess-next-code-line 1)) (when (< (point) start-pos) (goto-char start-pos)) (save-excursion (let ((beg (progn (backward-paragraph) (point))) (end (progn (forward-paragraph) (point)))) (ess-eval-region beg end vis))))) (defun ess-eval-function-or-paragraph (&optional vis) "Send the current function if \\[point] is inside one. Otherwise send the current paragraph to the inferior ESS process. Prefix arg VIS toggles visibility of ess-code as for `ess-eval-region'. Returns \\='function if a function was evaluated or \\='paragraph if a paragraph." (interactive "P") (condition-case nil (progn (ess-eval-function vis) 'function) ;; TODO: Maybe be smarter than just catching all errors? (error (ess-eval-paragraph vis) 'paragraph))) (defun ess-eval-function-or-paragraph-and-step (&optional vis) "Send the current function if \\[point] is inside one. Otherwise send the current paragraph to the inferior ESS process. Prefix arg VIS toggles visibility of ess-code as for `ess-eval-region'." (interactive "P") (ess-skip-thing (ess-eval-function-or-paragraph vis)) (ess-next-code-line)) (defun ess-eval-region-or-function-or-paragraph (&optional vis) "Send the region, function, or paragraph depending on context. Send the region if it is active. If not, send function if `point' is inside one, otherwise the current paragraph. Treats rectangular regions as `ess-eval-region' does. Prefix arg VIS toggles visibility of ess-code as for `ess-eval-region'." (interactive "P") (if (use-region-p) (ess-eval-region (region-beginning) (region-end) vis) (ess-eval-function-or-paragraph vis))) (defun ess-eval-region-or-function-or-paragraph-and-step (&optional vis) "Send the region, function, or paragraph depending on context. Send the region if it is active. If not, send function if `point' is inside one, otherwise the current paragraph. Treats rectangular regions as `ess-eval-region' does. After evaluation step to the next code line or to the end of region if region was active. Prefix arg VIS toggles visibility of ess-code as for `ess-eval-region'." (interactive "P") (ess-skip-thing (ess-eval-region-or-function-or-paragraph vis)) (ess-next-code-line)) (defun ess-eval-region-or-line-and-step (&optional vis) "Evaluate region if active, otherwise `ess-eval-line-and-step'. See `ess-eval-region' for the meaning of VIS. Treats rectangular regions as `ess-eval-region' does." (interactive "P") (if (use-region-p) (ess-eval-region (region-beginning) (region-end) vis) (ess-eval-line-and-step))) (defun ess-eval-region-or-line-visibly-and-step () "Evaluate region if active, otherwise the current line and step. Evaluation is done visibly. Note that when inside a package and namespaced evaluation is in place (see `ess-r-set-evaluation-env') evaluation of multiline input will fail." (interactive) (ess-force-buffer-current) (display-buffer (ess-get-process-buffer) ;; Use a different window for the process buffer: '(nil (inhibit-same-window . t)) ;; Pass t to reusable-frames if users have help in ;; own frames, otherwise help frames get split to ;; display the inferior. (or (equal ess-help-own-frame 'one) ess-help-own-frame)) (let ((ess-eval-visibly t)) (ess-eval-region-or-line-and-step))) (defun ess-eval-line (&optional vis) "Send the current line to the inferior ESS process. VIS has same meaning as for `ess-eval-region'." (interactive "P") (let* ((beg (line-beginning-position)) (end (line-end-position)) (msg (format "Loading line: %s" (buffer-substring beg end)))) (ess-eval-region beg end vis msg))) (defun ess-eval-line-and-step (&optional vis) "Evaluate the current line and step to the \"next\" line. See `ess-eval-region' for VIS." (interactive "P") (ess-eval-line vis) (ess-skip-thing 'line) (ess-next-code-line)) (defun ess-eval-line-visibly-and-step (&optional simple-next) "Evaluate the current line visibly and step to the \"next\" line. If SIMPLE-NEXT is non-nil, possibly via prefix arg, first skip empty and commented lines. When the variable `ess-eval-empty' is non-nil both SIMPLE-NEXT and EVEN-EMPTY are interpreted as true. Note that when inside a package and namespaced evaluation is in place (see `ess-r-set-evaluation-env'), the evaluation of multiline input will fail." (interactive "P") (ess-force-buffer-current) (display-buffer (ess-get-process-buffer) ;; Use a different window for the process buffer: '(nil (inhibit-same-window . t)) ;; Pass t to reusable-frames if users have help in ;; own frames, otherwise help frames get split to ;; display the inferior. (or (equal ess-help-own-frame 'one) ess-help-own-frame)) (let ((ess-eval-visibly t) (ess-eval-empty (or ess-eval-empty simple-next))) (ess-eval-line) (ess-skip-thing 'line) (ess-next-code-line))) (defun ess-eval-line-invisibly-and-step () "Evaluate the current line invisibly and step to the next line. Evaluate all comments and empty lines." (interactive) (let ((ess-eval-visibly nil)) (ess-eval-line-and-step))) (define-obsolete-function-alias 'ess-eval-line-and-step-invisibly #'ess-eval-line-invisibly-and-step "18.10") ;;;*;;; Evaluate and switch to S (defun ess-eval-region-and-go (start end &optional vis) "Send region from START to END to the inferior process buffer. START and END default to the current region, and rectangular regions are treated as `ess-eval-region'. VIS has same meaning as for `ess-eval-region'." (interactive "r\nP") (ess-eval-region start end vis) (ess-switch-to-ESS t)) (defun ess-eval-buffer-and-go (&optional vis) "Send the current buffer to the inferior S and switch to the process buffer. VIS has same meaning as for `ess-eval-region'." (interactive "P") (ess-eval-buffer vis) (ess-switch-to-ESS t)) (defun ess-eval-function-and-go (&optional vis) "Send the current function, then switch to the inferior process buffer. VIS has same meaning as for `ess-eval-region'." (interactive "P") (ess-eval-function vis) (ess-switch-to-ESS t)) (defun ess-eval-line-and-go (&optional vis) "Send the current line, then switch to the inferior process buffer. VIS has same meaning as for `ess-eval-region'." (interactive "P") (ess-eval-line vis) (ess-switch-to-ESS t)) (defun ess-eval-paragraph-and-go (&optional vis) "Send the current paragraph, then switch to the inferior process buffer. VIS has same meaning as for `ess-eval-region'." (interactive "P") (ess-eval-paragraph vis) (ess-switch-to-ESS t)) (defun ess-eval-paragraph-and-step (&optional vis) "Evaluate the current paragraph and move point to the next line. If not inside a paragraph, evaluate the next one. VIS has same meaning as for `ess-eval-region'." (interactive "P") (ess-eval-paragraph vis) (ess-skip-thing 'paragraph) (ess-next-code-line)) ; Inferior ESS mode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; In this section: ;;;; ;;;; * The major mode inferior-ess-mode ;;;; * Process handling code ;;;; * Completion code ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;*;; Major mode definition (defvar inferior-ess-mode-map (let ((map (make-sparse-keymap))) (define-key map "\C-y" #'ess-yank) (define-key map "\r" #'inferior-ess-send-input) (define-key map "\C-a" #'comint-bol) ;; 2010-06-03 SJE ;; disabled this in favor of ess-dirs. Martin was not sure why this ;; key was defined anyway in this mode. ;;(define-key map "\M-\r" #'ess-transcript-send-command-and-move) (define-key map "\C-c\M-l" #'ess-load-file) (define-key map "\C-c`" #'ess-show-traceback) (define-key map [(control ?c) ?~] #'ess-show-call-stack) (define-key map "\C-c\C-d" #'ess-dump-object-into-edit-buffer) (define-key map "\C-c\C-v" #'ess-display-help-on-object) (define-key map "\C-c\C-q" #'ess-quit) (define-key map "\C-c\C-s" #'ess-execute-search) (define-key map "\C-c\C-x" #'ess-execute-objects) (define-key map "\C-c\034" #'ess-abort) ; \C-c\C-backslash (define-key map "\C-c\C-z" #'ess-switch-to-inferior-or-script-buffer) ; mask comint map (define-key map "\C-d" #'delete-char) ; EOF no good in S (define-key map "\t" #'completion-at-point) (define-key map "\M-?" #'ess-complete-object-name) (define-key map "\C-c\C-k" #'ess-request-a-process) (define-key map "," #'ess-smart-comma) (define-key map "\C-c\C-d" 'ess-doc-map) (define-key map "\C-c\C-e" 'ess-extra-map) (define-key map "\C-c\C-t" 'ess-dev-map) map) "Keymap for `inferior-ess' mode.") (easy-menu-define inferior-ess-mode-menu inferior-ess-mode-map "Menu for use in Inferior S mode" '("iESS" ["Quit" ess-quit t] ["Reload process" inferior-ess-reload t] ;; ["Send and move" ess-transcript-send-command-and-move t] ["Copy command" comint-copy-old-input t] ["Send command" inferior-ess-send-input t] ["Switch to script buffer" ess-switch-to-inferior-or-script-buffer t] ["Get help on S object" ess-display-help-on-object t] "------" ("Process" ["Process Echoes" (lambda () (interactive) (setq comint-process-echoes (not comint-process-echoes))) :active t :style toggle :selected comint-process-echoes] ("Eval visibly " :filter ess--generate-eval-visibly-submenu )) "------" ("Utils" ["Attach directory" ess-execute-attach t] ["Display object list" ess-execute-objects t] ["Display search list" ess-execute-search t] ["Edit S object" ess-dump-object-into-edit-buffer t] ["Enter S command" ess-execute t] ["Jump to error" ess-parse-errors t] ["Load source file" ess-load-file t] ["Resynch S completions" ess-resynch t] ["Recreate R versions known to ESS" (lambda () (interactive) (ess-r-redefine-runners 'verbose)) t] ) "------" ("start-dev" :visible nil); <-- ?? ("end-dev" :visible nil) "------" ("Font Lock" :active ess-font-lock-keywords :filter ess--generate-font-lock-submenu) "------" ["Describe" describe-mode t] ["Send bug report" ess-submit-bug-report t] ["About" (ess-goto-info "Entering Commands") t] )) (defvar ess-mode-minibuffer-map (let ((map (make-sparse-keymap))) (set-keymap-parent map minibuffer-local-map) (define-key map "\t" #'ess-complete-object-name) (define-key map "\C-\M-i" #'ess-complete-object-name) ;; doesn't work:( (define-key map "\C-c\C-s" #'ess-execute-search) (define-key map "\C-c\C-x" #'ess-execute-objects) map) "Keymap used in `ess-execute'.") (define-derived-mode inferior-ess-mode comint-mode "iESS" "Major mode for interacting with an inferior ESS process. To learn more about how to use inferior ess modes, see Info node `(ess)Top'. If you accidentally suspend your process, use \\[comint-continue-subjob] to continue it." :group 'ess-proc (setq-local comint-input-sender 'inferior-ess-input-sender) (setq-local font-lock-fontify-region-function #'inferior-ess-fontify-region) ;; If comint-process-echoes is t inferior-ess-input-sender ;; recopies the input, otherwise not (setq-local comint-process-echoes (not (member ess-language '("SAS" "XLS" "OMG" "julia")))) (when comint-use-prompt-regexp ;; why comint is not setting this? bug? (setq-local inhibit-field-text-motion t)) (unless inferior-ess-prompt ;; build when unset (setq inferior-ess-prompt (concat "\\(" inferior-ess-primary-prompt (when inferior-ess-secondary-prompt "\\|") inferior-ess-secondary-prompt "\\)"))) (setq comint-prompt-regexp (concat "^" inferior-ess-prompt)) (setq mode-line-process '(" [" ess--mode-line-process-indicator ess--local-mode-line-process-indicator "]: %s")) ;;; Completion support ---------------- (remove-hook 'completion-at-point-functions #'comint-completion-at-point t) ;; reset the hook (add-hook 'completion-at-point-functions #'comint-c-a-p-replace-by-expanded-history nil 'local) (add-hook 'completion-at-point-functions #'ess-filename-completion nil 'local) ;; hyperlinks support (goto-address-mode t) ;; Avoid spaces after filenames (setq-local comint-completion-addsuffix (cons "/" "")) (setq comint-input-autoexpand t) ; Only for completion, not on input. (add-hook 'window-configuration-change-hook #'ess-set-width nil t) (setq-local indent-tabs-mode nil) (setq-local paragraph-start (concat inferior-ess-primary-prompt "\\|\^L")) (setq-local paragraph-separate "\^L") (setq-local jit-lock-chunk-size inferior-ess-jit-lock-chunk-size)) ;;*;; Commands used exclusively in inferior-ess-mode ;;;*;;; Main user commands (defun inferior-ess-input-sender (proc string) (inferior-ess--interrupt-subjob-maybe proc) (let ((comint-input-filter-functions nil)) ; comint runs them, don't run twice. (if comint-process-echoes (ess-eval-linewise string nil nil ess-eval-empty) (ess-send-string proc string)))) (defvar ess-help-arg-regexp "\\(['\"]?\\)\\([^,=)'\"]*\\)\\1" "Reg(ular) Ex(pression) of help(.) arguments. MUST: 2nd \\(.\\) = arg.") (defun inferior-ess-send-input () "Sends the command on the current line to the ESS process." (interactive) (run-hooks 'ess-send-input-hook) (unless (ess-process-get 'busy) ;; avoid new line insertion (ess-process-put 'prev-prompt nil)) (comint-send-input) (setq ess-object-list nil)) (defun inferior-ess--goto-input-start:field () "Move point to the beginning of input skipping all continuation lines. If in the output field, goes to the beginning of previous input field. Note: `inferior-ess-secondary-prompt' should match exactly." (goto-char (field-beginning)) ;; move to the beginning of non-output field (while (and (not (bobp)) (eq (field-at-pos (point)) 'output)) (goto-char (field-beginning nil t))) ;; skip all secondary prompts (let ((pos (field-beginning (point) t)) (secondary-prompt (concat "^" inferior-ess-secondary-prompt))) (while (and pos (if (eq (get-text-property pos 'field) 'output) (string-match secondary-prompt (field-string-no-properties pos)) t)) (goto-char pos) (setq pos (previous-single-property-change pos 'field))))) (defun inferior-ess--goto-input-end:field () "Move point to the end of input skipping all continuation lines. If in the output field, goes to the beginning of previous input field. NOTE: to be used only with fields, see `comint-use-prompt-regexp'." ;; this func is not used but might be useful some day (goto-char (field-end)) (let ((pos (point)) (secondary-prompt (concat "^" inferior-ess-secondary-prompt))) (while (and pos (if (eq (get-text-property pos 'field) 'output) (string-match secondary-prompt (field-string-no-properties pos)) t)) (goto-char pos) (setq pos (next-single-property-change pos 'field))))) (defun inferior-ess--get-old-input:field () "Return the ESS command surrounding point (use with fields)." (save-excursion (if (eq (field-at-pos (point)) 'output) (if (called-interactively-p 'any) (error "No command on this line") ;; else, just return "" "") (inferior-ess--goto-input-start:field) (let ((command (field-string-no-properties (point))) (pos (next-single-property-change (point) 'field )) (secondary-prompt (concat "^" inferior-ess-secondary-prompt))) (while (and pos (cond ((eq (get-text-property pos 'field) 'input) (setq command (concat command "\n" (field-string-no-properties pos)))) ((eq (get-text-property pos 'field) 'output) (string-match secondary-prompt (field-string-no-properties pos))) (t)));; just skip if unknown (setq pos (next-single-property-change pos 'field))) command)))) ;; TODO: error when entering a multiline function ;; check.integer <- function(N){ ;; is.integer(N) | !length(grep("[^[:digit:]]", as.character(N))) ;; } (defun inferior-ess--goto-input-start:regexp () "Move point to the beginning of input skipping all continuation lines. If in the output field, goes to the beginning of previous input." (beginning-of-line) (unless (looking-at inferior-ess-prompt) (re-search-backward (concat "^" inferior-ess-prompt) nil t)) ;; at bol (when (and inferior-ess-secondary-prompt (looking-at inferior-ess-secondary-prompt)) (while (and (> (forward-line -1) -1) (looking-at inferior-ess-secondary-prompt)))) (unless (looking-at inferior-ess-prompt) (error "Beginning of input not found")) (comint-skip-prompt)) (defun inferior-ess--get-old-input:regexp () "Return the ESS command surrounding point (use regexp)." ;;VS[03-09-2012]: This should not rise errors!! Troubles comint-interrupt-subjob (save-excursion (let* ((inhibit-field-text-motion t) command) (beginning-of-line) (when (and inferior-ess-secondary-prompt (looking-at inferior-ess-secondary-prompt)) (inferior-ess--goto-input-start:regexp)) (beginning-of-line) (if (looking-at inferior-ess-prompt) ; cust.var, might not include sec-prompt (progn (comint-skip-prompt) (setq command (buffer-substring-no-properties (point) (line-end-position))) (when inferior-ess-secondary-prompt (while (progn (forward-line 1) (looking-at inferior-ess-secondary-prompt)) (re-search-forward inferior-ess-secondary-prompt (line-end-position) t) (setq command (concat command "\n" (buffer-substring-no-properties (point) (line-end-position)))))) (forward-line -1) command) (message "No command at this point") "")))) (defun inferior-ess-get-old-input () "Return the ESS command surrounding point." (if comint-use-prompt-regexp (inferior-ess--get-old-input:regexp) (inferior-ess--get-old-input:field))) (defun ess-can-eval-in-background (&optional proc) "Can the current process be used for background commands. Inspects the `ess-can-eval-in-background' variable as well as the `bg-eval-disabled' property of PROC or of the current process, if any. This makes it possible to disable background evals for a specific process, for instance in case it was not initialized properly." (when ess-can-eval-in-background (when-let ((proc (or proc (ess-get-current-process)))) (not (process-get proc 'bg-eval-disabled))))) ;;;*;;; Hot key commands (defun ess-execute-objects (posn) "Send the objects() command to the ESS process. By default, gives the objects at position 1. A prefix argument toggles the meaning of `ess-execute-in-process-buffer'. A prefix argument of 2 or more means get objects for that position. A negative prefix argument gets the objects for that position and toggles `ess-execute-in-process-buffer' as well." (interactive "P") (ess-make-buffer-current) (let* ((num-arg (if (listp posn) (if posn -1 1) (prefix-numeric-value posn))) (the-posn (if (< num-arg 0) (- num-arg) num-arg)) (invert (< num-arg 0)) (the-command (format inferior-ess-objects-command the-posn ".*")) (the-message (concat ">>> Position " (number-to-string the-posn) " (" (nth (1- the-posn) (ess-search-list)) ")\n"))) (ess-execute the-command invert "S objects" the-message))) (defun ess-execute-search (invert) "Send the `inferior-ess-search-list-command' command. INVERT is as in `ess-execute'. E.g. search(..) in S." (interactive "P") (ess-execute inferior-ess-search-list-command invert "S search list")) ;; FIXME --- this *only* works in S / S-plus; not in R ;; ----- ("at least" is not assigned to any key by default) (defun ess-execute-attach (dir &optional posn) "Attach a directory in the `ess-language' process with the attach() command. When used interactively, user is prompted for DIR to attach and prefix argument is used for POSN (or 2, if absent.) Doesn't work for data frames." (interactive "Attach directory: \nP") (ess-execute (concat "attach(\"" (directory-file-name (expand-file-name dir)) "\"" (if posn (concat "," (number-to-string (prefix-numeric-value posn)))) ")") 'buffer) (ess-process-put 'sp-for-help-changed? t)) (defun ess-execute-screen-options (&optional invisibly) "Cause S to set the \"width\" option to 1 less than the window width. Also sets the \"length\" option to 99999. When INVISIBLY is non-nil, don't echo to R subprocess. This is a good thing to put in `ess-r-post-run-hook' or `ess-S+-post-run-hook'." (interactive) (ess-if-verbose-write (format "ess-execute-screen-options: invisibly=%s\n" invisibly)) (if (null ess-execute-screen-options-command) (message "Not implemented for '%s'" ess-dialect) (let ((command (ess-calculate-width 'window))) (if invisibly (ess-command command) (ess-eval-linewise command nil nil nil 'wait-prompt))))) ;; Runs in background if inferior is not busy (defun ess--execute-screen-options-bg () (when (and ess-execute-screen-options-command (inferior-ess-available-p)) (ess-execute-screen-options t))) (defun ess-calculate-width (opt) "Calculate width command given OPT. OPT can be \\='window, \\='frame, or an integer. Return a command suitable to send to the inferior process (e.g. \"options(width=80, length=999999)\")." (when (null ess-execute-screen-options-command) (error "Not implemented for %s" ess-dialect)) (let (command) (cond ((and (integerp opt) (>= opt 0)) (setq command (format ess-execute-screen-options-command opt))) ((or (eql 'window opt) (and (integerp opt) (> 0 opt))) ;; We cannot use (window-width) here because it returns sizes ;; in default (frame) characters which leads to incorrect ;; sizes with scaled fonts.To solve this we approximate font ;; width in pixels and use window-pixel-width to compute the ;; approximate number of characters that fit into line. (let* ((wedges (window-inside-pixel-edges)) (wwidth (- (nth 2 wedges) (nth 0 wedges))) (nchars (floor (/ wwidth (default-font-width))))) (when (and (integerp opt) (> 0 opt)) (setq nchars (- nchars (- opt)))) (setq command (format ess-execute-screen-options-command nchars)))) ((eql 'frame opt) (setq command (format ess-execute-screen-options-command (frame-width)))) (t (error "OPT (%s) not 'window, 'frame or an integer" opt))) command)) (defun ess-set-width () "Set the width option. A part of `window-configuration-change-hook' in inferior ESS buffers." (when (and ess-auto-width ess-execute-screen-options-command) ;; `window-configuration-change-hook' runs with the window selected. (let ((proc (get-buffer-process (window-buffer))) command) ;; TODO: Set the width once the process is no longer busy. (when (and (process-live-p proc) (not (process-get proc 'busy))) (setq command (ess-calculate-width ess-auto-width)) (if ess-auto-width-visible (ess-eval-linewise command nil nil nil 'wait-prompt) (ess-command command)))))) (defun ess-execute (command &optional invert buff message) "Send a command to the ESS process. A newline is automatically added to COMMAND. Prefix arg (or second arg INVERT) means invert the meaning of `ess-execute-in-process-buffer'. If INVERT is \\='buffer, output is forced to go to the process buffer. If the output is going to a buffer, name it *BUFF*. This buffer is erased before use. Optional fourth arg MESSAGE is text to print at the top of the buffer (defaults to the command if BUFF is not given.)" (interactive (list ;; simpler way to set proc name in mb? (let ((enable-recursive-minibuffers t) (proc-name (progn (ess-force-buffer-current) ess-local-process-name))) (with-current-buffer (get-buffer " *Minibuf-1*") ;; FIXME: hardcoded name (setq ess-local-process-name proc-name)) (read-from-minibuffer "Execute> " nil ess-mode-minibuffer-map)) current-prefix-arg)) (ess-make-buffer-current) (let ((the-command (concat command "\n")) (buff-name (concat "*" (or buff "ess-output") "*")) (in-pbuff (if invert (or (eq invert 'buffer) (not ess-execute-in-process-buffer)) ess-execute-in-process-buffer))) (if in-pbuff (ess-eval-linewise the-command) (ess-with-current-buffer (get-buffer-create buff-name) (ess-command the-command (current-buffer) nil nil nil (get-process ess-local-process-name)) (ansi-color-apply-on-region (point-min) (point-max)) (goto-char (point-min)) (if message (insert message) (insert "> " the-command)) (display-buffer (current-buffer)))))) ;;;*;;; Quitting (cl-defgeneric ess-quit--override (_arg) "Stop the inferior process." (let ((proc (ess-get-process))) (ess-cleanup) (when ess-eval-visibly (goto-char (marker-position (process-mark proc))) (insert inferior-ess-exit-command)) (process-send-string proc inferior-ess-exit-command))) (defun ess-quit (&optional arg) "Issue an exiting command to the inferior process. Runs `ess-cleanup'. ARG gets passed to a language specific method, see `ess-quit--override'." (interactive "P") (unless (ess-process-live-p) (user-error "No live ESS process associated with this buffer")) (ess-force-buffer-current "Process to quit: ") (ess-interrupt) (ess-make-buffer-current) (ess-quit--override arg)) (defvar ess--interrupt-timeout 5) (defun ess-interrupt () "Interrupt the inferior process. This sends an interrupt and quits a debugging session." (interactive) (inferior-ess-force) (let ((proc (ess-get-process))) (ess--interrupt proc) (unless (ess-wait-for-process proc nil nil nil ess--interrupt-timeout) (error "Timeout while interrupting process")) (with-current-buffer (process-buffer proc) (goto-char (process-mark proc))))) (defun ess--interrupt (proc) (interrupt-process proc comint-ptyp) ;; Workaround for Windows terminals. NOTE: Is this really needed ;; for background commands? Or just for interactive interrupts? (unless (memq system-type '(gnu/linux darwin)) (process-send-string nil "\n"))) (defun ess-abort () "Kill the ESS process, without executing .Last or terminating devices. If you want to finish your session, use \\[ess-quit] instead." ;;; Provided as a safety measure over the default binding of C-c C-z in ;;; comint-mode-map. (interactive) (ding) (message "WARNING: \\[inferior-ess-exit-command] will not be executed and graphics devices won't finish properly!") (sit-for 2) (if (y-or-n-p "Still abort? ") (comint-quit-subjob) (message "Good move."))) (defun ess-cleanup () "Cleanup buffers associated with the process. Possibly kill or offer to kill, depending on the value of `ess-S-quit-kill-buffers-p', all buffers associated with this ESS process. Uses `display-buffer' to display the process buffer. It is run automatically by \\[ess-quit]." (interactive) (let* ((the-procname (or (ess-make-buffer-current) ess-local-process-name)) (buf (buffer-name (process-buffer (get-process the-procname))))) (unless the-procname (error "I don't know which ESS process to clean up after!")) (when (or (eq ess-S-quit-kill-buffers-p t) (and (eq ess-S-quit-kill-buffers-p 'ask) (y-or-n-p (format "Delete all buffers associated with process %s? " the-procname)))) (dolist (buf (buffer-list)) (with-current-buffer buf ;; Consider buffers for which ess-local-process-name is ;; the same as the-procname (when (and (not (get-buffer-process buf)) ess-local-process-name (equal ess-local-process-name the-procname)) (kill-buffer buf))))) (display-buffer buf) buf)) (defun inferior-ess-reload (&optional start-args) "Reload the inferior process. START-ARGS gets passed to the dialect-specific `inferior-ess-reload-override'." (interactive) (let* ((inf-buf (inferior-ess-force)) (inf-proc (get-buffer-process inf-buf)) (inf-start-data (buffer-local-value 'inferior-ess--local-data inf-buf)) (start-name (car inf-start-data)) (start-args (or start-args (cdr inf-start-data)))) ;; Interrupt early so we can get working directory (ess-interrupt) ;; Quit debugging session before reloading (when (ess-debug-active-p) (ess-debug-command-quit) (ess-wait-for-process inf-proc nil nil nil 1)) (save-window-excursion ;; Make sure we don't ask for directory again ;; Use current working directory as default (let ((project-find-functions nil) (ess-startup-directory-function nil) (ess-startup-directory (ess-get-process-variable 'default-directory)) (ess-ask-for-ess-directory nil)) (ess-quit 'no-save) (inferior-ess--wait-for-exit inf-proc) (with-current-buffer inf-buf (inferior-ess-reload--override start-name start-args)))))) (cl-defgeneric inferior-ess-reload--override (_start-name _start-args) (user-error "Reloading not implemented for %s" ess-dialect)) (defun inferior-ess--wait-for-exit (proc) "Wait for process PROC to exit. This should be used instead of `ess-wait-for-process' for waiting after issuing a quit command as the latter assumes a live process." (let ((start-time (float-time))) (while (eq (process-status proc) 'run) (accept-process-output proc 0.002) (when (> (- (float-time) start-time) 30) (error "Timeout while quitting process"))))) ;;;*;;; Support functions (defun ess-extract-onames-from-alist (alist posn &optional force) "Return the object names in position POSN of ALIST. ALIST is an alist like `ess-sl-modtime-alist'. POSN should be in 1 .. (length ALIST). If optional third arg FORCE is t, the corresponding element of the search list is re-read. Otherwise it is only re-read if it's a directory and has been modified since it was last read." (let* ((entry (nth (1- posn) alist)) (dir (car entry)) (timestamp (car (cdr entry))) (new-modtime (and timestamp (ess-dir-modtime dir)))) ;; Refresh the object listing if necessary (if (or force (not (equal new-modtime timestamp))) (setcdr (cdr entry) (ess-object-names dir posn))) (cdr (cdr entry)))) (defun ess-dir-modtime (dir) "Return the last modtime if DIR is a directory, and nil otherwise." (and ess-filenames-map (file-directory-p dir) (nth 5 (file-attributes dir)))) (defun ess-object-modtime (object) "Return the modtime of the S object OBJECT (a string). Searches along the search list for a file named OBJECT and returns its modtime Returns nil if that file cannot be found, i.e., for R or any non-S language!" (let ((path (ess-search-list)) result) (while (and (not result) path) (setq result (file-attributes (concat (file-name-as-directory (car path)) object))) (setq path (cdr path))) (nth 5 result))) (defun ess-modtime-gt (mod1 mod2) "Return t if MOD1 is later than MOD2." (and mod1 (or (> (car mod1) (car mod2)) (and (= (car mod1) (car mod2)) (> (car (cdr mod1)) (car (cdr mod2))))))) (defun ess-get-object-list (name &optional exclude-first) "Return a list of current S object names associated with process NAME. Uses `ess-object-list' if that is non-nil. If EXCLUDE-FIRST is non-nil, don't return objects in first position (.GlobalEnv)." (or ess-object-list ;; <<- MM: this is now always(?) nil; we cache the *-modtime-alist (with-current-buffer (process-buffer (ess-get-process name)) (ess-make-buffer-current) (ess-write-to-dribble-buffer (format "(get-object-list %s) .." name)) (if (or (not ess-sl-modtime-alist) (ess-process-get 'sp-for-help-changed?)) (progn (ess-write-to-dribble-buffer "--> (ess-get-modtime-list)\n") (ess-get-modtime-list)) ;;else (ess-write-to-dribble-buffer " using existing ess-sl-modtime-alist\n")) (let* ((alist ess-sl-modtime-alist) (i 2) (n (length alist)) result) (ess-write-to-dribble-buffer (format " (length alist) : %d\n" n)) (unless exclude-first ;; re-read of position 1 : (setq result (ess-extract-onames-from-alist alist 1 'force))) (ess-write-to-dribble-buffer (format " have re-read pos=1: -> length %d\n" (length result))) ;; Re-read remaining directories if necessary. (while (<= i n) (setq result (append result (ess-extract-onames-from-alist alist i))) (setq i (1+ i))) (setq ess-object-list (delete-dups result)))))) (defun ess-get-words-from-vector (command &optional no-prompt-check wait proc timeout) "Evaluate the S command COMMAND, which returns a character vector. Return the elements of the result of COMMAND as an alist of strings. COMMAND should have a terminating newline. NO-PROMPT-CHECK, WAIT, PROC, and TIMEOUT are passed to `ess-command'. FILTER may be the keyword \\='non-... or nil. To avoid truncation of long vectors, wrap your command (%s) like this, or a version with explicit options(max.print=1e6): \"local({ out <- try({%s}); print(out, max=1e6) })\n\"." (unless proc (inferior-ess-force)) (let* ((tbuffer (get-buffer-create " *ess-get-words*")); initial space: disable-undo (word-RE (concat "\\(" "\\\\\"" "\\|" "[^\"]" ; \" or non-"-char "\\)*")) (full-word-regexp (concat "\"" "\\(" word-RE "\\)" "\"" "\\( \\|$\\)"; space or end )) words) (ess-command command tbuffer 'sleep no-prompt-check wait proc nil timeout) (with-current-buffer tbuffer (goto-char (point-min)) (while (re-search-forward full-word-regexp nil t) (setq words (cons (buffer-substring (match-beginning 1) (match-end 1)) words)))) (ess-if-verbose-write (if (> (length words) 5) (format " |-> (length words)= %d\n" (length words)) (format " |-> words= '%s'\n" words))) (reverse words))) (defun ess-get-words-from-vector--foreground (command &optional no-prompt-check wait proc) (let ((timeout most-positive-fixnum)) (ess-get-words-from-vector command no-prompt-check wait proc timeout))) (defun ess-compiled-dir (dir) "Return non-nil if DIR is an S object directory with special files. I.e. if the filenames in DIR are not representative of the objects in DIR." (or (file-exists-p (concat (file-name-as-directory dir) "___nonfile")) (file-exists-p (concat (file-name-as-directory dir) "__BIGIN")) (file-exists-p (concat (file-name-as-directory dir) "___NONFI")))) (defun ess-object-names (obj &optional pos) "Return alist of S object names in directory (or object) OBJ. If OBJ is a directory name (begins with `/') returns a listing of that dir. This may use the search list position POS if necessary. If OBJ is an object name, returns result of the command `inferior-ess-safe-names-command'. If POS is supplied return the result of the command in `inferior-ess-objects-command'. If OBJ is nil or not a directory, POS must be supplied. In all cases, the value is an list of object names." (cond ((and (stringp obj) (string-match-p "ESSR" obj)) nil) ;; FIXME: in both cases below, the same fallback "objects(POS)" is used -- merge! ((and obj (file-accessible-directory-p obj)) ;; Check the pre-compiled object list in ess-object-name-db first ;; FIXME: If used at all, ess-object-name-db should not only ;; ----- be used in the directory case !! (or (cdr-safe (assoc obj ess-object-name-db)) ;; Take a directory listing (and ess-filenames-map ;; first try .Data subdirectory: ;;FIXME: move ".Data" or ``this function'' to ess-sp6-d.el etc: (let ((dir (concat (file-name-as-directory obj) ".Data"))) (if (not (file-accessible-directory-p dir)) (setq dir obj)) (and (not (ess-compiled-dir dir)) (directory-files dir)))) ;; Get objects(pos) instead (and (or (ess-write-to-dribble-buffer (format "(ess-object-names ..): directory %s not used\n" obj)) t) pos (ess-get-words-from-vector (format inferior-ess-objects-command pos))))) ((and obj ;; want names(obj) (ess-get-words-from-vector (format inferior-ess-safe-names-command obj)))) (pos (ess-get-words-from-vector (format inferior-ess-objects-command pos))))) (defun ess-slot-names (obj) "Return alist of S4 slot names of S4 object OBJ." (ess-get-words-from-vector (format "slotNames(%s)\n" obj))) (defun ess-function-arguments (funname &optional proc) "Get FUNARGS from cache or ask the process for it. Return FUNARGS - a list with the first element being a cons (PACKAGE_NAME . TIME_STAMP), second element is a string giving arguments of the function as they appear in documentation, third element is a list of arguments of all methods. If PROC is given, it should be an ESS process. If PACKAGE_NAME is nil, and TIME_STAMP is less recent than the time of the last user interaction to the process, then update the entry. PACKAGE_NAME is also nil when FUNNAME was not found, or FUNNAME is a special name that contains :,$ or @." (when (and funname ;; usually returned by ess--fn-name-start (might be nil) (or proc (ess-process-live-p))) (let* ((proc (or proc (get-process ess-local-process-name))) (cache (or (process-get proc 'funargs-cache) (let ((cache (make-hash-table :test 'equal))) (process-put proc 'funargs-cache cache) cache))) (args (gethash funname cache)) (pack (caar args)) (ts (cdar args))) (when (and args (and (time-less-p ts (process-get proc 'last-eval)) (or (null pack) (equal pack "")))) ;; reset cache (setq args nil)) (or args (cadr (assoc funname (process-get proc 'funargs-pre-cache))) (and (not (process-get proc 'busy)) (with-current-buffer (ess-command (format ess-funargs-command (ess-quote-special-chars funname)) nil nil nil nil proc) (goto-char (point-min)) (when (re-search-forward "(list" nil t) (goto-char (match-beginning 0)) (setq args (ignore-errors (eval (read (current-buffer)) t))) (when args (setcar args (cons (car args) (current-time))))) ;; push even if nil (puthash (substring-no-properties funname) args cache))))))) ;;; SJE: Wed 29 Dec 2004 --- remove this function. ;;; rmh: Wed 5 Jan 2005 --- bring it back for use on Windows (defun ess-create-object-name-db () "Create a database of object names in standard S directories. This database is saved in the file specified by `ess-object-name-db-file', and is loaded when `ess-mode' is loaded. It defines the variable `ess-object-name-db', which is used for completions. Before you call this function, modify the S search list so that it contains all the non-changing (i.e. system) S directories. All positions of the search list except for position 1 are searched and stored in the database. After running this command, you should move ess-namedb.el to a directory in the `load-path'." (interactive) (setq ess-object-name-db nil) (let ((search-list (cdr (ess-search-list))) (pos 2) name (buffer (get-buffer-create " *ess-db*")) (temp-object-name-db nil)) (ess-write-to-dribble-buffer (format "(object db): search-list=%s \n " search-list)) (while search-list (message "Searching %s" (car search-list)) (setq temp-object-name-db (cons (cons (car search-list) (ess-object-names nil pos)) temp-object-name-db)) (setq search-list (cdr search-list)) (ess-write-to-dribble-buffer (format "(object db): temp-obj-name-db=%s \n pos=%s" temp-object-name-db pos)) (setq pos (1+ pos))) (with-current-buffer buffer (erase-buffer) (insert "(setq ess-object-name-db '") (prin1 temp-object-name-db (current-buffer)) (insert ")\n") (setq name (expand-file-name ess-object-name-db-file)) (write-region (point-min) (point-max) name) (message "Wrote %s" name)) (kill-buffer buffer) (setq ess-object-name-db temp-object-name-db))) (defun ess-resynch nil "Reread all directories and objects in `ess-search-list' for completions." (interactive) (if (ess-make-buffer-current) nil (error "Not an ESS process buffer")) (setq ess-sl-modtime-alist nil ess-object-list nil ess-object-name-db nil ; perhaps it would be better to reload? ) (ess-process-put 'sp-for-help-changed? t) ;; Action! : (ess-get-modtime-list)) (defun ess-filename-completion () "Return completion only within string or comment." (save-restriction ;; explicitly handle inferior-ess (ignore-errors (when (and (derived-mode-p 'inferior-ess-mode) (> (point) (process-mark (get-buffer-process (current-buffer))))) (narrow-to-region (process-mark (get-buffer-process (current-buffer))) (point-max)))) (when (and (not (equal ?` (nth 3 (syntax-ppss (point))))) (ess-inside-string-or-comment-p (point))) (append (comint-filename-completion) '(:exclusive no))))) (defun ess-complete-filename () "Do file completion only within strings." (declare (obsolete comint-filename-completion "ESS 19.04")) (save-restriction ;; explicitly handle inferior-ess (ignore-errors (when (and (derived-mode-p 'inferior-ess-mode) (> (point) (process-mark (get-buffer-process (current-buffer))))) (narrow-to-region (process-mark (get-buffer-process (current-buffer))) (point-max)))) (when (or (ess-inside-string-or-comment-p (point))) ;; usable within ess-mode as well (comint-dynamic-complete-filename)))) (defun ess-after-pathname-p nil ;; Heuristic: after partial pathname if it looks like we're in a ;; string, and that string looks like a pathname. Not the best for ;; use with unix() (or it's alias, !). Oh well. (declare (obsolete comint-filename-completion "ESS 19.04")) (save-excursion (save-match-data (let ((opoint (point))) (and (re-search-backward "\\(\"\\|'\\)[~/#$.a-zA-Z0-9][^ \t\n\"']*" nil t) (eq opoint (match-end 0))))))) ;;*;; Functions handling the search list (defun ess-search-list (&optional force-update) "Return the current search list as a list of strings. Elements which are apparently directories are expanded to full dirnames. Don't try to use cache if FORCE-UPDATE is non-nil. Is *NOT* used by \\[ess-execute-search], but by \\[ess-resynch], \\[ess-get-object-list], \\[ess-get-modtime-list], \\[ess-execute-objects], \\[ess-object-modtime], \\[ess-create-object-name-db], and (indirectly) by \\[ess-get-help-files-list]." (with-current-buffer (ess-get-process-buffer ess-current-process-name);to get *its* local vars (let ((result nil) (slist (ess-process-get 'search-list)) (tramp-mode nil)) ;; hack for bogus file-directory-p below (if (and slist (not force-update) (not (ess-process-get 'sp-for-help-changed?))) slist ;; else, re-compute: (ess-write-to-dribble-buffer " (ess-search-list ... ) ") (let ((tbuffer (get-buffer-create " *search-list*")) (homedir default-directory) (my-search-cmd inferior-ess-search-list-command); from ess-buffer elt) (ess-command my-search-cmd tbuffer 0.05); <- sleep for dde only; does (erase-buffer) (with-current-buffer tbuffer ;; guaranteed by the initial space in its name: (buffer-disable-undo) (goto-char (point-min)) (ess-write-to-dribble-buffer (format "after '%s', point-max=%d\n" my-search-cmd (point-max))) (while (re-search-forward "\"\\([^\"]*\\)\"" nil t) (setq elt (buffer-substring (match-beginning 1) (match-end 1))) ;;Dbg: (ess-write-to-dribble-buffer (format " .. elt= %s \t" elt)) (if (and (string-match "^[^/]" elt) (file-directory-p (concat homedir elt))) (progn ;;Dbg: (ess-write-to-dribble-buffer "*IS* directory\n") (setq elt (concat homedir elt))) ;;else ;;dbg ;;- (ess-write-to-dribble-buffer "not dir.\n") ) (setq result (append result (list elt)))) (kill-buffer tbuffer))) result)))) ;;; ess-sl-modtime-alist is a list with elements as follows: ;;; * key (directory or object name) ;;; * modtime (list of 2 integers) ;;; * name, name ... (accessible objects in search list posn labeled by key) ;;; It is a buffer-local variable (belonging to e.g. *R*, *S+6*, .. etc) ;;; and has the same number of elements and is in the same order as the ;;; S search list (defun ess-get-modtime-list (&optional cache-var-name exclude-first) "Record directories in the search list, and the objects in those directories. The result is stored in CACHE-VAR-NAME. If nil, CACHE-VAR-NAME defaults to `ess-sl-modtime-alist'. If EXCLUDE-FIRST is non-nil don't recompile first object in the search list." ;; Operation applies to process of current buffer (let* ((searchlist (if exclude-first (cdr (ess-search-list)) (ess-search-list))) (index (if exclude-first 2 1)) (cache-name (or cache-var-name 'ess-sl-modtime-alist)) pack newalist) (while searchlist (setq pack (car searchlist) newalist (append newalist (list (or (assoc pack (symbol-value cache-name)) (append (list pack (ess-dir-modtime pack)) (prog2 (message "Forming completions for %s..." pack) (ess-object-names pack index) (message "Forming completions for %s...done" pack)))))) index (1+ index) searchlist (cdr searchlist))) ;;DBG: (ess-write-to-dribble-buffer (format "(%s): created new alist of length %d\n" cache-var-name (length newalist))) (set cache-name newalist))) (defun ess-search-path-tracker (str) "Check if input STR changed the search path. This function monitors user input to the inferior ESS process so that Emacs can keep the process variable `search-list' up to date. `ess-completing-read' in \\[ess-read-object-name] uses this list indirectly when it prompts for help or for an object to dump. From ESS 12.09 this is not necessary anymore, as the search path is checked on idle time. It is kept for robustness and backward compatibility only." (when ess-change-sp-regexp (if (string-match ess-change-sp-regexp str) (ess-process-put 'sp-for-help-changed? t)))) ;;; Miscellaneous routines ;;;*;;; Routines for reading object names (defun ess-read-object-name (p-string) "Read an object name from the minibuffer with completion, and return it. P-STRING is the prompt string." (let* ((default (ess-read-object-name-dump)) (object-list (ess-get-object-list ess-local-process-name)) (spec (ess-completing-read p-string object-list nil nil nil nil default))) (list (cond ((string= spec "") default) (t spec))))) (defun ess-read-object-name-default () "Return the object name at point, or nil if none." (ignore-errors (save-excursion ;; The following line circumvents an 18.57 bug in following-char (if (eobp) (backward-char 1)) ; Hopefully buffer is not empty! ;; Get onto a symbol (catch 'nosym ; bail out if there's no symbol at all before point (while (let ((sc (char-syntax (following-char)))) (not (or (= sc ?w) (= sc ?_)))) (if (bobp) (throw 'nosym nil) (backward-char 1)))) (let* ((end (progn (forward-sexp 1) (point))) (beg (progn (backward-sexp 1) (point)))) (buffer-substring-no-properties beg end))))) (defun ess-read-object-name-dump () "Return the object name at point, or \"Temporary\" if none." (ignore-errors (save-excursion ;; Get onto a symbol (catch 'nosym ; bail out if there's no symbol at all before point (while (/= (char-syntax (following-char)) ?w) (if (bobp) (throw 'nosym nil) (backward-char 1))) (let* ((end (progn (forward-sexp 1) (point))) (beg (progn (backward-sexp 1) (point))) (object-name (buffer-substring beg end))) (or object-name "Temporary")))))) ;;;; start of ess-smart-operators ;;;; inspired by slime repl shortcuts (defvar ess--handy-history nil) (defun ess-handy-commands () "Request and execute a command from variable `ess-handy-commands'." (interactive) (let* ((commands (or ess--local-handy-commands ess-handy-commands)) (hist (and (assoc (car ess--handy-history) commands) (car ess--handy-history)))) (call-interactively (cdr (assoc (ess-completing-read "Execute" (sort (mapcar #'car commands) #'string-lessp) nil t nil 'ess--handy-history hist) commands))))) (defun ess-smart-comma () "If comma is invoked at the process marker of an ESS inferior buffer, request and execute a command from `ess-handy-commands' list." (interactive) (let ((proc (get-buffer-process (current-buffer)))) (if (and proc (eq (point) (marker-position (process-mark proc)))) (ess-handy-commands) (if ess-smart-operators (progn (delete-horizontal-space) (insert ", ") (unless (derived-mode-p 'inferior-ess-mode) (indent-according-to-mode))) (insert ","))))) ; directories (defun ess-set-working-directory (path &optional no-error) "Set the current working to PATH for the ESS buffer and iESS process. NO-ERROR prevents errors when this has not been implemented for `ess-dialect'." (interactive "DChange working directory to: ") (if ess-setwd-command (let* ((remote (file-remote-p path)) (path (if remote (progn (require 'tramp-sh) (tramp-sh-handle-expand-file-name path)) path)) (lpath (if remote (with-parsed-tramp-file-name path v v-localname) path))) (ess-eval-linewise (format ess-setwd-command lpath)) (ess-set-process-variable 'default-directory (file-name-as-directory path))) (unless no-error (error "Not implemented for dialect %s" ess-dialect)))) (defalias 'ess-change-directory #'ess-set-working-directory) (define-obsolete-function-alias 'ess-use-dir #'ess-set-working-directory "ESS 18.10") (defun ess-use-this-dir (&rest _ignore) "Set the current process directory to the directory of this file. `default-directory' is used as a fallback." (interactive) (let ((dir (if buffer-file-name (file-name-directory buffer-file-name) default-directory))) (ess-set-working-directory (abbreviate-file-name dir)))) (defun ess-get-working-directory (&optional no-error) "Retrieve the current working directory from the current ess process." (if ess-getwd-command (abbreviate-file-name (car (ess-get-words-from-vector ess-getwd-command))) (unless no-error (error "Not implemented for dialect %s" ess-dialect)))) (defun ess-synchronize-dirs () "Set Emacs' current directory to be the same as the subprocess directory. To be used in `ess-idle-timer-functions'." (when (and (ess-can-eval-in-background) ess-getwd-command (inferior-ess-available-p)) (ess-when-new-input last-sync-dirs (ess-if-verbose-write "\n(ess-synchronize-dirs)\n") (let ((lpath (car (ess-get-words-from-vector ess-getwd-command)))) (setq default-directory (file-name-as-directory (ess--derive-connection-path default-directory lpath)))) default-directory))) (defun ess-dirs () "Set Emacs' current directory to be the same as the *R* process." ;; Note: This function is not necessary anymore. The Emacs ;; default-directory and subprocess working directory are ;; synchronized automatically. (interactive) (let* ((dir (car (ess-get-words-from-vector "getwd()\n"))) (new-default-dir (ess--derive-connection-path default-directory dir))) (message "(ESS / default) directory: %s" dir) (setq default-directory (file-name-as-directory new-default-dir)))) (defun ess--derive-connection-path (old new) "Derive a (possibly remote) path with an updated local filename. A new connection path is derived from OLD (a path) and NEW (a path), in such a way that the host and connection information (if any) in OLD is retained in the NEW path. NEW must be an absolute path, and can be a remote path" (concat (file-remote-p old) (or (file-remote-p new 'localname) new))) ;; search path (defun ess--mark-search-list-as-changed () "Internal. Mark all the search-list related variables as changed." ;; other guys might track their own (ess-process-put 'sp-for-help-changed? t) (ess-process-put 'sp-for-ac-changed? t)) (defun ess-cache-search-list () "To be used in `ess-idle-timer-functions', to set search path related variables." (when (and (ess-can-eval-in-background) inferior-ess-search-list-command) (ess-when-new-input last-cache-search-list (let ((path (ess-search-list 'force)) (old-path (process-get *proc* 'search-list))) (when (not (equal path old-path)) (process-put *proc* 'search-list path) (ess--mark-search-list-as-changed) path))))) ;;*;; Temporary buffer handling (defun ess-display-temp-buffer (buff) "Display the buffer BUFF. Uses `temp-buffer-show-function' and respects `ess-display-buffer-reuse-frames'." (if (fboundp temp-buffer-show-function) (funcall temp-buffer-show-function buff)) (display-buffer buff '(display-buffer-reuse-window) ess-display-buffer-reuse-frames)) (defun ess--inject-code-from-file (file &optional chunked) "Load code from FILE into process. If CHUNKED is non-nil, split the file by separator (must be at bol) and load each chunk separately." ;; This is different from ess-load-file as it works by directly loading the ;; string into the process and thus works on remotes. (let ((proc-name ess-local-process-name) (dialect ess-dialect) (send-1 (lambda (str) (if (string= ess-dialect "R") ;; avoid detection of intermediate prompts (ess-command (concat "{" str "}\n")) (ess-command str))))) (with-temp-buffer (setq ess-local-process-name proc-name ess-dialect dialect) (insert-file-contents-literally file) (if chunked (let ((beg (point-min))) (goto-char beg) (while (re-search-forward "^ " nil t) (funcall send-1 (buffer-substring beg (point))) (setq beg (point))) (funcall send-1 (buffer-substring (point) (point-max)))) (funcall send-1 (buffer-string)))))) (defun ess-check-modifications nil "Check whether loading this file would overwrite some ESS objects which have been modified more recently than this file, and confirm if this is the case." (declare (obsolete "Do not use" "21.04")) (when (> (length ess-change-sp-regexp) 0) (and (buffer-file-name) ess-filenames-map (let ((sourcemod (nth 5 (file-attributes (buffer-file-name)))) (objname)) (save-excursion (goto-char (point-min)) ;; Get name of assigned object, if we can find it (setq objname (and (re-search-forward "^\\s *\"?\\(\\(\\sw\\|\\s_\\)+\\)\"?\\s *[<_]" nil t) (buffer-substring (match-beginning 1) (match-end 1))))) (and sourcemod ; the file may have been deleted objname ; may not have been able to ; find name (ess-modtime-gt (ess-object-modtime objname) sourcemod) (not (y-or-n-p (format "The ESS object %s is newer than this file. Continue? " objname))) (error "Aborted")))))) (define-obsolete-function-alias 'ess-check-source #'ess-save-file "ESS 19.04") (defun ess-save-file (file) "If FILE (a string) has an unsaved buffer, offer to save it. Return t if the buffer existed and was modified, but was not saved. If `ess-save-silently' is non-nil, the buffer is saved without offering." (when-let ((buff (find-buffer-visiting file))) (when (and (buffer-modified-p buff) (or (eql ess-save-silently t) (and (eql ess-save-silently 'auto) (or (not compilation-ask-about-save) (bound-and-true-p ;; Only added in Emacs 26.1 auto-save-visited-mode))) (y-or-n-p (format "Buffer %s is modified. Save? " (buffer-name buff))))) (with-current-buffer buff (save-buffer))) (buffer-modified-p buff))) ;;*;; Error messages (defun ess-parse-errors (&optional showerr _reset) "Jump to error in last loaded ESS source file. With prefix argument SHOWERR, only show the errors ESS reported. RESET is for compatibility with `next-error' and is ignored." (interactive "P") (ess-make-buffer-current) (let ((errbuff (get-buffer ess-error-buffer-name))) (when (not errbuff) (error "You need to do a load first!")) (set-buffer errbuff) (goto-char (point-max)) ;; FIXME: R does not give "useful" error messages by default. We ;; could try to use a more useful one, via ;; options(error=essErrorHandler) (cond ((re-search-backward ess-error-regexp nil t) (let* ((filename (buffer-substring (match-beginning 3) (match-end 3))) (fbuffer (get-file-buffer filename)) (linenum (string-to-number (buffer-substring (match-beginning 2) (match-end 2)))) (errmess (buffer-substring (match-beginning 1) (match-end 1)))) (if showerr (ess-display-temp-buffer errbuff) (if fbuffer nil (setq fbuffer (find-file-noselect filename)) (with-current-buffer fbuffer ;; TODO: ess-mode is surely wrong here, but I don't ;; think we need this whole function anymore? (when (fboundp 'ess-mode) (ess-mode)))) (pop-to-buffer fbuffer) (ess-goto-line linenum)) (princ errmess t))) (t (message "Not a syntax error.") (ess-display-temp-buffer errbuff))))) (defun ess-error (msg) "Something bad has happened. Display the S buffer, and cause an error displaying MSG." (declare (obsolete error "ESS 18.10")) (display-buffer (process-buffer (get-process ess-local-process-name))) (error msg)) (provide 'ess-inf) ;;; ess-inf.el ends here ESS-24.01.1/lisp/ess-jags-d.el000066400000000000000000000331651455642170100155540ustar00rootroot00000000000000;;; ess-jags-d.el --- ESS[JAGS] dialect -*- lexical-binding: t; -*- ;; Copyright (C) 2009-2022 Free Software Foundation, Inc. ;; Author: Rodney Sparapani ;; Created: 13 March 2008 ;; Maintainer: ESS Core Team ;; This file is part of GNU Emacs. ;;; License: ;; ;; 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 ;; ;;; Code: (require 'ess-bugs-d) (require 'ess-utils) (require 'ess-inf) (require 'ess-mode) (defvar ess-jags-command "jags" "Default JAGS program in PATH.") (make-local-variable 'ess-jags-command) (defvar ess-jags-monitor '("") "Default list of variables to monitor.") (make-local-variable 'ess-jags-monitor) (defvar ess-jags-thin 1 "Default thinning parameter.") (make-local-variable 'ess-jags-thin) (defvar ess-jags-chains 1 "Default number of chains.") (make-local-variable 'ess-jags-chains) (defvar ess-jags-burnin 10000 "Default burn-in.") (make-local-variable 'ess-jags-burnin) (defvar ess-jags-update 10000 "Default number of updates after burnin.") (make-local-variable 'ess-jags-update) (defvar ess-jags-system t "Default whether JAGS recognizes the system command.") (defvar ess-jags-font-lock-keywords (list ;; .jag files (cons "#.*\n" font-lock-comment-face) (cons "^[ \t]*\\(model\\|var\\)\\>" font-lock-keyword-face) (cons (concat "\\& " ess-bugs-file-root ".jog ") ;else "> " ess-bugs-file-root ".jog 2>&1 ") ; ;.txt not recognized by BOA and impractical to over-ride ; "&& (rm -f " ess-bugs-file-root ".ind; " ; "ln -s " ess-bugs-file-root "index.txt " ess-bugs-file-root ".ind; " ; "for i in " ess-jags-temp-chains "; do; " ; "rm -f " ess-bugs-file-root "$i.out; " ; "ln -s " ess-bugs-file-root "chain$i.txt " ess-bugs-file-root "$i.out; done) " ess-bugs-batch-post-command) (comint-send-input) )) (defun ess-jags-na-bug () "ESS[JAGS]: Perform Next-Action for .jag" (if (equal 0 (buffer-size)) (ess-jags-switch-to-suffix ".jag") ;else (ess-save-and-set-local-variables) (ess-jags-switch-to-suffix ".jmd" ess-jags-chains ess-jags-monitor ess-jags-thin ess-jags-burnin ess-jags-update)) ) ;;;###autoload (define-derived-mode ess-jags-mode ess-bugs-mode "ESS[JAGS]" "Major mode for JAGS." (setq-local comment-start "#") (setq font-lock-defaults '(ess-jags-font-lock-keywords nil t)) (setq ess-language "S") ; mimic S for ess-smart-underscore (unless (and (fboundp 'w32-shell-dos-semantics) (w32-shell-dos-semantics)) (add-hook 'comint-output-filter-functions #'ess-bugs-exit-notify-sh)) ) ;;;###autoload (add-to-list 'auto-mode-alist '("\\.[Jj][Aa][Gg]\\'" . ess-jags-mode)) (provide 'ess-jags-d) ;;; ess-jags-d.el ends here ESS-24.01.1/lisp/ess-julia.el000066400000000000000000000464641455642170100155210ustar00rootroot00000000000000;; ess-julia.el --- ESS julia mode and inferior interaction -*- lexical-binding: t; -*- ;; Copyright (C) 2012-2022 Free Software Foundation, Inc. ;; Author: Vitalie Spinu ;; Maintainer: Vitalie Spinu ;; Created: 02-04-2012 (ESS 12.03) ;; Keywords: ESS, julia ;; This file is part of GNU Emacs. ;;; License: ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see ;; ;;; Commentary: ;; Customize inferior-julia-program to point to your julia binary ;; and start the inferior with M-x julia. ;; As of Sept 2015, this file depends heavily on julia-mode.el from the Julia ;; sources. If you install ESS using `make', this will work fine, otherwise ;; ensure that julia-mode.el is on your path before loading this file. ;;; Code: (require 'ess-help) (require 'ess-inf) (require 'ess-r-mode) (require 'ess-utils) ;; Don't require `julia-mode' to compile this file. (when t (require 'julia-mode)) (declare-function julia-mode "julia-mode" ()) (declare-function julia-latexsub "julia-mode" ()) (defvar julia-mode-syntax-table) (defvar ac-prefix) (declare-function company-in-string-or-comment "company") (declare-function company-doc-buffer "company") (defcustom inferior-julia-args "" "String of arguments (see `julia --help') used when starting julia." :group 'ess-julia :type 'string) (eval-when-compile (require 'cl-lib)) (defun ess-julia-send-string-function (process string _visibly) "Send the Julia STRING to the PROCESS. VISIBLY is not currently used." (let ((file (concat temporary-file-directory "julia_eval_region.jl"))) (with-temp-file file (insert string)) (process-send-string process (format ess-load-command file)))) ;;; HELP (cl-defmethod ess-help-get-topics (proc &context (ess-dialect "julia")) (append (with-current-buffer (ess--foreground-command "ESS.all_help_topics()\n") (split-string (buffer-string) "\n")) (ess-julia--get-objects proc))) (defun ess-julia--retrieve-topics (url) (with-current-buffer (url-retrieve-synchronously url) (require 'url) (goto-char (point-min)) (let (out) (while (re-search-forward "toctext[ \"]+href=\"\\([^>]+\\)\">\\([^<]+\\) ") (inferior-ess-secondary-prompt . nil) (inferior-ess-prompt . "\\w*> ") (ess-local-customize-alist . 'ess-julia-customize-alist) (inferior-ess-program . inferior-julia-program) (ess-load-command . "include(expanduser(\"%s\"))\n") (ess-funargs-command . "ESS.fun_args(\"%s\")\n") (ess-dump-error-re . "in \\w* at \\(.*\\):[0-9]+") (ess-error-regexp . "\\(^\\s-*at\\s-*\\(?3:.*\\):\\(?2:[0-9]+\\)\\)") (ess-error-regexp-alist . ess-julia-error-regexp-alist) (ess-mode-completion-syntax-table . ess-julia-completion-syntax-table) ;; (inferior-ess-objects-command . inferior-ess-r-objects-command) ;; (inferior-ess-search-list-command . "search()\n") (inferior-ess-help-command . "ESS.help(\"%s\")\n") ;; (inferior-ess-help-command . "help(\"%s\")\n") (ess-language . "julia") (ess-dialect . "julia") (ess-suffix . "jl") (ess-dump-filename-template . (replace-regexp-in-string "S$" ess-suffix ; in the one from custom: ess-dump-filename-template-proto)) (ess-mode-editing-alist . nil) (ess-change-sp-regexp . nil );ess-r-change-sp-regexp) (ess-help-sec-regex . ess-help-r-sec-regex) (ess-help-sec-keys-alist . ess-help-r-sec-keys-alist) (ess-function-pattern . ess-r-function-pattern) (ess-object-name-db-file . "ess-jl-namedb.el" ) (ess-smart-operators . ess-r-smart-operators) (inferior-ess-exit-command . "exit()\n") ;;harmful for shell-mode's C-a: -- but "necessary" for ESS-help? (inferior-ess-language-start . nil) (ess-STERM . "iESS") (ess-editor . ess-r-editor) (ess-pager . ess-r-pager) (ess-getwd-command . "pwd()\n") (ess-setwd-command . "cd(expanduser(\"%s\"))\n")) "Variables to customize for Julia.") (cl-defmethod ess--help-web-search-override (cmd &context (ess-dialect "julia")) "Offer to search the web for a Julia command." (browse-url (format "https://docs.julialang.org/en/latest/search/?q=%s" cmd))) (defvar ess-julia-completion-syntax-table (let ((table (copy-syntax-table ess-r-mode-syntax-table))) (modify-syntax-entry ?. "_" table) ;; (modify-syntax-entry ?: "_" table) ;; (modify-syntax-entry ?$ "_" table) (modify-syntax-entry ?@ "_" table) table) "Syntax table used for completion and help symbol lookup. It makes underscores and dots word constituent chars.") (cl-defmethod ess-help-commands (&context (ess-dialect "julia")) '((packages . "_ess_list_categories()\n") (package-index . "_ess_print_index(\"%s\")\n") (index-keyword-reg . "^\\(.*+\\):$*") (index-start-reg . ":"))) (defvar ess-julia-mode-syntax-table (copy-syntax-table julia-mode-syntax-table)) (defvar ess-julia-mode-map (let ((map (make-sparse-keymap))) (set-keymap-parent map ess-mode-map) map) "Keymap for `ess-julia-mode'.") ;;;###autoload (define-derived-mode ess-julia-mode julia-mode "ESS[julia]" "Major mode for julia files." :group 'ess-Julia (setq-local ess-local-customize-alist ess-julia-customize-alist) (setq ess-dialect "julia") (ess-setq-vars-local ess-julia-customize-alist) ;; eldoc (ess--setup-eldoc #'ess-julia-eldoc-function) ;; auto-complete (ess--setup-auto-complete '(ac-source-ess-julia-objects)) ;; company (ess--setup-company '(company-ess-julia-objects)) ;; for emacs >= 24 (remove-hook 'completion-at-point-functions #'ess-filename-completion 'local) ;; should be first (add-hook 'completion-at-point-functions #'ess-julia-object-completion nil 'local) (add-hook 'completion-at-point-functions #'ess-filename-completion nil 'local) (add-hook 'completion-at-point-functions #'ess-julia-latexsub-completion nil 'local) (if (fboundp 'ess-add-toolbar) (ess-add-toolbar))) ;; Inferior mode (defvar inferior-ess-julia-mode-syntax-table (copy-syntax-table ess-julia-mode-syntax-table) "Syntax table for `inferior-ess-julia-mode'.") (define-derived-mode inferior-ess-julia-mode inferior-ess-mode "iESS[julia]" "Major mode for inferior julia processes." :group 'ess-Julia (ess-setq-vars-local ess-julia-customize-alist) (setq-local comint-use-prompt-regexp t) (setq comint-prompt-regexp (concat "^" inferior-ess-prompt)) (setq ess-dialect "julia") ;; eldoc (ess--setup-eldoc #'ess-julia-eldoc-function) ;; auto-complete (ess--setup-auto-complete '(ac-source-ess-julia-objects) t) ;; company (ess--setup-company '(company-ess-julia-objects) t) (remove-hook 'completion-at-point-functions #'ess-filename-completion 'local) ;; should be first (add-hook 'completion-at-point-functions #'ess-julia-object-completion nil 'local) (add-hook 'completion-at-point-functions #'ess-filename-completion nil 'local) (add-hook 'completion-at-point-functions #'ess-julia-latexsub-completion nil 'local) (setq comint-input-sender #'ess-julia-input-sender)) (defvar ess-julia-mode-hook nil) (defvar ess-julia-post-run-hook nil "Functions run in process buffer after starting julia process.") ;;;###autoload (defun run-ess-julia (&optional start-args) "Start an inferior julia process. Optional prefix START-ARGS (\\[universal-argument]) allows to set command line arguments, such as --load=. This should be OS agnostic. If you have certain command line arguments that should always be passed to julia, put them in the variable `inferior-julia-args'." (interactive "P") ;; get settings, notably inferior-julia-program : (if (null inferior-julia-program) (error "'inferior-julia-program' does not point to 'julia' or 'julia-basic' executable") (ess-write-to-dribble-buffer ;; for debugging only (format "\n(julia): ess-dialect=%s, buf=%s, start-arg=%s\n current-prefix-arg=%s\n" ess-dialect (current-buffer) start-args current-prefix-arg)) (let* ((jl-start-args (concat inferior-julia-args " " ; add space just in case (if start-args (read-string (concat "Starting Args" (if inferior-julia-args (concat " [other than '" inferior-julia-args "']")) " ? ")) nil)))) (let ((inf-buf (inferior-ess jl-start-args ess-julia-customize-alist))) (with-current-buffer inf-buf (ess--tb-start) ;; Remove ` from julia's logo (goto-char (point-min)) (while (re-search-forward "`" nil t) (replace-match "'")) ;; Remove an offending unmatched parenthesis (goto-char (point-min)) (forward-line 4) (when (re-search-forward "(" nil t) (replace-match "|")) (goto-char (point-max)) ;; --> julia helpers from ../etc/ess-julia.jl : (ess--inject-code-from-file (format "%sess-julia.jl" ess-etc-directory)) (run-mode-hooks 'ess-julia-post-run-hook)) inf-buf)))) ;;;###autoload (defalias 'julia #'run-ess-julia) (cl-defmethod ess--help-major-mode (&context (ess-dialect "julia")) (ess-julia-help-mode)) (define-derived-mode ess-julia-help-mode ess-help-mode "ESS[Julia] Help" "Major mode for Julia documentation." :group 'ess-help (let ((inhibit-read-only t)) ;; Julia help buffers can contain color if julia starts with ;; --color=yes (ansi-color-apply-on-region (point-min) (point-max)))) (add-to-list 'auto-mode-alist '("\\.jl\\'" . ess-julia-mode)) (provide 'ess-julia) ;;; ess-julia.el ends here ESS-24.01.1/lisp/ess-mode.el000066400000000000000000000711131455642170100153260ustar00rootroot00000000000000;;; ess-mode.el -- Emacs Speaks Statistics root mode. -*- lexical-binding: t; -*- ;; Copyright (C) 1994-2022 Free Software Foundation, Inc. ;; Maintainer: ESS-core ;; This file is part of GNU Emacs. ;;; License: ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see ;; ;;; Commentary: ;; This file defines ess-mode from which other modes (like ess-r-mode) ;; derive. ;;; Code: (require 'ess) (eval-when-compile (require 'cl-lib) (require 'subr-x)) (require 'ess-inf) ;; Silence the byte compiler (declare-function R "ess-r-mode" (&optional start-args)) (declare-function S+ "ess-sp6-d" (&optional proc-name)) (declare-function SAS "ess-sas-d" ()) ;; FIXME:This one should not be necessary (declare-function ess-display-help-on-object "ess-help" (object &optional command)) ;; ESS mode ;; Major mode definition ;;*;; Hooks (defcustom ess-mode-hook nil "Hook for customizing ESS each time it is entered." :group 'ess-hooks :type 'hook) (defvar ess-mode-map (let ((map (make-sparse-keymap))) (define-key map [remap yank] #'ess-yank) (define-key map "\C-c\C-r" #'ess-eval-region) (define-key map "\C-c\M-r" #'ess-eval-region-and-go) (define-key map "\C-c\C-b" #'ess-eval-buffer) (define-key map "\C-c\M-b" #'ess-eval-buffer-and-go) (define-key map (kbd "C-c C-") #'ess-eval-buffer-from-beg-to-here) (define-key map (kbd "C-c C-") #'ess-eval-buffer-from-here-to-end) (define-key map "\C-c\C-f" #'ess-eval-function) (define-key map "\C-c\M-f" #'ess-eval-function-and-go) (define-key map "\C-c\C-c" #'ess-eval-region-or-function-or-paragraph-and-step) (define-key map "\C-c\C-p" #'ess-eval-paragraph-and-step) (define-key map "\C-c\M-p" #'ess-eval-paragraph-and-go) (define-key map "\C-\M-x" #'ess-eval-region-or-function-or-paragraph) (define-key map "\C-c\C-n" #'ess-eval-line-visibly-and-step) (define-key map "\C-c\C-j" #'ess-eval-line) (define-key map [(control return)] #'ess-eval-region-or-line-visibly-and-step) (define-key map "\C-c\M-j" #'ess-eval-line-and-go) ;; FIXME: The next three can only work in S/R - mode (define-key map "\C-\M-a" #'ess-goto-beginning-of-function-or-para) (define-key map "\C-\M-e" #'ess-goto-end-of-function-or-para) (define-key map "\C-xnd" #'ess-narrow-to-defun-or-para) (define-key map "\C-xnf" #'ess-narrow-to-defun-or-para) (define-key map "\C-c\C-z" #'ess-switch-to-inferior-or-script-buffer) (define-key map "\C-c\C-l" #'ess-load-file) ;;; Make an alias because C-c C-l is taken up by comint in inferiors (define-key map "\C-c\M-l" #'ess-load-file) (define-key map "\C-c\C-v" #'ess-display-help-on-object) (define-key map "\C-c\C-s" #'ess-switch-process) (define-key map "\C-c\C-k" #'ess-force-buffer-current) (define-key map "\C-c`" #'ess-show-traceback) (define-key map [(control ?c) ?~] #'ess-show-call-stack) (define-key map "\C-\M-q" #'ess-indent-exp) (define-key map "{" #'skeleton-pair-insert-maybe) (define-key map "}" #'skeleton-pair-insert-maybe) (define-key map "\C-\M-h" #'ess-mark-function-or-para) (define-key map "\t" #'ess-indent-or-complete) (define-key map "\C-c\C-q" #'ess-quit) (define-key map "\M-\r" #'ess-use-this-dir) (define-key map "," #'ess-smart-comma) (define-key map "\C-c\C-d" 'ess-doc-map) (define-key map "\C-c\C-e" 'ess-extra-map) (define-key map "\C-c\C-t" 'ess-dev-map) map) "Keymap for `ess-mode'.") ;; Redefine `indent-new-comment-line' commands for Emacs < 26. Emacs ;; 27 binds M-j to `default-indent-new-line' which calls ;; `comment-line-break-function' if point is in a comment. We set this ;; function in the mode init. (substitute-key-definition #'indent-new-comment-line #'ess-indent-new-comment-line ess-mode-map global-map) (defvar ess-extra-map (let (ess-extra-map) (define-prefix-command 'ess-extra-map) (define-key ess-extra-map "\C-d" #'ess-dump-object-into-edit-buffer) (define-key ess-extra-map "d" #'ess-dump-object-into-edit-buffer) (define-key ess-extra-map "\C-e" #'ess-execute) (define-key ess-extra-map "e" #'ess-execute) (define-key ess-extra-map "\C-i" #'ess-install-library) (define-key ess-extra-map "i" #'ess-install-library) (define-key ess-extra-map "\C-l" #'ess-load-library) (define-key ess-extra-map "l" #'ess-load-library) (define-key ess-extra-map "\C-r" #'inferior-ess-reload) (define-key ess-extra-map "r" #'inferior-ess-reload) (define-key ess-extra-map "\C-s" #'ess-set-style) (define-key ess-extra-map "s" #'ess-set-style) (define-key ess-extra-map "\C-t" #'ess-build-tags-for-directory) (define-key ess-extra-map "t" #'ess-build-tags-for-directory) (define-key ess-extra-map "\C-w" #'ess-execute-screen-options) (define-key ess-extra-map "w" #'ess-execute-screen-options) (define-key ess-extra-map "/" #'ess-set-working-directory) ess-extra-map) "ESS extra map.") (easy-menu-define ess-mode-menu ess-mode-map "Menu for use in `ess-mode'." '("ESS" ; ESS-mode ["Load file" ess-load-file t] ["Eval region | func | para" ess-eval-region-or-function-or-paragraph t] ["Eval region | func | para & step" ess-eval-region-or-function-or-paragraph-and-step t] ["Eval region | line" ess-eval-region-or-line-visibly-and-step t] ["Enter expression" ess-execute t] ;; sub menus "------" ("Process" ["Goto end of process buffer" ess-switch-to-end-of-ESS t] ["Switch to process buffer" ess-switch-to-inferior-or-script-buffer t] ["Switch process" ess-switch-process t] ;; ["Recreate R and S versions known to ESS" (ess-r-s-versions-creation+menu) t] ("Start Process" ["R" R :help "Start a new R process" :active t] ["S" S :help "Start a new S process" :active t] ["Sqpe" Sqpe ess-microsoft-p] ;; :help "Start a new Sqpe process" :active t ["S+6-existing" S+6-existing ess-microsoft-p] ;; :help "Access an existing S process" :active t ["SAS" SAS-menu t] ;; :help "Start a new SAS process" :active t ;; The following menu item "Other" is a place-holder that will ;; be replaced with the other versions of R and Sqpe that can be run. ;; See `ess-r-define-runners' and ess-site.el ("Other" ["No other R or Sqpe versions" nil nil]) ["About" (ess-goto-info "Starting up") t] ;; :help "Read about starting a new ESS process" :active t] ) ("Eval visibly " :filter ess--generate-eval-visibly-submenu) ["Quit process" ess-quit t] ["Reload process" inferior-ess-reload t]) "------" ("ESS Eval" ["Eval region | func | para" ess-eval-region-or-function-or-paragraph t] ["Eval region | func | para & step" ess-eval-region-or-function-or-paragraph-and-step t] ["Eval region | line & step" ess-eval-region-or-line-visibly-and-step t] "-----" ["Eval buffer" ess-eval-buffer t] ["Eval buffer till here" ess-eval-buffer-from-beg-to-here t] ["Eval buffer from here" ess-eval-buffer-from-here-to-end t] ["Eval region" ess-eval-region t] ["Eval function" ess-eval-function t] ["Eval line" ess-eval-line t] ["Eval line & step" ess-eval-line-and-step t] ["Eval paragraph" ess-eval-paragraph t] ["Eval paragraph & step" ess-eval-paragraph-and-step t] ["About" (ess-goto-info "Evaluating code") t] ) ("Eval and Go" ["Eval buffer" ess-eval-buffer-and-go t] ["Eval region" ess-eval-region-and-go t] ["Eval function" ess-eval-function-and-go t] ["Eval line" ess-eval-line-and-go t] ["Eval paragraph" ess-eval-paragraph-and-go t] ["About" (ess-goto-info "Evaluating code") t] ) ("Motion" ["Beginning of function or para" ess-goto-beginning-of-function-or-para t] ["End of function or para" ess-goto-end-of-function-or-para t] "-----" ["Backward list" backward-list t] ["Forward list" forward-list t] ["Next parenthesis" down-list t] ["Enclosing parenthesis" backward-up-list t] ["Backward sexp" backward-sexp t] ["Forward sexp" forward-sexp t] ["About" (Info-goto-node "(Emacs)Lists") t] ) ("ESS Edit" ["Edit new object" ess-dump-object-into-edit-buffer t] ["Complete Filename" comint-replace-by-expanded-filename t] ["Complete File or Object" ess-indent-or-complete t] ["Kill sexp" kill-sexp t] ["Mark function" ess-mark-function-or-para t] ["Indent expression" ess-indent-exp t] ["Indent line" ess-indent-command t] ["Toggle Auto-Fill Mode" auto-fill-mode t] ["Undo" undo t] ["About" (ess-goto-info "Edit buffer") t] ) "------" ("start-dev" :visible nil) ("end-dev" :visible nil) "------" ("Font Lock" :active ess-font-lock-keywords :filter ess--generate-font-lock-submenu) "------" ["Describe" describe-mode t] ["About editing" (ess-goto-info "Editing") t] ["Read ESS info" (ess-goto-info "") t] ["Send bug report" ess-submit-bug-report t])) ;;;###autoload (define-derived-mode ess-mode prog-mode "ESS" "Major mode for editing ESS source. Optional arg ALIST describes how to customize the editing mode. Optional arg PROC-NAME is name of associated inferior process. \\{ess-mode-map} You can send text to the inferior ESS process from other buffers containing ESS source. `ess-eval-region' sends the current region to the ESS process. `ess-eval-buffer' sends the current buffer to the ESS process. `ess-eval-function' sends the current function to the ESS process. `ess-eval-line' sends the current line to the ESS process. `ess-switch-to-ESS' switches the current buffer to the ESS process buffer. `ess-switch-to-end-of-ESS' switches the current buffer to the ESS process buffer and puts point at the end of it. `ess-eval-region-and-go', `ess-eval-buffer-and-go', `ess-eval-function-and-go', and `ess-eval-line-and-go' switch to the S process buffer after sending their text. `ess-load-file' sources a file of commands to the ESS process. \\[ess-indent-command] indents for ESS code. \\[backward-delete-char-untabify] converts tabs to spaces as it moves back. Comments are indented in a similar way to Emacs-lisp mode: `###' beginning of line `##' the same level of indentation as the code `#' the same column on the right, or to the right of such a column if that is not possible.(default value 40). \\[indent-for-comment] command automatically inserts such a `#' in the right place, or aligns such a comment if it is already inserted. \\[ess-indent-exp] command indents each line of the syntactic unit following point. Variables controlling indentation style: `ess-indent-offset' Indentation of ESS statements within surrounding block. The surrounding block's indentation is the indentation of the line on which the open-brace appears. `ess-offset-block' Indentation of blocks opened with curly braces or anonymous parentheses. `ess-offset-arguments' Indentation of function arguments or bracket indices. `ess-offset-arguments-newline' Indentation of function arguments or bracket indices when the opening delimiter is immediately followed by a newline. `ess-offset-continued' Indentation style for continued statements. `ess-align-nested-calls' Functions whose nested calls should be aligned. `ess-align-arguments-in-calls' Calls in which arguments should be aligned. `ess-align-continuations-in-calls' Whether ignore indentation after an operator in calls `ess-align-blocks' Blocks that should always be aligned vertically. `ess-indent-from-lhs' Whether function calls given as argument should be indented from the parameter name. `ess-indent-from-chain-start' Whether to indent arguments from the first of several consecutive calls. `ess-indent-with-fancy-comments' Non-nil means distinguish between #, ##, and ### for indentation. Furthermore, \\[ess-set-style] command enables you to set up predefined ess-mode indentation style. See `ess-style-alist' for predefined styles." :group 'ess ;; TODO: get rid of these and rely on modes to set variables properly (when-let ((alist (buffer-local-value 'ess-local-customize-alist (current-buffer)))) (ess-setq-vars-local alist)) (when-let ((alist ess-mode-editing-alist)) (ess-setq-vars-local alist)) ;; Keep out of the code. (setq-local indent-tabs-mode nil) (setq-local comment-line-break-function #'ess-newline-and-indent) (setq mode-line-process '(" [" (:eval (ess--get-mode-line-indicator)) ess--local-mode-line-process-indicator "]")) (add-hook 'ess-idle-timer-functions #'ess-synchronize-dirs nil 'local)) (defun ess--get-mode-line-indicator () "Get `ess--mode-line-process-indicator' from process buffer. Internal function to be used for dynamic mode-line display in `ess-mode'." (if ess-local-process-name (let* ((proc (get-process ess-local-process-name)) (buff (when proc (process-buffer proc)))) (if (and proc (buffer-live-p buff)) (with-current-buffer buff (mapcar (lambda (e) (eval e t)) ess--mode-line-process-indicator)) "none")) "none")) ;;; User commands in ess-mode (defun ess-install-library (&optional update package) "Install PACKAGE for current dialect. With UPDATE, update cached package list." (interactive "P") (ess-install-library--override update package)) (cl-defgeneric ess-install-library--override (update package) "See `ess-install-library' for UPDATE, PACKAGE." (when update (message "Don't know how to update for %s" ess-dialect)) (error "Cannot install %s, not available for %s" package ess-dialect)) ;; Motion / manipulation commands (defun ess-goto-beginning-of-function-or-para () "If inside a function go to the beginning of it. Otherwise go to the beginning of paragraph." (interactive) (let ((start-pos (point)) beg end) (beginning-of-defun) (setq beg (point)) (end-of-defun) (setq end (point)) (goto-char beg) (unless (and (< beg start-pos) (> end start-pos)) (let ((par-pos (save-excursion (goto-char start-pos) (forward-comment most-negative-fixnum) (backward-paragraph) (forward-comment most-positive-fixnum) (point)))) (if (< end par-pos) (goto-char par-pos) (goto-char beg)))))) (defun ess-goto-end-of-function-or-para () "If inside a function go to end of it. Otherwise go to the end of paragraph." (interactive) (let ((pos (point)) beg end) (end-of-defun) (setq end (point)) (beginning-of-defun) (setq beg (point)) (goto-char end) (when (or (< beg pos) (> end pos)) (let ((par-pos (save-excursion (goto-char pos) (forward-comment most-positive-fixnum) (forward-paragraph) (point)))) (when (<= par-pos beg) (goto-char par-pos)))))) (defun ess-mark-function-or-para () "Put mark at end of ESS function, point at beginning." (interactive) (ess-goto-beginning-of-function-or-para) (push-mark (point)) (ess-goto-end-of-function-or-para) (exchange-point-and-mark)) (define-obsolete-function-alias 'ess-mark-function #'ess-mark-function-or-para "15.09") (defun ess-narrow-to-defun-or-para () "Make text outside current function invisible. If text is already narrowed, this is removed before narrowing to the current function." (interactive) (save-excursion (widen) (let* ((beg (progn (ess-goto-beginning-of-function-or-para) (point))) (end (progn (ess-goto-end-of-function-or-para) (point)))) (narrow-to-region beg end)))) (define-obsolete-function-alias 'ess-narrow-to-defun #'ess-narrow-to-defun-or-para "15.09") ;; FIXME: Support soft breaks with `insert-and-inherit'. See ;; https://www.gnu.org/software/emacs/manual/html_node/emacs/Hard-and-Soft-Newlines.html (defun ess-newline-and-indent (&optional _soft) (ess-indent-new-comment-line)) (defun ess-indent-new-comment-line () "Like `indent-new-comment-line' but accounts for roxygen comments." (interactive) (cond ((and (fboundp 'ess-roxy-indent-new-comment-line) (string= ess-dialect "R")) (ess-roxy-indent-new-comment-line)) (t (indent-new-comment-line)))) ;;; Formatting / indentation (defvar-local ess--installed-style-vars nil "A cons of the form (STYLE . VARS). VARS is a list of all style vars which were not set explicitly to buffer local values by the user in mode hooks.") (defun ess-set-style (&optional style _quiet) "Set up the `ess-mode' style variables from the `ess-style' variable. If STYLE argument is given, use that instead. It makes the ESS indentation style variables buffer local. QUIET is for backward compatibility and is ignored. In programs, when STYLE is nil, the `ess-style' is installed. In this case, if `ess-style' is buffer local, all settings are overwritten, otherwise only those settings which are not already buffer local. For example, `ess-style' is buffer local when it is set in .dir-locals and thus must have priority over the user settings in the mode hook." (interactive (list (let ((styles (mapcar (lambda (x) (symbol-name (car x))) ess-style-alist))) (intern (ess-completing-read "Set ESS mode indentation style" styles nil t nil nil ess-style))))) (let* ((keep-local (and (null style) (not (local-variable-p 'ess-style)))) (style (or style ess-style)) (style-alist (or (cdr (assq style ess-style-alist)) (error "Bad ESS style: %s" style))) (vars (if keep-local ;; Install, but Keep user's buffer-local settings. (cl-loop for (var . _) in (cdr (assq 'DEFAULT ess-style-alist)) unless (local-variable-p var) collect var) (mapcar #'car style-alist)))) (when (called-interactively-p 'any) (message "Set indentation style to %s" style)) (mapc (lambda (var) (make-local-variable var) (set var (cdr (assq var style-alist)))) vars) style)) (defun ess-indent-command (&optional whole-exp) "Indent current line as ESS code, or in some cases insert a tab character. If `tab-always-indent' is non-nil, always indent current line. Otherwise, indent the current line only if point is at the left margin or in the line's indentation; otherwise insert a tab. If given, WHOLE-EXP means indent rigidly all the lines of the expression starting after point so that this line becomes properly indented. The relative indentation among the lines of the expression are preserved. If in a roxygen block at the beginning of the line with `ess-roxy-hide-show-p' non-nil, call `ess-roxy-toggle-hiding' instead of indenting." (interactive "P") (cond ((and (fboundp 'ess-roxy-entry-p) (fboundp 'ess-roxy-toggle-hiding) (bolp) (ess-roxy-entry-p) ess-roxy-hide-show-p) (ess-roxy-toggle-hiding)) (whole-exp ;; If arg, always indent this line as S ;; and shift remaining lines of expression the same amount. (let ((shift-amt (funcall indent-line-function)) beg end) (save-excursion (if tab-always-indent (beginning-of-line)) (setq beg (point)) (backward-up-list 1) (forward-list 1) (setq end (point)) (goto-char beg) (forward-line 1) (setq beg (point))) (if (> end beg) (indent-code-rigidly beg end shift-amt)))) ((and (not tab-always-indent) (save-excursion (skip-chars-backward " \t") (not (bolp)))) (insert-tab)) (t (funcall indent-line-function)))) (defun ess-indent-or-complete () "When region is selected indent the region. Otherwise, if `tab-always-indent' is \\='complete, try to indent, if code is already indented, complete instead. Also see `ess-first-tab-never-complete'." (interactive) (if (use-region-p) (indent-region (region-beginning) (region-end)) (let ((shift (let ((indent (current-indentation))) (ess-indent-command) (- (current-indentation) indent)))) (when (and (or (equal tab-always-indent 'complete) ess-tab-complete-in-script) (numberp shift) ;; can be nil if tab-always-indent is nil (equal shift 0) (or (eq last-command 'ess-indent-or-complete) (null ess-first-tab-never-complete) (and (eq ess-first-tab-never-complete 'unless-eol) (looking-at "\\s-*$")) (and (eq ess-first-tab-never-complete 'symbol) (not (looking-at "\\w\\|\\s_"))) (and (eq ess-first-tab-never-complete 'symbol-or-paren) (not (looking-at "\\w\\|\\s_\\|\\s)"))) (and (eq ess-first-tab-never-complete 'symbol-or-paren-or-punct) (not (looking-at "\\w\\|\\s_\\|\\s)\\|\\s."))))) (completion-at-point))))) (defun ess-indent-exp () "Indent each line of the ESS grouping following point." (interactive) (cond ((and (fboundp 'ess-r-indent-exp) (string= ess-dialect "R")) (ess-r-indent-exp)) (t (save-excursion (let ((start (point)) (end (ignore-errors (forward-sexp 1) (point)))) (when end (indent-region start end))))))) (defun ess-indent-line () "Indent current line as ESS code. Return the amount the indentation changed by." (declare (obsolete 'indent-line-function "ESS 19.04")) (funcall indent-line-function)) ;;; Dump Objects (defun ess-dump-object-into-edit-buffer (object) "Edit an ESS OBJECT in its own buffer. Without a prefix argument, this simply finds the file pointed to by `ess-source-directory'. If this file does not exist, or if a prefix argument is given, a dump() command is sent to the ESS process to generate the source buffer." (interactive (progn (ess-force-buffer-current "Process to dump from: ") (ess-read-object-name "Object to edit"))) (let* ((dirname (file-name-as-directory (if (stringp ess-source-directory) ess-source-directory (with-current-buffer (process-buffer (ess-get-process ess-local-process-name)) (ess-setq-vars-local ess-local-customize-alist) (apply ess-source-directory nil))))) (filename (concat dirname (convert-standard-filename (format ess-dump-filename-template object)))) (old-buff (get-file-buffer filename))) ;; If the directory doesn't exist, offer to create it (unless (file-exists-p (directory-file-name dirname)) (if (y-or-n-p (format "Directory %s does not exist. Create it? " dirname)) (make-directory (directory-file-name dirname)) (error "Directory %s does not exist" dirname))) ;; Three options: ;; (1) Pop to an existing buffer containing the file in question ;; (2) Find an existing file ;; (3) Create a new file by issuing a dump() command to S ;; Force option (3) if there is a prefix arg (cond (current-prefix-arg (ess-dump-object object filename)) (old-buff (pop-to-buffer old-buff)) ((file-exists-p filename) (ess-find-dump-file-other-window filename) (message "Read %s" filename)) (t (ess-dump-object object filename))))) (defun ess-dump-object (object filename) "Dump the ESS object OBJECT into file FILENAME." (unless (file-writable-p filename) (error "Can't dump %s as %f is not writeable" object filename)) (let ((dump-cmd (format inferior-ess-dump-command object filename))) ;; Make sure we start fresh (when (get-file-buffer filename) (kill-buffer (get-file-buffer filename))) (ess-command dump-cmd) (message "Dumped in %s" filename) (ess-find-dump-file-other-window filename) ;; PD, 1Apr97 ;;This ensures that the object gets indented according to ess-mode, ;;not as the R/S deparser does it. At the same time, it gets rid ;;of the mess generated by sending TAB characters to the readline ;;functions in R when you eval-buffer-*. (indent-region (point-min-marker) (point-max-marker) nil) (set-buffer-modified-p nil) ; no need to safe just because of indenting ;; Don't make backups for temporary files; it only causes clutter. ;; The ESS object itself is a kind of backup, anyway. (unless ess-keep-dump-files (make-local-variable 'make-backup-files) (setq make-backup-files nil)) ;; Don't get confirmation to delete dumped files when loading (when (eq ess-keep-dump-files 'check) (setq ess-keep-dump-files nil)) ;; Delete the file if necessary (when ess-delete-dump-files (delete-file (buffer-file-name))))) (defun ess-find-dump-file-other-window (filename) "Find ESS source file FILENAME in another window." (unless (file-readable-p filename) (ess-write-to-dribble-buffer (format "%s does not exist. Bad dump, starting fresh." filename))) ;; Generate a buffer with the dumped data (find-file-other-window filename) (auto-save-mode 1) ; Auto save in this buffer (when (and ess-function-template (goto-char (point-max)) (re-search-backward ess-dumped-missing-re nil t)) (replace-match ess-function-template t t) (set-buffer-modified-p nil) ; Don't offer to save if killed now (goto-char (point-min)) (ignore-errors ;; This may fail if there are no opens (down-list 1)))) ;;; Runners (defun ess-define-runner (name dialect &optional path) "Create a function NAME. This function starts the inferior process with the specified version. DIALECT can be \"R,\" \"S,\", \"SAS.\" If given, PATH should be the absolute path to the program. It defaults to NAME." (let ((name name) (dialect dialect) (path path)) (fset (intern name) (lambda (&optional start-args) "Start this process version in an inferior ESS buffer. Function defined using `ess-define-runner'." (interactive "P") (cond ((string= dialect "R") (let ((inferior-ess-r-program (or path name))) (require 'ess-r-mode) (R start-args))) ((string= dialect "S") (let ((inferior-S+-program (or path name))) (require 'ess-sp6-d) (S+))) ((string= dialect "SAS") (let ((inferior-SAS-program (or path name))) (require 'ess-sas-d) (SAS)))))))) (provide 'ess-mode) ;;; ess-mode.el ends here ESS-24.01.1/lisp/ess-r-completion.el000066400000000000000000000571211455642170100170150ustar00rootroot00000000000000;;; ess-r-completion.el --- R completion -*- lexical-binding: t; -*- ;; Copyright (C) 2015-2022 Free Software Foundation, Inc. ;; Author: Vitalie Spinu ;; Maintainer: ESS-core ;; This file is part of GNU Emacs. ;;; License: ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see ;; ;;; Commentary: ;; Provide completion support in R buffers. ;;; Code: (require 'cl-lib) (require 'ess-inf) (require 'ess-help) (eval-when-compile (require 'subr-x)) (defvar ac-auto-start) (defvar ac-prefix) (defvar ac-point) (defvar ac-use-comphist) (declare-function company-begin-backend "company") (declare-function company-doc-buffer "company") (defcustom ess-R-argument-suffix " = " "Suffix appended by `ac-source-R' and `ac-source-R-args' to candidates." :group 'ess-R :type 'string) ;;;*;;; ElDoc (defun ess-r-eldoc-function (&rest _ignored) "Return the doc string, or nil. If an ESS process is not associated with the buffer, do not try to look up any doc strings." (when eldoc-mode (when-let ((proc (ess-get-next-available-bg-process)) (funname (or (and ess-eldoc-show-on-symbol ;; Aggressive completion (thing-at-point 'symbol)) (car (ess--fn-name-start))))) (let* ((args (ess-function-arguments funname proc)) (bargs (cadr args)) (doc (mapconcat (lambda (el) (if (equal (car el) "...") "..." (concat (car el) "=" (cdr el)))) bargs ", ")) (margs (nth 2 args)) (W (- (window-width (minibuffer-window)) (+ 4 (length funname)))) (multiline (eq t eldoc-echo-area-use-multiline-p)) doc1) (when doc (setq doc (ess-eldoc-docstring-format funname doc (not multiline))) (when (or multiline (and margs (< (length doc1) W))) (setq doc1 (concat doc (propertize " || " 'face font-lock-function-name-face))) (while (and margs (< (length doc1) W)) (let ((head (pop margs))) (unless (assoc head bargs) (setq doc doc1 doc1 (concat doc1 head "=, "))))) (when (equal (substring doc -2) ", ") (setq doc (substring doc 0 -2))) (when (and margs (< (length doc) W)) (setq doc (concat doc " {--}")))) doc))))) (defun ess-eldoc-docstring-format (funname doc &optional truncate) (save-match-data (let* (;; Subtract 1 from window width since will cause a wraparound and ;; resize of the echo area. (W (1- (- (window-width (minibuffer-window)) (+ 2 (length funname)))))) (setq doc (if (or (<= (length doc) W) (null ess-eldoc-abbreviation-style) (eq 'none ess-eldoc-abbreviation-style)) doc ;;MILD filter (setq doc (replace-regexp-in-string "TRUE" "T" doc)) (setq doc (replace-regexp-in-string "FALSE" "F" doc)) (if (or (<= (length doc) W) (eq 'mild ess-eldoc-abbreviation-style)) doc ;;NORMAL filter (deal with long defaults) (setq doc (replace-regexp-in-string ;; function calls inside default docs foo(xxxx{..}) "([^)]\\{8\\}\\([^)]\\{4,\\}\\))" "{.}" doc nil nil 1)) (if (<= (length doc) W) doc (setq doc (replace-regexp-in-string " +[^ \t=,\"\]+=[^ \t]\\{10\\}\\([^ \t]\\{4,\\}\\)\\(,\\|\\'\\)" "{.}," doc nil nil 1)) (if (<= (length doc) W) doc (setq doc (replace-regexp-in-string " +[^ \t=,\"]+=\\([^ \t]\\{10,\\}\\)\\(,\\|\\'\\)" "{.}," doc nil nil 1)) (if (or (<= (length doc) W) (eq 'normal ess-eldoc-abbreviation-style)) doc ;;STRONG filter (replace defaults) (setq doc (replace-regexp-in-string " *[^ \t=,\"\\]* = \\([^ \t]\\{4,\\}\\)\\(,\\|\\'\\)" "{.}," doc nil nil 1)) (if (<= (length doc) W) doc (setq doc (replace-regexp-in-string "\\(=[^FT0-9].+?\\)\\(, [^ =,\"\\]+=\\|\\'\\)" "" doc nil nil 1)) (setq doc (replace-regexp-in-string "\\(=[^FT0-9].+?\\)\\(, [^ =,\"\\]+,\\|\\'\\)" "" doc nil nil 1)) (if (or (<= (length doc) W) (eq 'strong ess-eldoc-abbreviation-style)) doc ;;AGGRESSIVE filter (truncate what is left) (concat (substring doc 0 (- W 4)) "{--}"))))))))) (when (and truncate (> (length doc) W)) (setq doc (concat (substring doc 0 (- W 4)) "{--}"))) (format "%s: %s" (propertize funname 'face 'font-lock-function-name-face) doc)))) ;;;*;;; OBJECTS (defun ess-r-object-completion () "Return completions at point as required in `completion-at-point-functions'." (if (ess-make-buffer-current) (let* ((funstart (cdr (ess--fn-name-start))) (completions (ess-r-get-rcompletions funstart)) (token (pop completions))) (when completions (list (- (point) (length token)) (point) completions))) (when (string-match "complete" (symbol-name last-command)) (message "No ESS process associated with current buffer") nil))) (defun ess-complete-object-name () "Perform completion on object preceding point. Uses `ess-r-complete-object-name' when `ess-use-R-completion' is non-nil, and `ess-internal-complete-object-name' otherwise." (interactive) (if (ess-make-buffer-current) (if ess-use-R-completion (ess-r-complete-object-name) (ess-internal-complete-object-name)) ;; else give a message on second invocation (when (string-match "complete" (symbol-name last-command)) (message "No ESS process associated with current buffer") nil))) (define-obsolete-function-alias 'ess-list-object-completions #'ess-complete-object-name "ESS 19.04") ;; This one is needed for R <= 2.6.x -- hence *not* obsoleting it (defun ess-internal-complete-object-name () "Perform completion on `ess-language' object preceding point. The object is compared against those objects known by `ess-get-object-list' and any additional characters up to ambiguity are inserted. Completion only works on globally-known objects (including elements of attached data frames), and thus is most suitable for interactive `command-line' entry, and not so much for function editing since local objects (e.g. argument names) aren't known. Use \\[ess-resynch] to re-read the names of the attached directories. This is done automatically (and transparently) if a directory is modified (S only!), so the most up-to-date list of object names is always available. However attached dataframes are *not* updated, so this command may be necessary if you modify an attached dataframe." (ess-make-buffer-current) (if (memq (char-syntax (preceding-char)) '(?w ?_)) (let* ((comint-completion-addsuffix nil) (bounds (ess-bounds-of-symbol)) (beg (car bounds)) (end (cdr bounds)) (full-prefix (buffer-substring beg end)) (pattern full-prefix) ;; See if we're indexing a list with `$' (listname (if (string-match "\\(.+\\)\\$\\(\\(\\sw\\|\\s_\\)*\\)$" full-prefix) (progn (setq pattern (if (not (match-beginning 2)) "" (substring full-prefix (match-beginning 2) (match-end 2)))) (substring full-prefix (match-beginning 1) (match-end 1))))) ;; are we trying to get a slot via `@' ? (classname (if (string-match "\\(.+\\)@\\(\\(\\sw\\|\\s_\\)*\\)$" full-prefix) (progn (setq pattern (if (not (match-beginning 2)) "" (substring full-prefix (match-beginning 2) (match-end 2)))) (ess-write-to-dribble-buffer (format "(ess-C-O-Name : slots..) : patt=%s" pattern)) (substring full-prefix (match-beginning 1) (match-end 1))))) (components (if listname (ess-object-names listname) (if classname (ess-slot-names classname) ;; Default case: It hangs here when ;; options(error=recover) : (ess-get-object-list ess-current-process-name))))) ;; always return a non-nil value to prevent history expansions (or (completion-in-region beg end components) 'none)))) (defun ess-r-get-rcompletions (&optional start end prefix allow-3-dots) "Call R internal completion utilities (rcomp) for possible completions. Optional START and END delimit the entity to complete, default to bol and point. If PREFIX is given, perform completion on PREFIX. First element of the returned list is the completion token. Needs version of R >= 2.7.0." (let* ((start (or start (if prefix 0 (save-excursion (comint-bol nil) (point))))) (end (or end (if prefix (length prefix) (point)))) (prefix (or prefix (buffer-substring start end))) ;; (opts1 (if no-args "op<-rc.options(args=FALSE)" "")) ;; (opts2 (if no-args "rc.options(op)" "")) (call1 (format ".ess_get_completions(\"%s\", %d, \"%s\")" (ess-quote-special-chars prefix) (- end start) ess-R-argument-suffix)) (cmd (if allow-3-dots (concat call1 "\n") (concat "local({ r <- " call1 "; r[r != '...='] })\n")))) (ess-get-words-from-vector cmd))) (defun ess-r-complete-object-name () "Completion in R via R's completion utilities (formerly `rcompgen'). To be used instead of ESS' completion engine for R versions >= 2.7.0." (let ((possible-completions (ess-r-get-rcompletions)) token-string) (when possible-completions (setq token-string (pop possible-completions)) (or (completion-in-region (- (point) (length token-string)) (point) possible-completions) 'none)))) (defvar ess--cached-sp-objects nil) (defun ess--get-cached-completions (prefix &optional _point) (if (string-match-p "[]:$@[]" prefix) ;; call proc for objects (cdr (ess-r-get-rcompletions nil nil prefix)) ;; else, get cached list of objects (with-ess-process-buffer 'no-error ;; use proc buf alist (ess-when-new-input last-cached-completions (if (and ess--cached-sp-objects (not (process-get *proc* 'sp-for-ac-changed?))) ;; if global cache is already there, only re-read local .GlobalEnv (progn (unless ess-sl-modtime-alist ;; initialize if empty (setq ess-sl-modtime-alist '((".GlobalEnv" nil)))) ;; fixme: Make adaptive. Not on all remotes are slow; For lots of ;; objects in .GlobalEnv,locals could also be slow. (unless (file-remote-p default-directory) (ess-extract-onames-from-alist ess-sl-modtime-alist 1 'force))) (if ess--cached-sp-objects (ess-get-modtime-list 'ess--cached-sp-objects 'exclude-first) (ess-get-modtime-list) (setq ess--cached-sp-objects (cdr ess-sl-modtime-alist))) ;; reread new package, but not rda, much faster and not needed anyways (process-put *proc* 'sp-for-ac-changed? nil))) (apply #'append (cl-cddar ess-sl-modtime-alist) ; .GlobalEnv (mapcar #'cddr ess--cached-sp-objects))))) ;;;*;;; ARGUMENTS (defvar ess-r--funargs-pre-cache '(("plot" (("graphics") (("x" . "") ("y" . "NULL") ("type" . "p") ("xlim" . "NULL") ("ylim" . "NULL") ("log" . "") ("main" . "NULL") ("sub" . "NULL") ("xlab" . "NULL") ("ylab" . "NULL") ("ann" . "par(\"ann\")") ("axes" . "TRUE") ("frame.plot" . "axes") ("panel.first" . "NULL") ("panel.last" . "NULL") ("asp" . "NA") ("..." . "")) ("x" "y" "..." "ci" "type" "xlab" "ylab" "ylim" "main" "ci.col" "ci.type" "max.mfrow" "ask" "mar" "oma" "mgp" "xpd" "cex.main" "verbose" "scale" "xlim" "log" "sub" "ann" "axes" "frame.plot" "panel.first" "panel.last" "asp" "center" "edge.root" "nodePar" "edgePar" "leaflab" "dLeaf" "xaxt" "yaxt" "horiz" "zero.line" "verticals" "col.01line" "pch" "legend.text" "formula" "data" "subset" "to" "from" "newpage" "vp" "labels" "hang" "freq" "density" "angle" "col" "border" "lty" "add" "predicted.values" "intervals" "separator" "col.predicted" "col.intervals" "col.separator" "lty.predicted" "lty.intervals" "lty.separator" "plot.type" "main2" "par.fit" "grid" "panel" "cex" "dimen" "abbrev" "which" "caption" "sub.caption" "id.n" "labels.id" "cex.id" "qqline" "cook.levels" "add.smooth" "label.pos" "cex.caption" "rows" "levels" "conf" "absVal" "ci.lty" "xval" "do.points" "col.points" "cex.points" "col.hor" "col.vert" "lwd" "set.pars" "range.bars" "col.range" "xy.labels" "xy.lines" "nc" "yax.flip" "mar.multi" "oma.multi"))) ("print" (("base") (("x" . "") ("digits" . "NULL") ("quote" . "TRUE") ("na.print" . "NULL") ("print.gap" . "NULL") ("right" . "FALSE") ("max" . "NULL") ("useSource" . "TRUE") ("..." . "")) ("x" "..." "digits" "signif.stars" "intercept" "tol" "se" "sort" "verbose" "indent" "style" ".bibstyle" "prefix" "vsep" "minlevel" "quote" "right" "row.names" "max" "na.print" "print.gap" "useSource" "diag" "upper" "justify" "title" "max.levels" "width" "steps" "showEnv" "newpage" "vp" "cutoff" "max.level" "give.attr" "units" "abbrCollate" "print.x" "deparse" "locale" "symbolic.cor" "loadings" "zero.print" "calendar")))) "Alist of cached arguments for time consuming functions.") ;;;*;;; HELP (defun ess-r-get-object-help-string (sym) "Help string for ac." (let ((proc (ess-get-next-available-bg-process))) (if (null proc) "No free ESS process found" (let ((buf (get-buffer-create " *ess-command-output*"))) (when (string-match ":+\\(.*\\)" sym) (setq sym (match-string 1 sym))) (with-current-buffer (process-buffer proc) (ess-with-current-buffer buf (ess--flush-help-into-current-buffer sym nil))) (with-current-buffer buf (ess-help-underline) (goto-char (point-min)) (buffer-string)))))) (defun ess-r-get-arg-help-string (sym &optional proc) "Help string for ac." (setq sym (replace-regexp-in-string " *= *\\'" "" sym)) (let ((proc (ess-get-next-available-bg-process proc))) (if (null proc) "No free ESS process found" (let ((fun (car ess--fn-name-start-cache))) (with-current-buffer (ess-command (format ".ess_arg_help('%s','%s')\n" sym fun) nil nil nil nil proc) (goto-char (point-min)) (forward-line) (buffer-substring-no-properties (point) (point-max))))))) ;;;*;;; COMPANY ;; https://company-mode.github.io (defun company-R-objects (command &optional arg &rest _ignored) (interactive (list 'interactive)) (cl-case command (interactive (company-begin-backend 'company-R-objects)) (prefix (unless (ess-inside-string-or-comment-p) (let ((start (ess-symbol-start))) (when start (buffer-substring-no-properties start (point)))))) (candidates (when-let ((proc (ess-get-next-available-bg-process))) (with-current-buffer (process-buffer proc) (all-completions arg (ess--get-cached-completions arg))))) (doc-buffer (company-doc-buffer (ess-r-get-object-help-string arg))))) (defun company-R-args (command &optional arg &rest _ignored) (interactive (list 'interactive)) (cl-case command (interactive (company-begin-backend 'company-R-args)) (prefix (unless (ess-inside-string-or-comment-p) (let ((start (ess-arg-start))) (when start (let ((prefix (buffer-substring-no-properties start (point)))) (if ess-company-arg-prefix-length (cons prefix (>= (length prefix) ess-company-arg-prefix-length)) prefix)))))) (candidates (when-let ((proc (ess-get-next-available-bg-process))) (let* ((args (delete "..." (nth 2 (ess-function-arguments (car ess--fn-name-start-cache) proc)))) (args (mapcar (lambda (a) (concat a ess-R-argument-suffix)) args))) (all-completions arg args)))) ;; Displaying help for the argument in the echo area is disabled ;; by default for performance reasons. It causes delays or hangs (#1062). (meta (when (bound-and-true-p ess-r--company-meta) (when-let ((proc (ess-get-next-available-bg-process))) (when (with-current-buffer (process-buffer proc) (not (file-remote-p default-directory))) ;; fixme: ideally meta should be fetched with args (let ((doc (ess-r-get-arg-help-string arg proc))) (replace-regexp-in-string "^ +\\| +$" "" (replace-regexp-in-string "[ \t\n]+" " " doc))))))) (sorted t) (require-match 'never) (doc-buffer (company-doc-buffer (ess-r-get-arg-help-string arg))))) (defun company-R-library (command &optional arg &rest _ignored) (interactive (list 'interactive)) (cl-case command (interactive (company-begin-backend 'company-R-library)) (prefix (and (member (car (ess--fn-name-start)) '("library" "require")) (let ((start (ess-symbol-start))) (and start (buffer-substring start (point)))))) (candidates (when (ess-can-eval-in-background) (all-completions arg (ess-installed-packages)))) (annotation "") (duplicates nil) (sorted t))) ;; FIXME: There's a lot of overlap between `ess-r-package-completion' ;; and `company-R-library'. Can we merge them somehow? (defun ess-r-package-completion () "Return installed packages if in a call to library or require. Return format suitable for `completion-at-point-functions'." (when (and (ess-can-eval-in-background) (member (car (ess--fn-name-start)) '("library" "require"))) (list (ess-symbol-start) (point) (ess-installed-packages) :annotation-function (lambda (_) " ")))) ;;;*;;; AC SOURCES ;; http://cx4a.org/software/auto-complete/index.html ;; auto-complete is de-facto unmaintained, users should switch to `company-mode'. (defvar ac-source-R '((prefix . ess-ac-start) ;; (requires . 0) ::) (candidates . ess-ac-candidates) ;; (action . ess-ac-action-args) ;; interfere with ac-fallback mechanism on RET (which is extremely annoying in inferior buffers) (document . ess-ac-help)) "Combined ad-completion source for R function arguments and R objects.") (make-obsolete-variable 'ac-source-R "Use company-mode instead" "ESS 19.04") (defun ess-ac-start () (when (ess-process-live-p) (or (ess-arg-start) (ess-symbol-start)))) (make-obsolete-variable 'ess-ac-start "Use company-mode instead" "ESS 19.04") (defun ess-ac-candidates () "OBJECTS + ARGS." (let ((args (with-no-warnings ;; suppress obsolete warnings (ess-ac-args)))) ;; sort of intrusive but right (if (and ac-auto-start (< (length ac-prefix) ac-auto-start)) args (if args (append args (with-no-warnings ;; suppress obsolete warnings (ess-ac-objects t))) (with-no-warnings ;; suppress obsolete warnings (ess-ac-objects)))))) (make-obsolete-variable 'ess-ac-candidates "Use company-mode instead" "ESS 19.04") (defun ess-ac-help (sym) (if (string-match-p "= *\\'" sym) (ess-r-get-arg-help-string sym) (ess-r-get-object-help-string sym))) (make-obsolete-variable 'ess-ac-help "Use company-mode instead" "ESS 19.04") ;; OBJECTS (defvar ac-source-R-objects '((prefix . ess-symbol-start) ;; (requires . 2) (candidates . ess-ac-objects) (document . ess-r-get-object-help-string)) "Auto-completion source for R objects.") (make-obsolete-variable 'ac-source-R-objects "Use company-mode instead" "ESS 19.04") (defun ess-ac-objects (&optional no-kill) "Get all cached objects." (declare (obsolete "Use company-mode instead" "ESS 19.04")) (let ((aprf ac-prefix)) (when (and aprf (ess-process-live-p)) (unless no-kill ;; workaround (kill-local-variable 'ac-use-comphist)) (ess--get-cached-completions aprf ac-point)))) ;; ARGS (defvar ac-source-R-args '((prefix . ess-arg-start) ;; (requires . 0) (candidates . ess-ac-args) ;; (action . ess-ac-action-args) (document . ess-r-get-arg-help-string)) "Auto-completion source for R function arguments.") (make-obsolete-variable 'ac-source-R-args "Use company-mode instead" "ESS 19.04") (defun ess-ac-args () "Get the args of the function when inside parentheses." (declare (obsolete "Use company-mode-instead" "ESS 19.04")) (when (and ess--fn-name-start-cache ;; set in a call to ess-arg-start (ess-process-live-p)) (let ((args (nth 2 (ess-function-arguments (car ess--fn-name-start-cache))))) (if args (setq-local ac-use-comphist nil) (kill-local-variable 'ac-use-comphist)) (delete "..." args) (mapcar (lambda (a) (concat a ess-R-argument-suffix)) args)))) (provide 'ess-r-completion) ;;; ess-r-completion.el ends here ESS-24.01.1/lisp/ess-r-flymake.el000066400000000000000000000240001455642170100162620ustar00rootroot00000000000000;;; ess-r-flymake.el --- A ess-r Flymake backend -*- lexical-binding: t; -*- ;; Copyright (C) 2018-2022 Free Software Foundation, Inc. ;; Maintainer: ESS-core ;; This file is part of GNU Emacs. ;;; License: ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see ;; ;;; Commentary: ;; Flymake is the built-in Emacs package that supports on-the-fly ;; syntax checking. This file adds support for this in ess-r-mode by ;; relying on the lintr package, available on CRAN and currently ;; hosted at https://github.com/jimhester/lintr. ;;; Code: (eval-when-compile (require 'cl-lib)) (require 'ess-inf) (require 'flymake) ;; Appease the byte compiler for Emacs 25. Remove after dropping ;; support for Emacs 25. (declare-function flymake-diag-region "flymake") (declare-function flymake-make-diagnostic "flymake") (declare-function flymake--overlays "flymake") (declare-function ess-r-project "ess-r-mode") (declare-function ess-r-package-project "ess-r-package") (defcustom ess-r-flymake-linters '("closed_curly_linter = NULL" "commas_linter = NULL" "commented_code_linter = NULL" "infix_spaces_linter = NULL" "line_length_linter = NULL" "object_length_linter = NULL" "object_name_linter = NULL" "object_usage_linter = NULL" "open_curly_linter = NULL" "pipe_continuation_linter = NULL" "single_quotes_linter = NULL" "spaces_inside_linter = NULL" "spaces_left_parentheses_linter = NULL" "trailing_blank_lines_linter = NULL" "trailing_whitespace_linter = NULL") "Default linters to use. Can be either a string with R expression to be used as is (e.g. `lintr::default_linters'). Or a list of strings where each element is passed as argument to `lintr::with_defaults'." :group 'ess-R :type '(choice string (repeat string)) :package-version '(ess . "18.10")) (defcustom ess-r-flymake-lintr-cache t "If non-nil, cache lintr results." :group 'ess-R :type 'boolean :package-version '(ess . "18.10")) (defvar-local ess-r--flymake-proc nil) (defvar-local ess-r--lintr-file nil "Location of the .lintr file for this buffer.") (defvar ess-r--flymake-def-linter (replace-regexp-in-string "[\n\t ]+" " " "esslint <- function(str, ...) { if (!suppressWarnings(require(lintr, quietly=T))) { cat('@@error: @@`lintr` package not installed') } else { if (packageVersion('lintr') <= '1.0.3') { cat('@@error: @@Need `lintr` version > v1.0.3') } else { tryCatch(lintr::lint(commandArgs(TRUE), ...), error = function(e) { cat('@@warning: @@', e) }) } } };")) (defun ess-r--find-lintr-file () "Return the absolute path to the .lintr file. Check first the current directory, then the project root, then the package root, then the user's home directory. Return nil if we couldn't find a .lintr file." ;; VS[2022-01-26]: Can't this entire thing be replaced by ;; `(locate-dominating-file ".lintr")`? (let* ((cur-file (expand-file-name ".lintr" default-directory)) (pkg (cdr (ess-r-package-project))) (pkg-file (and pkg (expand-file-name ".lintr" pkg))) (proj (ess-r-project)) (proj-file (and proj (expand-file-name ".lintr" proj))) (home-file (expand-file-name ".lintr" (getenv "HOME")))) (cond ((file-readable-p cur-file) cur-file) ((and proj-file (file-readable-p proj-file)) proj-file) ((and pkg-file (file-readable-p pkg-file)) pkg-file) ((file-readable-p home-file) home-file)))) (defun ess-r--flymake-linters () "If `ess-r-flymake-linters' is a string, use that. Otherwise, construct a string to pass to lintr::with_defaults." (replace-regexp-in-string "[\n\t ]+" " " (if (stringp ess-r-flymake-linters) ess-r-flymake-linters (concat "lintr::with_defaults(" (mapconcat #'identity ess-r-flymake-linters ", ") ")")))) (defun ess-r--flymake-msg-type (str) "Transform STR into log level." (cond ((string= str "error: ") :error) ((string= str "warning: ") :warning) ((string= str "style: ") :note) (t (error "Invalid msg type %s" str)))) (defun ess-r--flymake-check-errors () "Check for critical errors and return non-nil if such occurred." (goto-char (point-min)) (when (re-search-forward "@@\\(\\(error\\|warning\\): \\)@@" nil t) (let ((type (ess-r--flymake-msg-type (match-string 1))) (msg (buffer-substring-no-properties (match-end 0) (point-max)))) (flymake-log type msg) (eq type :error)))) (defun ess-r--flymake-parse-output (msg-buffer src-buffer report-fn) "Parse the content of MSG-BUFFER for lint locations. SRC-BUFFER is the original source buffer. Collect all messages into a list and call REPORT-FN on it." (with-current-buffer msg-buffer (if (ess-r--flymake-check-errors) (with-current-buffer src-buffer ;; we are in the sentinel here; don't throw but remove our hook instead (remove-hook 'flymake-diagnostic-functions #'ess-r-flymake t)) (goto-char (point-min)) (cl-loop while (search-forward-regexp ;; Regex to match the output lint() gives us. (rx line-start ":" ;; row (group-n 1 (one-or-more num)) ":" ;; column (group-n 2 (one-or-more num)) ": " ;; type (group-n 3 (| "style: " "warning: " "error: ")) ;; msg (group-n 4 (one-or-more not-newline)) line-end) nil t) for msg = (match-string 4) for (beg . end) = (let ((line (string-to-number (match-string 1))) (col (string-to-number (match-string 2)))) (flymake-diag-region src-buffer line col)) for type = (ess-r--flymake-msg-type (match-string 3)) collect (flymake-make-diagnostic src-buffer beg end type msg) into diags finally (funcall report-fn diags))))) (defun ess-r-flymake (report-fn &rest _args) "A Flymake backend for ESS-R modes. Relies on the lintr package. REPORT-FN is flymake's callback function." (unless (executable-find inferior-ess-r-program) (error "Cannot find program '%s'" inferior-ess-r-program)) ;; Kill the process if earlier check was found. The sentinel of the earlier ;; check will detect this. (when (process-live-p ess-r--flymake-proc) (kill-process ess-r--flymake-proc)) (if (and (eql ess-use-flymake 'process) (not (ess-process-live-p))) (progn (funcall report-fn nil) (mapc #'delete-overlay (flymake--overlays))) (let ((src-buffer (current-buffer))) (setq ess-r--flymake-proc (make-process :name "ess-r-flymake" :noquery t :connection-type 'pipe :buffer (generate-new-buffer " *ess-r-flymake*") :command (list inferior-R-program "--no-save" "--no-restore" "--no-site-file" "--no-init-file" "--slave" "-e" (concat (when ess-r--lintr-file (concat "options(lintr.linter_file = \"" ess-r--lintr-file "\");")) ess-r--flymake-def-linter ;; commandArgs(TRUE) returns everything after ;; --args as a character vector "esslint(commandArgs(TRUE)" (unless ess-r--lintr-file (concat ", linters = " (ess-r--flymake-linters))) (when ess-r-flymake-lintr-cache ", cache = TRUE") ")") "--args" (buffer-substring-no-properties (point-min) (point-max))) :sentinel (lambda (proc _event) (cond ((eq 'exit (process-status proc)) (unwind-protect (if (eq proc (buffer-local-value 'ess-r--flymake-proc src-buffer)) (ess-r--flymake-parse-output (process-buffer proc) src-buffer report-fn) (flymake-log :warning "Canceling obsolete check %s" proc)) (kill-buffer (process-buffer proc)))) ((not (eq 'run (process-status proc))) (kill-buffer (process-buffer proc)))))))))) (defun ess-r-setup-flymake () "Setup flymake for ESS. Activate flymake only if `ess-use-flymake' is non-nil." (when ess-use-flymake (when (< emacs-major-version 26) (error "ESS-flymake requires Emacs version 26 or later")) (when (string= "R" ess-dialect) (setq ess-r--lintr-file (ess-r--find-lintr-file)) (add-hook 'flymake-diagnostic-functions #'ess-r-flymake nil t) ;; Try not to enable flymake if flycheck is already running: (unless (bound-and-true-p flycheck-mode) (flymake-mode))))) ;; Enable flymake in Emacs 26+ (when (<= 26 emacs-major-version) (if (eval-when-compile (<= 26 emacs-major-version)) (add-hook 'ess-r-mode-hook #'ess-r-setup-flymake) (when ess-use-flymake (display-warning 'ess "ESS was compiled with older version of Emacs;\n `ess-r-flymake' won't be available")))) (provide 'ess-r-flymake) ;;; ess-r-flymake.el ends here ESS-24.01.1/lisp/ess-r-mode.el000066400000000000000000003735261455642170100156020ustar00rootroot00000000000000;;; ess-r-mode.el --- R customization -*- lexical-binding: t; -*- ;; Copyright (C) 1997-2022 Free Software Foundation, Inc. ;; Author: A.J. Rossini ;; Created: 12 Jun 1997 ;; Maintainer: ESS-core ;; This file is part of GNU Emacs. ;;; License: ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see ;; ;;; Commentary: ;; This file defines all the R customizations for ESS. See ess-s-lang.el ;; for general S language customizations. ;;; Code: (eval-when-compile (require 'subr-x)) (require 'cl-lib) (require 'compile) (require 'ess-mode) (require 'ess-help) (require 'ess-s-lang) (require 'ess-roxy) (require 'ess-r-completion) (require 'ess-r-syntax) (require 'ess-r-package) (require 'ess-trns) (require 'ess-r-xref) (when (>= emacs-major-version 26) (require 'ess-r-flymake)) ; Flymake rewrite in Emacs 26 (declare-function ess-rdired "ess-rdired" ()) (defcustom ess-r-mode-hook nil "Hook run when entering `ess-r-mode'." :options '(electric-layout-local-mode) :type 'hook :group 'ess-R) ;; Define and run old hook for backward compatibility. We don't ;; obsolete it with warnings because this is a historically important ;; user-facing variable and it would not be worth the trouble. (defvar R-mode-hook nil "This variable is obsolete since ESS 19.04; use `ess-r-mode-hook' instead.") (add-hook 'ess-r-mode-hook (lambda () (run-hooks 'R-mode-hook))) (defcustom ess-r-fetch-ESSR-on-remotes nil "If non-nil, when loading ESSR, fetch it from the GitHub repository. Otherwise source from local ESS installation. When the value is \\='ess-remote, fetch only with ess-remote's and not with TRAMP connections. When t, always fetch from remotes. Change this variable when loading ESSR code on remotes fails for you. Fetching happens once per new ESSR version. The archive is stored in ~/.config/ESSR/ESSRv[VERSION].rds file. You can download and place it there manually if the remote has restricted network access." :type '(choice (const nil :tag "Never") (const ess-remote :tag "With ess-remote only") (const t :tag "Always")) :group 'ess-R) ;; Silence the byte compiler (defvar add-log-current-defun-header-regexp) ;; TODO: Refactor so as to not rely on dynamic scoping. After that ;; refactor, also remove the file-local-variable byte-compile-warnings ;; (not lexical) at the bottom. (defvar containing-sexp) (defvar indent-point) (defvar prev-containing-sexp) (define-obsolete-variable-alias 'ess-r-versions 'ess-r-runner-prefixes "ESS 19.04") (defcustom ess-r-runner-prefixes (let ((r-ver '("R-1" "R-2" "R-3" "R-4" "R-5" "R-6" "R-7" "R-devel" "R-patched"))) (if (eq system-type 'darwin) (append r-ver '("R32" "R64")) r-ver)) "List of partial strings for versions of R to access within ESS. Each string specifies the start of a filename. If a filename beginning with one of these strings is found on variable `exec-path', a command for that version of R is made available. For example, if the file \"R-1.8.1\" is found and this variable includes the string \"R-1\", a function called `R-1.8.1' will be available to run that version of R. If duplicate versions of the same program are found (which happens if the same path is listed on variable `exec-path' more than once), they are ignored by calling `delete-dups'. Set this variable to nil to disable searching for other versions of R. Setting this variable directly does not take effect; use either \\[customize-option] or set the value by using `ess-r-runners-reset'." :group 'ess-R :package-version '(ess . "19.04") :type '(repeat string) :set #'ess-r-runners-reset ;; Use `custom-initialize-default' since we call ;; `ess-r-define-runners' at the end of this file directly. :initialize #'custom-initialize-default) ;;*;; Mode definition ;;;*;;; UI (Keymaps / Menus) (defvar ess-dev-map (let (ess-dev-map) (define-prefix-command 'ess-dev-map) (define-key ess-dev-map "\C-s" #'ess-r-set-evaluation-env) (define-key ess-dev-map "s" #'ess-r-set-evaluation-env) (define-key ess-dev-map "T" #'ess-toggle-tracebug) (define-key ess-dev-map "\C-l" #'ess-r-devtools-load-package) (define-key ess-dev-map "l" #'ess-r-devtools-load-package) (define-key ess-dev-map "`" #'ess-show-traceback) (define-key ess-dev-map "~" #'ess-show-call-stack) (define-key ess-dev-map "\C-w" #'ess-watch) (define-key ess-dev-map "w" #'ess-watch) (define-key ess-dev-map "\C-d" #'ess-debug-flag-for-debugging) (define-key ess-dev-map "d" #'ess-debug-flag-for-debugging) (define-key ess-dev-map "\C-u" #'ess-debug-unflag-for-debugging) (define-key ess-dev-map "u" #'ess-debug-unflag-for-debugging) (define-key ess-dev-map "" #'ess-debug-unflag-for-debugging) (define-key ess-dev-map "\C-b" #'ess-bp-set) (define-key ess-dev-map "b" #'ess-bp-set) (define-key ess-dev-map "" #'ess-bp-set-conditional) (define-key ess-dev-map "B" #'ess-bp-set-conditional) (define-key ess-dev-map "\C-L" #'ess-bp-set-logger) (define-key ess-dev-map "L" #'ess-bp-set-logger) (define-key ess-dev-map "\C-o" #'ess-bp-toggle-state) (define-key ess-dev-map "o" #'ess-bp-toggle-state) (define-key ess-dev-map "\C-k" #'ess-bp-kill) (define-key ess-dev-map "k" #'ess-bp-kill) (define-key ess-dev-map "\C-K" #'ess-bp-kill-all) (define-key ess-dev-map "K" #'ess-bp-kill-all) (define-key ess-dev-map "\C-n" #'ess-bp-next) (define-key ess-dev-map "n" #'ess-bp-next) (define-key ess-dev-map "i" #'ess-debug-goto-input-event-marker) (define-key ess-dev-map "I" #'ess-debug-goto-input-event-marker) (define-key ess-dev-map "\C-p" #'ess-bp-previous) (define-key ess-dev-map "p" #'ess-bp-previous) (define-key ess-dev-map "\C-e" #'ess-debug-toggle-error-action) (define-key ess-dev-map "e" #'ess-debug-toggle-error-action) (define-key ess-dev-map "0" #'ess-electric-selection) (define-key ess-dev-map "1" #'ess-electric-selection) (define-key ess-dev-map "2" #'ess-electric-selection) (define-key ess-dev-map "3" #'ess-electric-selection) (define-key ess-dev-map "4" #'ess-electric-selection) (define-key ess-dev-map "5" #'ess-electric-selection) (define-key ess-dev-map "6" #'ess-electric-selection) (define-key ess-dev-map "7" #'ess-electric-selection) (define-key ess-dev-map "8" #'ess-electric-selection) (define-key ess-dev-map "9" #'ess-electric-selection) (define-key ess-dev-map "?" #'ess-tracebug-show-help) ess-dev-map) "Keymap for commands related to development and debugging.") (defvar ess-r-package-check-map (let (ess-r-package-check-map) (define-prefix-command 'ess-r-package-check-map) (define-key ess-r-package-check-map "\C-c" #'ess-r-devtools-check-package) (define-key ess-r-package-check-map "c" #'ess-r-devtools-check-package) (define-key ess-r-package-check-map "\C-w" #'ess-r-devtools-check-with-winbuilder) (define-key ess-r-package-check-map "w" #'ess-r-devtools-check-with-winbuilder) (define-key ess-r-package-check-map "h" #'ess-r-rhub-check-package) ess-r-package-check-map) "Keymap for R package checks.") (defvar ess-r-package-dev-map (let (ess-r-package-dev-map) (define-prefix-command 'ess-r-package-dev-map) (define-key ess-r-package-dev-map "\C-s" #'ess-r-set-evaluation-env) (define-key ess-r-package-dev-map "s" #'ess-r-set-evaluation-env) (define-key ess-r-package-dev-map "\C-a" #'ess-r-devtools-execute-command) (define-key ess-r-package-dev-map "a" #'ess-r-devtools-execute-command) (define-key ess-r-package-dev-map "\C-e" #'ess-r-devtools-execute-command) (define-key ess-r-package-dev-map "e" #'ess-r-devtools-execute-command) (define-key ess-r-package-dev-map "\C-b" #'ess-r-devtools-build) (define-key ess-r-package-dev-map "b" #'ess-r-devtools-build) (define-key ess-r-package-dev-map "\C-c" 'ess-r-package-check-map) (define-key ess-r-package-dev-map "c" 'ess-r-package-check-map) (define-key ess-r-package-dev-map "\C-d" #'ess-r-devtools-document-package) (define-key ess-r-package-dev-map "d" #'ess-r-devtools-document-package) (define-key ess-r-package-dev-map "g" #'ess-r-devtools-install-github) (define-key ess-r-package-dev-map "\C-i" #'ess-r-devtools-install-package) (define-key ess-r-package-dev-map "i" #'ess-r-devtools-install-package) (define-key ess-r-package-dev-map "\C-l" #'ess-r-devtools-load-package) (define-key ess-r-package-dev-map "l" #'ess-r-devtools-load-package) (define-key ess-r-package-dev-map "\C-t" #'ess-r-devtools-test-package) (define-key ess-r-package-dev-map "t" #'ess-r-devtools-test-package) (define-key ess-r-package-dev-map "\C-u" #'ess-r-devtools-unload-package) (define-key ess-r-package-dev-map "u" #'ess-r-devtools-unload-package) ess-r-package-dev-map)) (easy-menu-define ess-roxygen-menu nil "Roxygen submenu." '("Roxygen" :visible (and ess-dialect (string-match "^R" ess-dialect)) ["Update/Generate Template" ess-roxy-update-entry t] ["Preview Rd" ess-roxy-preview-Rd t] ["Preview HTML" ess-roxy-preview-HTML t] ["Preview text" ess-roxy-preview-text t] ["Hide all" ess-roxy-hide-all t] ["Toggle Roxygen Prefix" ess-roxy-toggle-roxy-region t])) (easy-menu-define ess-tracebug-menu nil "Tracebug submenu." '("Tracebug" :visible (and ess-dialect (string-match "^R" ess-dialect)) ;; :enable ess-local-process-name ["Active?" ess-toggle-tracebug :style toggle :selected (or (and (ess-process-live-p) (ess-process-get 'tracebug)) ess-use-tracebug)] ["Show traceback" ess-show-traceback (ess-process-live-p)] ["Show call stack" ess-show-call-stack (ess-process-live-p)] ["Watch" ess-watch (and (ess-process-live-p) (ess-process-get 'tracebug))] ["Error action cycle" ess-debug-toggle-error-action (and (ess-process-live-p) (ess-process-get 'tracebug))] "----" ["Flag for debugging" ess-debug-flag-for-debugging ess-local-process-name] ["Unflag for debugging" ess-debug-unflag-for-debugging ess-local-process-name] "----" ["Set BP" ess-bp-set t] ["Set conditional BP" ess-bp-set-conditional t] ["Set logger BP" ess-bp-set-logger t] ["Kill BP" ess-bp-kill t] ["Kill all BPs" ess-bp-kill-all t] ["Next BP" ess-bp-next t] ["Previous BP" ess-bp-previous t] "-----" ["About" ess-tracebug-show-help t])) (easy-menu-define ess-r-package-menu nil "Package Development submenu." '("Package development" :visible (and ess-dialect (string-match "^R" ess-dialect)) ["Active?" ess-r-package-mode :style toggle :selected ess-r-package-mode] ["Select package for evaluation" ess-r-set-evaluation-env t])) (easy-menu-add-item ess-mode-menu nil ess-roxygen-menu "end-dev") (easy-menu-add-item ess-mode-menu nil ess-r-package-menu "end-dev") (easy-menu-add-item ess-mode-menu nil ess-tracebug-menu "end-dev") (easy-menu-add-item inferior-ess-mode-menu nil ess-r-package-menu "end-dev") (easy-menu-add-item inferior-ess-mode-menu nil ess-tracebug-menu "end-dev") (defvar ess-r-mode-map (let ((map (make-sparse-keymap))) (define-key map (kbd "C-c C-=") #'ess-cycle-assign) (define-key map "\M-?" #'ess-complete-object-name) (define-key map (kbd "C-c C-.") 'ess-rutils-map) map)) (defvar ess-r-mode-syntax-table (let ((table (copy-syntax-table S-syntax-table))) ;; Letting Emacs treat backquoted names and %ops% as strings solves ;; many problems with regard to nested strings and quotes (modify-syntax-entry ?` "\"" table) (modify-syntax-entry ?% "\"" table) ;; Underscore is valid in R symbols (modify-syntax-entry ?_ "_" table) (modify-syntax-entry ?: "." table) (modify-syntax-entry ?@ "." table) (modify-syntax-entry ?$ "." table) (modify-syntax-entry ?\\ "." table) table) "Syntax table for `ess-r-mode'.") (defvar ess-r-completion-syntax-table (let ((table (copy-syntax-table ess-r-mode-syntax-table))) (modify-syntax-entry ?. "_" table) (modify-syntax-entry ?: "_" table) (modify-syntax-entry ?$ "_" table) (modify-syntax-entry ?@ "_" table) table) "Syntax table used for completion and help symbol lookup. It makes underscores and dots word constituent chars.") (defvar ess-r-namespaced-load-verbose t "Whether to display information on namespaced loading. When t, loading a file into a namespaced will output information about which objects are exported and which stay hidden in the namespace.") ;; The syntax class for '\' is punctuation character to handle R 4.1 ;; lambdas. Inside strings it should be treated as an escape ;; character which we ensure here. (defun ess-r--syntax-propertize-backslash () (when (nth 3 (save-excursion (syntax-ppss (1- (point))))) (string-to-syntax "\\"))) ;; Adapted from `python-syntax-stringify' (defun ess-r--syntax-propertize-raw-string-opening () (let* ((raw-beg (match-beginning 0)) (quote-beg (1+ raw-beg)) (ppss (save-excursion (goto-char raw-beg) (syntax-ppss))) (string-start (and (eq t (nth 3 ppss)) (nth 8 ppss)))) (cond ;; Inside a comment ((nth 4 ppss) nil) ;; This set of quotes delimits the start of a string ((null string-start) (put-text-property quote-beg (1+ quote-beg) 'syntax-table (string-to-syntax "|")))))) (defun ess-r--syntax-propertize-raw-string-closing () (let* ((quote-end (match-end 0)) (quote-chr (aref (match-string 3) 0)) (dashes (match-string 2)) (matching-delim (pcase (match-string 1) (`")" ?\() (`"}" ?{) (`"]" ?\[))) (ppss (save-excursion (goto-char quote-end) (syntax-ppss))) (string-start (and (eq t (nth 3 ppss)) (nth 8 ppss)))) (when string-start (save-match-data (save-excursion (goto-char string-start) (when (equal (char-after) quote-chr) (forward-char) (re-search-forward "-*" nil t) (let ((matching-dashes (match-string 0))) (when (or (not matching-dashes) (string= matching-dashes dashes)) (when (equal (char-after) matching-delim) (put-text-property (1- quote-end) quote-end 'syntax-table (string-to-syntax "|"))))))))))) (defconst ess-r--syntax-propertize-function (syntax-propertize-rules ("[rR]\\([\"']\\)\\(-*\\)\\([([{]\\)" (0 (ignore (ess-r--syntax-propertize-raw-string-opening)))) ("\\([])}]\\)\\(-*\\)\\([\"']\\)" (0 (ignore (ess-r--syntax-propertize-raw-string-closing)))) ("\\\\" (0 (ess-r--syntax-propertize-backslash))))) (defun ess-r-font-lock-syntactic-face-function (state) (if (nth 3 state) ;; string case (let ((string-end (save-excursion (ess-goto-char (nth 8 state)) (ess-forward-sexp) (point)))) (cond ((eq (nth 3 state) ?%) (if (eq (point) (1- string-end)) (when (cdr (assq 'ess-fl-keyword:operators ess-R-font-lock-keywords)) 'ess-operator-face) (if (cdr (assq 'ess-R-fl-keyword:%op% ess-R-font-lock-keywords)) 'ess-%op%-face nil))) ((save-excursion (and (cdr (assq 'ess-R-fl-keyword:fun-defs ess-R-font-lock-keywords)) (ess-goto-char string-end) (ess-looking-at "<-") (ess-goto-char (match-end 0)) (ess-looking-at "function\\b" t))) font-lock-function-name-face) ((save-excursion (and (cdr (assq 'ess-fl-keyword:fun-calls ess-R-font-lock-keywords)) (ess-goto-char string-end) (ess-looking-at "("))) ess-function-call-face) ((eq (nth 3 state) ?`) nil) (t font-lock-string-face))) font-lock-comment-face)) ;; Don't fontify backquoted symbols as strings (defun inferior-ess-r-font-lock-syntactic-face-function (state) (if (nth 3 state) (if (eq (nth 3 state) ?`) nil font-lock-string-face) font-lock-comment-face)) (defvar ess-r--non-fn-kwds '("in" "else" "break" "next" "repeat")) (defvar-local ess-r--keyword-regexp nil) (defun ess-r--find-fl-keyword (limit) "Search for R keyword and set the match data. To be used as part of `font-lock-defaults' keywords." (unless ess-r--keyword-regexp (let (fn-kwds non-fn-kwds) (dolist (kw ess-R-keywords) (if (member kw ess-r--non-fn-kwds) (push kw non-fn-kwds) (push kw fn-kwds))) (setq ess-r--keyword-regexp (concat "\\(" (regexp-opt non-fn-kwds 'words) "\\)\\|\\(" (regexp-opt fn-kwds 'words) "\\)")))) (let (out) (while (and (not out) (re-search-forward ess-r--keyword-regexp limit t)) (save-match-data (setq out (if (match-beginning 1) ;; Non-function-like keywords: Always fontified ;; except for `in` for which we check it's part ;; of a `for` construct. Ideally we'd check that ;; other keywords like `break` or `next` are ;; part of the right syntactic construct but ;; that requires robust and efficient detection ;; of complete expressions. (if (string= (match-string 1) "in") (save-excursion (goto-char (match-beginning 1)) (and (ess-backward-up-list) (forward-word -1) (looking-at "for\\s-*("))) t) ;; Function-like keywords: check if they are ;; followed by an open paren (looking-at "\\s-*("))))) out)) (define-obsolete-variable-alias 'R-customize-alist 'ess-r-customize-alist "ESS 18.10.2") (defvar ess-r-customize-alist (append '((ess-local-customize-alist . 'ess-r-customize-alist) (ess-dialect . "R") (ess-suffix . "R") (ess-traceback-command . ess-r-traceback-command) (ess-call-stack-command . ess-r-call-stack-command) (ess-mode-completion-syntax-table . ess-r-completion-syntax-table) (ess-build-eval-message-function . #'ess-r-build-eval-message) (ess-dump-filename-template . ess-r-dump-filename-template) (ess-change-sp-regexp . ess-r-change-sp-regexp) (ess-help-sec-regex . ess-help-r-sec-regex) (ess-help-sec-keys-alist . ess-help-r-sec-keys-alist) (ess-function-pattern . ess-r-function-pattern) (ess-object-name-db-file . "ess-r-namedb.el") (ess-smart-operators . ess-r-smart-operators) (inferior-ess-program . inferior-ess-r-program) (inferior-ess-objects-command . inferior-ess-r-objects-command) (inferior-ess-search-list-command . "search()\n") (inferior-ess-help-command . inferior-ess-r-help-command) (inferior-ess-exit-command . "q()") (ess-error-regexp-alist . ess-r-error-regexp-alist) (ess-describe-object-at-point-commands . 'ess-r-describe-object-at-point-commands) (ess-STERM . "iESS") (ess-editor . ess-r-editor) (ess-pager . ess-r-pager)) S-common-cust-alist) "Variables to customize for R.") (cl-defmethod ess-build-tags-command (&context (ess-dialect "R")) "Return tags command for R." "rtags('%s', recursive = TRUE, pattern = '\\\\.[RrSs](rw)?$',ofile = '%s')") (defvar ess-r-traceback-command "local({cat(geterrmessage(), \ '---------------------------------- \n', \ fill=TRUE); try(traceback(), silent=TRUE)})\n") (defvar ess-r-call-stack-command "traceback(1)\n") (defun ess-r-format-command (cmd &rest args) (let ((sentinel (alist-get 'output-delimiter args))) (ess-r--format-call ".ess.command(local(%s), '%s')\n" cmd sentinel))) (defvar ess-r-format-command-alist '((fun . ess-r-format-command) (use-delimiter . t))) (defvar ess-r-dump-filename-template (replace-regexp-in-string "S$" "R" ess-dump-filename-template-proto)) (defvar ess-r-ac-sources '(ac-source-R)) (defvar ess-r-company-backends '((company-R-library company-R-args company-R-objects :separate))) (defconst ess-help-r-sec-regex "^[A-Z][A-Za-z].+:$" "Reg(ular) Ex(pression) of section headers in help file.") (defconst ess-help-r-sec-keys-alist '((?a . "\\s *Arguments:") (?d . "\\s *Description:") (?D . "\\s *Details:") (?t . "\\s *Details:") (?e . "\\s *Examples:") (?n . "\\s *Note:") (?r . "\\s *References:") (?s . "\\s *See Also:") (?u . "\\s *Usage:") (?v . "\\s *Value[s]?") ; ) "Alist of (key . string) pairs for use in help section searching.") (defvar ess-r-error-regexp-alist '(R R1 R2 R3 R4 R-rlang R-recover) "List of symbols which are looked up in `compilation-error-regexp-alist-alist'.") (dolist (l '(;; Takes precedence over R1 below in English locales, and allows spaces in file path (R "\\(\\(?: at \\|(@\\)\\([^#()\n:]+\\)[#:]\\([0-9]+\\)\\)" 2 3 nil 2 1) ;; valgrind, testthat, rlang/shiny style ;; e.g. (stl_numeric.h:183), (test-parsers.R:238:3) [.../R/file.R#158] (R1 "\\s(\\([^0-9][^ ():\n]+\\)[#:]\\([0-9]+\\)[#:]?\\([0-9]+\\)?\\s)" 1 2 nil 2) (R2 "(\\(\\w+ \\([^())\n]+\\)#\\([0-9]+\\)\\))" 2 3 nil 2 1) ;; Precedes R4 and allows spaces in file path, Starts at bol or with ": " (patterns 3,4,5,6,9) (R3 "\\(?:^ *\\|: ?\\)\\([^-+[:digit:] \t\n]:?[^: \t\n]*\\):\\([0-9]+\\):\\(?:\\([0-9]+\\):\\)?" 1 2 3 2 1) ;; Don't start with digit; no spaces (R4 "\\([^-+ [:digit:]][^: \t\n]+\\):\\([0-9]+\\):\\([0-9]+\\):" 1 2 3 2 1) (R-rlang "^ *[0-9]+\\..* \\(\\([^ :]+\\):\\([0-9]+\\):\\([0-9]+\\)\\)$" 2 3 4 nil 1) (R-recover " *[0-9]+: +\\([^:\n\t]+?\\)#\\([0-9]+:\\)" 1 2 nil 2 1))) (cl-pushnew l compilation-error-regexp-alist-alist)) (define-obsolete-variable-alias 'ess-r-versions-created 'ess-r-created-runners "ESS 18.10") (defvar ess-r-created-runners nil "List of R-versions found from `ess-r-runner-prefixes' on the system.") ;;;*;;; Mode init (define-obsolete-variable-alias 'ess-R-post-run-hook 'ess-r-post-run-hook "ESS 18.10.2") ;; We moved the set-wd instruction from `inferior-ess' to here to ;; avoid sending R code to gdb or lldb before we had a chance to ;; send "run". So this is no longer generic and inferior modes need ;; to call this manually. One way to fix this would be to make ;; `inferior-ess' a `cl-defgeneric'. (defvar ess-r-post-run-hook nil "Functions run in process buffer after the initialization of R process. Make sure to call blocking commands (e.g. based on `ess-command') first. Streaming commands (e.g. based on `ess-send-string') should come last, otherwise they will make R busy and the blocking commands will throw an error.") ;;;###autoload (defun run-ess-r (&optional start-args) "Call 'R', the 'GNU S' system from the R Foundation. Optional prefix (\\[universal-argument]) allows to set command line arguments, such as --vsize. This should be OS agnostic. If you have certain command line arguments that should always be passed to R, put them in the variable `inferior-R-args'. START-ARGS can be a string representing an argument, a list of such strings, or any other non-nil value. In the latter case, you will be prompted to enter arguments interactively." (interactive "P") (ess-write-to-dribble-buffer ;; for debugging only (format "\n(R): ess-dialect=%s, buf=%s, start-arg=%s\n current-prefix-arg=%s\n" ess-dialect (current-buffer) start-args current-prefix-arg)) (unless (or (file-remote-p default-directory) (when ess-startup-directory (file-remote-p (if (symbolp ess-startup-directory) (symbol-value ess-startup-directory) ess-startup-directory))) ;; TODO: Once we drop Emacs 26 support, can probably ;; just use the REMOTE argument of `executable-find'. (executable-find inferior-ess-r-program)) (display-warning 'ess (format "%s could not be found on the system. Try running `run-ess-r-newest' instead, which searches your system for R." inferior-ess-r-program) :error) (user-error "%s program not found" inferior-ess-r-program)) (let* ((r-always-arg (if (or ess-microsoft-p (eq system-type 'cygwin)) "--ess " ;; else: "Unix alike" (if (not ess-R-readline) "--no-readline "))) (start-args (cond ((stringp start-args) start-args) ((and start-args (listp start-args) (cl-every #'stringp start-args)) (mapconcat #'identity start-args " ")) (start-args (read-string (concat "Starting Args" (if r-always-arg (concat " [other than '" r-always-arg "']")) " ? "))))) (r-start-args (concat r-always-arg inferior-R-args " " ; add space just in case start-args)) (debug (string-match-p " -d \\| --debugger=" r-start-args)) use-dialog-box) (when (or ess-microsoft-p (eq system-type 'cygwin)) (setq use-dialog-box nil) (when ess-microsoft-p ;; default-process-coding-system would break UTF locales on Unix (setq default-process-coding-system '(undecided-dos . undecided-dos)))) (let ((inf-buf (inferior-ess r-start-args ess-r-customize-alist debug))) (with-current-buffer inf-buf (ess-process-put 'funargs-pre-cache ess-r--funargs-pre-cache) (if debug (progn ;; We need to use callback, because R might start with a gdb process (ess-process-put 'callbacks '(inferior-ess-r--init-callback)) ;; Trigger the callback (process-send-string (get-buffer-process inf-buf) "r\n")) (ess-r-initialize) (comint-goto-process-mark))) inf-buf))) ;;;###autoload (defun R (&optional start-args) (interactive "P") ;; FIXME: Current ob-R expects current buffer set to process buffer (set-buffer (run-ess-r start-args))) (defun inferior-ess-r--init-callback (_proc _name) (ess-r-initialize)) (defvar ess-r--init-timeout 5 "Maximum time for R to become available on startup. If the timeout is reached, an error is thrown advising the user to run `ess-r-initialize' again.") (define-obsolete-function-alias 'R-initialize-on-start #'ess-r-initialize "ESS 19.04") (defun ess-r-initialize () "This function is run after the first R prompt. Executed in process buffer." (interactive) (condition-case err (progn (unless (ess-wait-for-process nil nil nil nil ess-r--init-timeout) (error "Process is busy")) (ess-command (ess-r--init-options-command)) (ess-r-load-ESSR)) (error (ess-r--init-error-handler err)) (quit (ess-r--init-error-handler))) (ess-process-put 'format-command-alist ess-r-format-command-alist) (ess-process-put 'bg-eval-disabled nil) (ess-execute-screen-options t) (ess-set-working-directory default-directory) (when ess-use-tracebug (ess-tracebug 1)) (add-hook 'ess-presend-filter-functions #'ess-R-scan-for-library-call nil 'local) ;; Wait before running user hook so they can call blocking commands (ess-wait-for-process) (run-hooks 'ess-r-post-run-hook) (ess-wait-for-process)) (defun ess-r--init-error-handler (&optional err) (ess-write-to-dribble-buffer "Failed to start ESSR\n") (when-let ((proc (and ess-local-process-name (get-process ess-local-process-name)))) (process-put proc 'bg-eval-disabled t)) (let ((msgs `("ESSR failed to start, please call `ess-r-initialize' to recover" ,@(when err (concat "Caused by error: " (error-message-string err)))))) (error (mapconcat 'identity msgs "\n")))) ;; FIXME: Should we stop setting `str.dendogram.last`? See: ;; https://emacs.stackexchange.com/questions/27673/ess-dendrograms-appearance-of-last-branch/27729#27729 ;; ;; FIXME: We don't use `ess-r-pager`? It's nil by default and ;; documented that this should not normally be set (defun ess-r--init-options-command () (let ((args (list (format "STERM = '%s'" ess-STERM) "str.dendrogram.last = '\\''" (format "editor = '%s'" ess-r-editor) (ess-r--update-opt-if-eq "pager" "file.path(R.home(), 'bin', 'pager')" (format "'%s'" inferior-ess-pager)) "show.error.locations = TRUE"))) (format "options(%s)\n" (mapconcat 'identity args ", ")))) (defun ess-r--update-opt-if-eq (opt old new) (let ((actual (format "getOption('%s')" opt))) (format "%s = if (identical(%s, %s)) %s else %s" opt actual old new actual))) (defun ess-r--skip-function () ;; Assumes the point is at function start (if (looking-at-p ess-r-set-function-start) (forward-list 1) ; get over the entire setXyz(...) (forward-list 1) ; get over arguments (if (looking-at-p "[ \t\n]*{") (forward-sexp 1) ;; move over {...} ;; {..}-less case (skip-chars-forward " \t\n") (goto-char (cadr (ess-continuations-bounds)))))) ;; `beginning-of-defun' protocol: ;; 1) assumes that defuns are at the top level (e.g. always moves to bol) (defun ess-r-beginning-of-defun (&optional arg) "Move to beginning a top level function. ARG is as in `beginning-of-defun'." (ess-r-beginning-of-function arg t)) ;; `end-of-defun' protocol: ;; 1) Uses beginning-of-defun-function with negative arg ;; 2) Assumes that beginning-of-defun-function with -1 arg finds current defun ;; when point is just in front of the function (defun ess-r-end-of-defun (&optional arg) "End of top level function. ARG is as in `end-of-defun'." (ess-r-end-of-function arg t)) (defun ess-r-beginning-of-function (&optional arg top-level) "Leave (and return) the point at the beginning of the current ESS function. When ARG is positive, search for beginning of function backward, otherwise forward. Value of ARG is currently ignored. Return the new position, or nil if no-match. If TOP-LEVEL is non-nil, search for top-level functions only." (setq arg (or arg 1)) (let ((start-point (point)) done) ;; In case we are at the start of a function, skip past new lines. (when (> arg 0) ;; Start search from a forward position in order to capture current ;; function start. But not when arg < 0; see end-of-defun protocol above. (forward-line 2)) (while (and (not done) (re-search-backward ess-r-function-pattern nil t arg)) (unless (ess-inside-string-or-comment-p) (setq done (if top-level (= (car (syntax-ppss (match-beginning 0))) 0) t)) (if (< arg 0) ;; move to match-end to avoid the infloop in re-search-backward (goto-char (if done (match-beginning 0) (match-end 0))) ;; Backward regexp match stops at the minimal match (e.g. partial ;; function name), so we need a bit more work here. (beginning-of-line) (re-search-forward ess-r-function-pattern) (goto-char (match-beginning 0)) (when (<= start-point (point)) (setq done nil))))) (if done (point) (goto-char start-point) nil))) (defun ess-r-end-of-function (&optional arg top-level) "Leave the point at the end of the current function. When ARG is positive, search for end of function forward, otherwise backward. Move to point and return point if search was successful, otherwise nil. If TOP-LEVEL is non-nil, search for top level functions only." (setq arg (or arg 1)) (let* ((start-pos (point)) (search-fn (lambda (lim) (let ((foundp nil)) (while (and (not foundp) (re-search-forward ess-r-function-pattern nil t)) (when (< arg 0) ;; re-search-backward is a forward search ;; internally, so we need to bol in order to avoid ;; the infloop (beginning-of-line)) (setq foundp (unless (ess-inside-string-or-comment-p) (if top-level (= 0 (car (save-excursion (syntax-ppss (match-beginning 0))))) (>= (point) lim))))) (if foundp (progn (goto-char (match-beginning 0)) (ess-r--skip-function)) (goto-char start-pos)))))) (ess-r-beginning-of-function 1 top-level) (if (< (point) start-pos) ;; Moved back. We were either inside a function or after a function. (progn (ess-r--skip-function) ;; For negative ARG we are done. (when (and (> arg 0) (<= (point) start-pos)) (funcall search-fn start-pos))) ;; No function before point; search forward on positive ARG. (when (> arg 0) (funcall search-fn start-pos))))) ;;;###autoload (define-derived-mode ess-r-mode ess-mode "ESS[R]" "Major mode for editing R source. See `ess-mode' for more help." :group 'ess-R (set-syntax-table ess-r-mode-syntax-table) (ess-setq-vars-local ess-r-customize-alist) (setq-local ess-font-lock-keywords 'ess-R-font-lock-keywords) (setq-local paragraph-start (concat "\\s-*$\\|" page-delimiter)) (setq-local paragraph-separate (concat "\\s-*$\\|" page-delimiter)) (setq-local paragraph-ignore-fill-prefix t) (setq-local indent-line-function #'ess-r-indent-line) (setq-local comment-indent-function #'ess-calculate-indent) (setq-local add-log-current-defun-header-regexp "^\\(.+\\)\\s-+<-[ \t\n]*function") (setq-local font-lock-syntactic-face-function #'ess-r-font-lock-syntactic-face-function) (setq-local syntax-propertize-function ess-r--syntax-propertize-function) (setq-local electric-layout-rules '((?{ . after))) ;; indentation (add-hook 'hack-local-variables-hook #'ess-set-style nil t) ;; eldoc (ess--setup-eldoc #'ess-r-eldoc-function) ;; auto-complete (ess--setup-auto-complete ess-r-ac-sources) ;; company (ess--setup-company ess-r-company-backends) (setq-local prettify-symbols-alist ess-r-prettify-symbols) (setq font-lock-defaults '(ess-build-font-lock-keywords nil nil ((?\. . "w") (?\_ . "w")))) (remove-hook 'completion-at-point-functions #'ess-filename-completion 'local) ;; should be first (add-hook 'completion-at-point-functions #'ess-r-object-completion nil 'local) (add-hook 'completion-at-point-functions #'ess-r-package-completion nil 'local) (add-hook 'completion-at-point-functions #'ess-filename-completion nil 'local) (add-hook 'xref-backend-functions #'ess-r-xref-backend nil 'local) (add-hook 'project-find-functions #'ess-r-project nil 'local) (if (fboundp 'ess-add-toolbar) (ess-add-toolbar)) ;; imenu is needed for `which-function' (setq imenu-generic-expression ess-imenu-S-generic-expression) (when ess-imenu-use-S (imenu-add-to-menubar "Imenu-R")) (setq-local beginning-of-defun-function #'ess-r-beginning-of-defun) (setq-local end-of-defun-function #'ess-r-end-of-defun) (ess-roxy-mode)) ;;;###autoload (defalias 'R-mode #'ess-r-mode) ;;;###autoload (defalias 'r-mode #'ess-r-mode) ;;;###autoload (add-to-list 'auto-mode-alist '("/R/.*\\.q\\'" . ess-r-mode)) ;;;###autoload (add-to-list 'auto-mode-alist '("\\.[rR]\\'" . ess-r-mode)) ;;;###autoload (add-to-list 'auto-mode-alist '("\\.[rR]profile\\'" . ess-r-mode)) ;;;###autoload (add-to-list 'auto-mode-alist '("NAMESPACE\\'" . ess-r-mode)) ;;;###autoload (add-to-list 'auto-mode-alist '("CITATION\\'" . ess-r-mode)) ;;;*;;; Project detection (defvar-local ess-r-project--info-cache nil "Current package info cache. See `ess-r-project-info' for its structure.") (defun ess-r-project (&optional dir) "Return the current project as an Emacs project instance. R project is a directory XYZ containing either .Rprofile, DESCRIPTION or XYZ.Rproj file. Return a list of the form (:name \"XYZ\" :root \"/path/to/project\"). If DIR is provided, the project is searched from that directory instead of `default-directory'." (let ((info (ess-r-project-info dir))) (when (car info) (cons 'ess-r-project (plist-get info :root))))) ;; FIXME: remove when emacs 27 is dropped (unless (eval-when-compile (get 'project-roots 'byte-obsolete-info)) (cl-defmethod project-roots ((project (head ess-r-project))) "Return the project root for ESS R projects." (list (cdr project)))) (cl-defmethod project-root ((project (head ess-r-project))) "Return the project root for ESS R projects." (cdr project)) (defun ess-r-project-info (&optional dir) "Get the description of the R project in directory DIR. Return an plist with the keys :name and :root. When not in a project return \\='(nil). This value is cached buffer-locally for efficiency reasons." (let ((do-cache (null dir))) (if (and do-cache ess-r-project--info-cache) ess-r-project--info-cache (setq dir (or dir (buffer-file-name) default-directory)) (let ((out (or (unless (file-remote-p dir) (let ((dir (locate-dominating-file dir (lambda (dir) (or (file-exists-p (expand-file-name ".Rprofile" dir)) (file-exists-p (expand-file-name "DESCRIPTION" dir)) (let ((nm (file-name-nondirectory (directory-file-name dir)))) (file-exists-p (expand-file-name (concat nm ".Rproj") dir)))))))) (when dir (let ((dir (directory-file-name dir))) (unless (member dir (list "~" (getenv "HOME"))) (list :name (file-name-nondirectory dir) :root (expand-file-name dir))))))) '()))) (when do-cache (setq ess-r-project--info-cache out)) out)))) ;;*;; Miscellaneous (defun ess-R-arch-2-bit (arch) "Translate R's architecture shortcuts/directory names to `bits'. ARCH \"32\" or \"64\" (for now)." (if (string= arch "i386") "32" ;; else: "64")) (defun ess-rterm-arch-version (long-path &optional give-cons) "Find a name for LONG-PATH, an absolute path to R on Windows. Returns either Name, a string, or a (Name . Path) cons, such as (\"R-2.12.1-64bit\" . \"C:/Program Files/R/R-2.12.1/bin/x64/Rterm.exe\") \"R-x.y.z/bin/Rterm.exe\" will return \"R-x.y.z\", for R-2.11.x and older. \"R-x.y.z/bin/i386/Rterm.exe\" return \"R-x.y.z-32bit\", for R-2.12.x and newer. \"R-x.y.z/bin/x64/Rterm.exe\" return \"R-x.y.z-64bit\", for R-2.12.x and newer." (let* ((dir (directory-file-name (file-name-directory long-path))) (dir2 (directory-file-name (file-name-directory dir))) (v-1up (file-name-nondirectory dir));; one level up (v-2up (file-name-nondirectory dir2));; two levels up; don't want "bin" ... (v-3up (file-name-nondirectory ;; three levels up; no "bin" for i386, x64 ... (directory-file-name (file-name-directory dir2)))) (val (if (string= v-2up "bin") (concat v-3up "-" (ess-R-arch-2-bit v-1up) "bit") ;; pre R-2.12.x, or when there's no extra arch-specific sub directory: v-2up))) (if give-cons (cons val long-path) val))) (defun ess-r-define-runners (&optional verbose) "Generate functions for starting other versions of R. See `ess-r-runner-prefixes' for strings that determine which functions are created. On MS Windows, this works using `ess-rterm-version-paths' instead. The functions will normally be placed on the menubar and stored as `ess-r-created-runners' upon ESS initialization." (when ess-r-runner-prefixes (let ((versions ;; Find which versions of R we want. Remove the pathname, leaving just ;; the name of the executable. (if ess-microsoft-p (mapcar (lambda (v) (car (ess-rterm-arch-version v 'give-cons))) ess-rterm-version-paths) (delete-dups (mapcar #'file-name-nondirectory (apply #'nconc (mapcar #'ess-find-exec-completions ess-r-runner-prefixes))))))) ;; Iterate over each string in VERSIONS, creating a new defun each time. (setq ess-r-created-runners versions) (if verbose (message "Recreated %d R versions known to ESS: %s" (length versions) versions)) (if ess-microsoft-p (cl-mapcar (lambda (v p) (ess-define-runner v "R" p)) versions ess-rterm-version-paths) (mapc (lambda (v) (ess-define-runner v "R")) versions)) ;; Add to menu (when ess-r-created-runners ;; new-menu will be a list of 3-vectors, of the form: ;; ["R-1.8.1" R-1.8.1 t] (let ((new-menu (mapcar (lambda(x) (vector x (intern x) t)) ess-r-created-runners))) (easy-menu-add-item ess-mode-menu '("Start Process") (cons "Other" new-menu)) (easy-menu-add-item inferior-ess-mode-menu '("Process") (cons "R processes" new-menu))))))) (defun ess-r-redefine-runners (&optional verbose) "Regenerate runners, i.e. `M-x R-*` possibilities. Call `fmakunbound' on all elements of `ess-r-created-runners', then define new runners." (interactive "P") (dolist (f ess-r-created-runners) (fmakunbound (intern f))) (setq ess-r-created-runners nil) (ess-r-define-runners verbose)) (defun ess-r-runners-reset (sym val) "Regenerate runners. Set SYM to VAL and call `ess-r-redefine-runners'." (set-default sym val) (ess-r-redefine-runners)) (define-obsolete-function-alias 'ess-r-versions-create #'ess-r-define-runners "ESS 18.10") (defvar ess-newest-R nil "Stores the newest version of R that has been found. Used as a cache, within `ess-find-newest-R'. Do not use this value directly, but instead call the function \\[ess-find-newest-R].") (defcustom ess-prefer-higher-bit t "Non-nil means prefer higher bit architectures of R. e.g. prefer 64 bit over 32 bit. This is currently used only by the code on Windows for finding the newest version of R." :group 'ess-R :type 'boolean) (defun ess-rterm-prefer-higher-bit () "Optionally remove 32bit Rterms from being candidate for `run-ess-r-newest'. Return the list of candidates for being `run-ess-r-newest'. Filtering is done iff `ess-prefer-higher-bit' is non-nil. This is used only by Windows when running `ess-find-newest-R'." (if ess-prefer-higher-bit ;; filter out 32 bit elements (let ((filtered (delq nil (mapcar (lambda (x) (unless (string-match "/i386/Rterm.exe" x) x)) ess-rterm-version-paths)))) (if (null filtered) ;; if none survived filtering, keep the original list ess-rterm-version-paths filtered)) ess-rterm-version-paths)) (defun run-ess-r-newest (&optional start-args) "Find the newest version of R available, and run it. Subsequent calls to `run-ess-r-newest' will run that version, rather than searching again for the newest version. Providing START-ARGS (interactively, with \\[universal-argument]) will prompt for command line arguments." (interactive "P") (unless ess-newest-R (message "Finding all versions of R on your system...") (setq ess-newest-R (ess-find-newest-date (mapcar #'ess-r-version-date (if ess-microsoft-p (ess-rterm-prefer-higher-bit) (add-to-list 'ess-r-created-runners inferior-ess-r-program)))))) (let ((inferior-ess-r-program ess-newest-R)) (run-ess-r start-args))) (defun R-newest (&optional start-args) (interactive "P") ;; FIXME: Current ob-R expects current buffer set to process buffer (set-buffer (run-ess-r-newest start-args))) ;; (ess-r-version-date "R-2.5.1") (ess-r-version-date "R-patched") ;; (ess-r-version-date "R-1.2.1") (ess-r-version-date "R-1.8.1") ;; Windows: ;; (ess-r-version-date "C:/Program Files (x86)/R/R-2.11.1/bin/Rterm.exe") ;; Note that for R-devel, ver-string is something like ;; R version 2.6.0 Under development (unstable) (2007-07-14 r42234) ;; Antique examples are 'R 1.0.1 (April 14, 2000)' or 'R 1.5.1 (2002-06-17).' (defun ess-r-version-date (rver) "Return the date of the version of R named RVER. The date is returned as a date string. If the version of R could not be found from the output of the RVER program, \"-1\" is returned." (let ((date "-1") (ver-string (shell-command-to-string ;; here, MS Windows (shell-command) needs a short name: (concat (if (and ess-microsoft-p ;; silence byte compiler warns about w32-fns (fboundp 'w32-short-file-name)) (w32-short-file-name rver) rver) " --version")))) (when (string-match "R \\(version \\)?[1-9][^\n]+ (\\(2[0-9-]+\\)\\( r[0-9]+\\)?" ver-string) (setq date (match-string 2 ver-string))) (cons date rver))) (defun ess-current-R-version () "Get the version of R currently running in the ESS buffer as a string." (ess-make-buffer-current) (car (ess-get-words-from-vector (format "base::as.character(%s)\n" (ess-r--format-call ".ess.Rversion"))))) (defun ess-current-R-at-least (version) "Is the version of R (in the ESS buffer) at least (\">=\") VERSION ? Examples: (ess-current-R-at-least '2.7.0) or (ess-current-R-at-least \"2.5.1\")" (ess-make-buffer-current) (string= "TRUE" (car (ess-get-words-from-vector (format "base::as.character(%s >= \"%s\")\n" (ess-r--format-call ".ess.Rversion") version))))) (defun ess-find-newest-date (rvers) "Find the newest version of R given in the a-list RVERS. Each element of RVERS is a dotted pair (date . R-version), where date is given as e.g.\"2007-11-30\" so that we can compare dates as strings. If a date is listed as \"-1\", that version of R could not be found. If the value returned is nil, no valid newest version of R could be found." (let (new-r this-r (new-time "0")) (while rvers (setq this-r (car rvers) rvers (cdr rvers)) (when (string< new-time (car this-r)) (setq new-time (car this-r) new-r (cdr this-r)))) new-r)) (defun ess-find-rterm (&optional ess-R-root-dir bin-Rterm-exe) "Find the full path of all occurrences of Rterm.exe under the ESS-R-ROOT-DIR. If ESS-R-ROOT-DIR is nil, construct it by looking for an occurrence of Rterm.exe in the `exec-path'. If there are no occurrences of Rterm.exe in the `exec-path', then use `ess-program-files' (which evaluates to something like \"c:/progra~1/R/\" in English locales) which is the default location for the R distribution. If BIN-RTERM-EXE is nil, then use \"bin/Rterm.exe\"." (if (not ess-R-root-dir) (let ((Rpath (executable-find "Rterm"))) (setq ess-R-root-dir (expand-file-name (if Rpath (concat (file-name-directory Rpath) "../../") (concat ess-program-files "/R/")))) (ess-write-to-dribble-buffer (format "(ess-find-rterm): ess-R-root-dir = '%s'\n" ess-R-root-dir)))) (if (not bin-Rterm-exe) (setq bin-Rterm-exe "bin/Rterm.exe")) (when (file-directory-p ess-R-root-dir) ; otherwise file-name-all-.. errors (setq ess-R-root-dir (replace-regexp-in-string "[\\]" "/" ess-R-root-dir)) (let ((R-ver (ess-drop-non-directories (ess-flatten-list (mapcar (lambda (r-prefix) (file-name-all-completions r-prefix ess-R-root-dir)) (append '("rw") ess-r-runner-prefixes)))))) (mapcar (lambda (dir) (let ((R-path (concat ess-R-root-dir (replace-regexp-in-string "[\\]" "/" dir) bin-Rterm-exe))) (if (file-exists-p R-path) R-path))) R-ver)))) ;;;###autoload (define-derived-mode ess-r-transcript-mode ess-transcript-mode "ESS R Transcript" "A Major mode for R transcript files." :syntax-table ess-r-mode-syntax-table :group 'ess (ess-setq-vars-local ess-r-customize-alist) (setq-local comint-prompt-regexp inferior-S-prompt) (setq-local ess-font-lock-keywords 'ess-R-font-lock-keywords) (setq-local paragraph-start (concat "\\s-*$\\|" page-delimiter)) (setq-local paragraph-separate (concat "\\s-*$\\|" page-delimiter)) (setq-local paragraph-ignore-fill-prefix t) (setq-local indent-line-function #'ess-r-indent-line) (setq-local add-log-current-defun-header-regexp "^\\(.+\\)\\s-+<-[ \t\n]*function") (setq-local font-lock-syntactic-face-function #'ess-r-font-lock-syntactic-face-function) (setq-local prettify-symbols-alist ess-r-prettify-symbols) (setq font-lock-defaults '(ess-build-font-lock-keywords nil nil ((?\. . "w") (?\_ . "w") (?' . "."))))) (defalias 'r-transcript-mode #'ess-r-transcript-mode) ;;;###autoload (add-to-list 'auto-mode-alist '("\\.[Rr]out\\'" . ess-r-transcript-mode)) ;;;###autoload (add-to-list 'interpreter-mode-alist '("Rscript" . ess-r-mode)) ;;;###autoload (add-to-list 'interpreter-mode-alist '("r" . ess-r-mode)) (defun ess-r-fix-T-F (&optional from quietly) "Change T/F into TRUE and FALSE cautiously. Do not change in comments and strings. Start at FROM, which defaults to point, and change to end of buffer. When QUIETLY, do not issue messages." (interactive "d\nP"); point and prefix (C-u) (save-excursion (goto-char from) (ess-rep-regexp "\\(\\([][=,()]\\|<-\\) *\\)T\\>" "\\1TRUE" 'fixcase nil (not quietly)) (goto-char from) (ess-rep-regexp "\\(\\([][=,()]\\|<-\\) *\\)F\\>" "\\1FALSE" 'fixcase nil (not quietly)))) (define-obsolete-function-alias 'R-fix-T-F #'ess-r-fix-T-F "ESS 18.10") (defvar ess--packages-cache nil "Cache var to store package names. Used by `ess-r-install-library'.") (defvar ess--CRAN-mirror nil "CRAN mirror name cache.") (cl-defmethod ess-install-library--override (update package &context (ess-dialect "R")) "Prompt and install R PACKAGE. With argument UPDATE, update cached packages list." (inferior-ess-r-force) (when (equal "@CRAN@" (car (ess-get-words-from-vector "getOption('repos')[['CRAN']]\n"))) (ess-set-CRAN-mirror ess--CRAN-mirror) (ess-wait-for-process (get-process ess-current-process-name)) (unless package (setq update t))) (when (or update (not ess--packages-cache)) (message "Fetching R packages ... ") (setq ess--packages-cache (ess-get-words-from-vector--foreground "print(rownames(available.packages()), max=1e6)\n"))) (let* ((ess-eval-visibly-p t) (package (or package (ess-completing-read "Package to install" ess--packages-cache)))) (process-send-string (get-process ess-current-process-name) (format "install.packages('%s')\n" package)) (display-buffer (buffer-name (ess-get-process-buffer))))) (defun ess-setRepositories () "Call setRepositories()." (interactive) (if (not (string-match "^R" ess-dialect)) (message "Sorry, not available for %s" ess-dialect) (ess-eval-linewise "setRepositories(FALSE)\n"))) (defun ess-set-CRAN-mirror (&optional mirror) "Set cran MIRROR." (interactive) (let ((mirror-cmd "local({r <- getOption('repos'); r['CRAN'] <- '%s';options(repos=r)})\n")) (if mirror (ess-command (format mirror-cmd mirror)) (when-let ((M1 (ess-get-words-from-vector "local({out <- getCRANmirrors(local.only=TRUE); print(paste(out$Name,'[',out$URL,']', sep=''))})\n")) (mirror (ess-completing-read "Choose CRAN mirror" M1 nil t)) (url (car (cl-member mirror M1 :test #'string=)))) (setq ess--CRAN-mirror (progn (string-match "\\(.*\\)\\[\\(.*\\)\\]$" url) (match-string 2 url))) (ess-command (format mirror-cmd ess--CRAN-mirror))))) (message "CRAN mirror: %s" (car (ess-get-words-from-vector "getOption('repos')[['CRAN']]\n")))) (define-obsolete-function-alias 'ess-setCRANMiror #'ess-set-CRAN-mirror "ESS 18.10") (defun ess-r-check-install-package (pkg) "Check if package PKG is installed and offer to install if not." (unless (ess-boolean-command (format "print(requireNamespace('%s', quietly = TRUE))\n" pkg)) (if (y-or-n-p (format "Package '%s' is not installed. Install? " pkg)) (ess-eval-linewise (format "install.packages('%s')\n" pkg)) (signal 'quit nil)))) (define-obsolete-function-alias 'ess-r-sos #'ess-help-web-search "ESS 19.04") (cl-defmethod ess--help-web-search-override (cmd &context (ess-dialect "R")) (ess-r-check-install-package "sos") (ess-eval-linewise (format "sos::findFn(\"%s\", maxPages=10)" cmd))) (defun ess-R-scan-for-library-call (string) "Detect `library/require' call in STRING and update tracking vars. Placed into `ess-presend-filter-functions' for R dialects." (when (string-match-p "\\blibrary(\\|\\brequire(" string) (ess--mark-search-list-as-changed)) string) (cl-defmethod ess-installed-packages (&context (ess-dialect "R")) ;;; FIXME? .packages() does not cache; installed.packages() does but is slower first time (ess-get-words-from-vector--foreground "print(.packages(TRUE), max=1e6)\n")) (cl-defmethod ess-load-library--override (pack &context (ess-dialect "R")) "Load an R package." (ess-eval-linewise (format "library('%s')\n" pack))) (define-obsolete-function-alias 'ess-library #'ess-load-library "ESS[12.09-1]") ;;; smart-comma was a bad idea (eval-after-load "eldoc" '(eldoc-add-command "ess-smart-comma")) ;;*;; Interaction with R ;;;*;;; Evaluation (defun ess-r-arg (param value &optional wrap) (let ((value (if wrap (concat "'" value "'") value))) (concat ", " param " = " value))) (defun ess-r-build-args (visibly output namespace) (let ((visibly (ess-r-arg "visibly" (if visibly "TRUE" "FALSE"))) (output (ess-r-arg "output" (if output "TRUE" "FALSE"))) (pkg (when namespace (ess-r-arg "package" namespace t))) (verbose (when (and namespace ess-r-namespaced-load-verbose) (ess-r-arg "verbose" "TRUE")))) (concat visibly output pkg verbose))) (defun ess-r--format-call (cmd &rest objects) "Prefix an ESSR command with a namespace qualifier. CMD is formatted with OBJECTS using `format'." (concat "base::as.environment('ESSR')$" (apply #'format cmd objects))) (cl-defmethod ess-build-eval-command--override (string &context (ess-dialect "R") &optional visibly output file &rest args) "R method to build eval command." (let* ((namespace (caar args)) (namespace (unless ess-debug-minor-mode (or namespace (ess-r-get-evaluation-env)))) (cmd (ess-r--format-call (if namespace ".ess.ns_eval" ".ess.eval"))) (file (when file (ess-r-arg "file" file t))) (rargs (ess-r-build-args visibly output namespace))) (concat cmd "(\"" string "\"" rargs file ")\n"))) (cl-defmethod ess-build-load-command (string &context (ess-dialect "R") &optional visibly output file &rest _args) (let* ((namespace (or file (ess-r-get-evaluation-env))) (cmd (ess-r--format-call (if namespace ".ess.ns_source" ".ess.source"))) (rargs (ess-r-build-args visibly output namespace))) (concat cmd "('" string "'" rargs ")\n"))) (defun ess-r-build-eval-message (message) (let ((env (cond (ess-debug-minor-mode (substring-no-properties ess-debug-indicator 1)) ((ess-r-get-evaluation-env))))) (if env (format "[%s] %s" env message) message))) (defvar-local ess-r-evaluation-env nil "Environment into which code should be evaluated. When this variable is nil, code is evaluated in the current environment. Currently only packages can be set as evaluation environments. Use `ess-r-set-evaluation-env' to set this variable.") (defun ess-r-get-evaluation-env () "Get current evaluation env." ess-r-evaluation-env) (defun ess-r-set-evaluation-env (&optional arg) "Select a package namespace for evaluation of R code. Call interactively with a prefix argument to disable evaluation in a namespace. When calling from a function, ARG can be a string giving the package to select, any other non-nil value to disable, or nil to prompt for a package. If `ess-r-prompt-for-attached-pkgs-only' is non-nil, prompt only for attached packages." (interactive "P") (let ((env (cond ((stringp arg) arg) ((null arg) (ess-r--select-package-name)) (t "*none*")))) (if (equal env "*none*") (let ((cur-env (ess-r-get-evaluation-env))) (setq ess-r-evaluation-env nil) (delq 'ess-r--evaluation-env-mode-line ess--local-mode-line-process-indicator) (message (format "Evaluation in %s disabled" (propertize cur-env 'face font-lock-function-name-face)))) (setq ess-r-evaluation-env env) (add-to-list 'ess--local-mode-line-process-indicator 'ess-r--evaluation-env-mode-line t) (message (format "Evaluating in %s" (propertize env 'face font-lock-function-name-face)))) (force-mode-line-update))) (defvar-local ess-r--evaluation-env-mode-line '(:eval (let ((env (ess-r-get-evaluation-env))) (if env (format " %s" (propertize (if (equal env (ess-r-package-name)) "pkg" env) 'face 'mode-line-emphasis)) "")))) (put 'ess-r--evaluation-env-mode-line 'risky-local-variable t) (defvar ess-r-namespaced-load-only-existing t "Whether to load only objects already existing in a namespace.") (cl-defmethod ess-load-file--override (file &context (ess-dialect "R")) (cond ;; Namespaced evaluation ((ess-r-get-evaluation-env) (ess-r-load-file-namespaced file)) ;; Evaluation into current env via .ess.source() (t (let ((command (ess-build-load-command file nil t))) (ess-send-string (ess-get-process) command))))) (defun ess-r-load-file-namespaced (&optional file) "Load FILE into a package namespace. This prompts for a package when no package is currently selected (see `ess-r-set-evaluation-env')." (ess-force-buffer-current "R process to use: ") (let* ((pkg-name (ess-r-get-evaluation-env)) (command (ess-build-load-command file nil t pkg-name))) (ess-send-string (ess-get-process) command))) (cl-defmethod ess-send-region--override (process start end visibly message type &context (ess-dialect "R")) (cond ;; Namespaced evaluation ((ess-r-get-evaluation-env) (ess-r-send-region-namespaced process start end visibly message)) ;; Evaluation into current env (t (ess-send-string process (buffer-substring start end) visibly message type)))) (defun ess-r-send-region-namespaced (proc start end &optional visibly message) "Ask for for the package and devSource region into it." (or (ess-r-get-evaluation-env) (ess-r-set-evaluation-env)) (message (ess-r-build-eval-message (or message "Eval region"))) (ess-send-string proc (buffer-substring start end) visibly message)) ;;;*;;; Help (cl-defmethod ess-build-help-command (object &context (ess-dialect "R")) (let ((info (ess-r--split-namespace object))) (if info (ess-r-help--build-help-command--qualified (car info) (cdr info)) (ess-r-help--build-help-command--unqualified object)))) (defun ess-r--split-namespace (sym) (when (string-match "^[[:alnum:].]+::" sym) (let ((pkg (substring-no-properties sym (match-beginning 0) (- (match-end 0) 2))) (obj (substring-no-properties sym (match-end 0)))) (cons pkg obj)))) (defvar-local ess-r-help--local-object nil) (defvar-local ess-r-help--local-package nil) (put 'ess-r-help--local-object 'permanent-local t) (put 'ess-r-help--local-package 'permanent-local t) (defun ess-r-help--build-help-command--qualified (pkg obj) (setq ess-r-help--local-package pkg) (setq ess-r-help--local-object obj) (let ((obj-arg (concat "'" obj "'")) (pkg-arg (ess-r-arg "package" pkg t))) (ess-r--format-call ".ess.help(%s%s)\n" obj-arg pkg-arg))) (defun ess-r-help--build-help-command--unqualified (obj) (if (eq ess-help-type 'index) ;; We are in index page, qualify with namespace (ess-r-help--build-help-command--qualified ess-help-object obj) (let ((pkg (ess-r-help--find-package obj))) (unless pkg (error "Can't find documentation for `%s'" obj)) (ess-r-help--build-help-command--qualified pkg obj)))) (defun ess-r-help--find-package (object) "Find package where to find OBJECT. If there are multiple packages attached to the search path, the user is prompted for a package location. If OBJECT is not documented, returns nil." (let* ((paths (ess-get-words-from-vector (format "as.character(utils::help('%s'))\n" object))) (paths (if (> (length paths) 1) (cl-delete-if (lambda (x) (string-match-p "reexports$" x)) paths) paths))) (cond ((not paths) nil) ((and (> (length paths) 1) (not noninteractive)) (let ((path (ess-completing-read "Choose location" paths nil t))) (ess-r-help--get-pkg-from-help-path path))) (t (ess-r-help--get-pkg-from-help-path (car paths)))))) (defun ess-r-help--get-pkg-from-help-path (path) (file-name-nondirectory (directory-file-name (file-name-directory (directory-file-name (file-name-directory path)))))) (defconst inferior-ess-r--input-help (format "^ *help *(%s)" ess-help-arg-regexp)) (defconst inferior-ess-r--input-?-help-regexp "^ *\\(?:\\(?1:[a-zA-Z ]*?\\?\\{1,2\\}\\) *\\(?2:.+\\)\\)") (defconst inferior-ess-r--page-regexp (format "^ *page *(%s)" ess-help-arg-regexp)) (defun ess-help-r--process-help-input (proc string) (let ((help-match (and (string-match inferior-ess-r--input-help string) (match-string 2 string))) (help-?-match (and (string-match inferior-ess-r--input-?-help-regexp string) string)) (page-match (and (string-match inferior-ess-r--page-regexp string) (match-string 2 string)))) (when (or help-match help-?-match page-match) (cond (help-match (ess-display-help-on-object help-match) (process-send-string proc "\n")) (help-?-match (ess-help-r--display-help-? string help-?-match) (process-send-string proc "\n")) (page-match (switch-to-buffer-other-window (ess-command (concat page-match "\n") (get-buffer-create (concat page-match ".rt")))) (ess-r-transcript-mode) (process-send-string proc "\n"))) t))) (defun ess-help-r--display-help-? (string help-?-match) (cond ((string-match "\\?\\?\\(.+\\)" help-?-match) (ess--display-indexed-help-page (concat help-?-match "\n") "^\\([^ \t\n]+::[^ \t\n]+\\)[ \t\n]+" (format "*ess-apropos[%s](%s)*" ess-current-process-name (match-string 1 help-?-match)) 'apropos)) ((string-match "^ *\\? *\\([^ \t]+\\)$" help-?-match) (ess-display-help-on-object (match-string 1 help-?-match))) ;; Anything else we send to process almost unchanged (t (let ((help-?-match (and (string-match inferior-ess-r--input-?-help-regexp string) (format "%s%s" (match-string 1 string) (ess-help-r--sanitize-topic (match-string 2 string)))))) (ess-display-help-on-object help-?-match "%s\n"))))) (defun ess-help-r--sanitize-topic (string) "Enclose help topic STRING into `` to avoid ?while ?if etc hangs." (if (string-match "\\([^:]*:+\\)\\(.*\\)$" string) ; treat foo::bar correctly (format "%s`%s`" (match-string 1 string) (match-string 2 string)) (format "`%s`" string))) ;;;*;;; Utils for inferior R process (defun inferior-ess-r-input-sender (proc string) (save-current-buffer (or (ess-help-r--process-help-input proc string) (inferior-ess-input-sender proc string)))) (defun ess-r-load-ESSR () "Load ESSR functionality into ESSR environment. On remotes, when `ess-r-fetch-ESSR-on-remotes' is non-nil we fetch ESSR environment from github to the remote machine. Otherwise (the default) we source ESSR files into the remote process." (interactive) ;; `.ess.command()` is not defined until ESSR is loaded so disable ;; it temporarily. Would be helpful to implement an `inferior-ess-let' ;; macro . (cond ((file-remote-p (ess-get-process-variable 'default-directory)) (if (eq ess-r-fetch-ESSR-on-remotes t) (or (ess-r--fetch-ESSR-remote) (ess-r--load-ESSR-remote)) (ess-r--load-ESSR-remote))) ((and (bound-and-true-p ess-remote)) ;; NB: With ess-remote we send by chunks because sending large sources is ;; fragile (if ess-r-fetch-ESSR-on-remotes (or (ess-r--fetch-ESSR-remote) (ess-r--load-ESSR-remote t)) (ess-r--load-ESSR-remote t))) (t (ess-r--load-ESSR-local)))) (defun ess-r--load-ESSR-local () "Load ESSR into a local process. Source the etc/ESSR/.load.R file into the R process. The .ess.ESSR.load function sources all of the contents of the etc/ESSR/R directory into the ESSR environment and attaches the environment to the search path." (let* ((src-dir (expand-file-name "ESSR/R" ess-etc-directory)) (buf (ess-command (ess-r--load-ESSR-command src-dir)))) (with-current-buffer buf (let ((msg (buffer-string))) (when (> (length msg) 1) (message (format "Messages while loading ESSR: %s" msg))))))) (defun ess-r--load-ESSR-command (src-dir) (format "base::tryCatch( base::local({ base::source('%s/.load.R', local=TRUE) #define load.ESSR .ess.ESSR.load('%s') }), error = function(cnd) { msg <- paste0('ESSR::ERROR \"', conditionMessage(cnd), '\"') writeLines(msg) } )\n" src-dir src-dir)) (defun ess-r--load-ESSR-remote (&optional chunked) "Load ESSR into a remote process through the process connection. Send the contents of the etc/ESSR/R directory to the remote process through the process connection file by file. Then, collect all the objects into an ESSR environment and attach to the search path. If CHUNKED is non-nil, split each file by separators and send chunk by chunk." (ess-command (format ".ess.ESSRversion <<- '%s'\n" essr-version)) (with-temp-message "Loading ESSR into remote ..." (let ((src-dir (expand-file-name "ESSR/R" ess-etc-directory))) (dolist (file (directory-files src-dir t "\\.R\\'")) (ess--inject-code-from-file file chunked)) (ess-command ".ess.collect.ESSR.objects()\n")))) (defun ess-r--fetch-ESSR-remote () "Load ESSR into a remote process through a GitHub download. Downloads a file with a serialized version of the R ESSR environment from GitHub and attaches it to the search path. If the file already exists on disk from a previous download then the download step is omitted. This function returns t if the ESSR load is successful, and nil otherwise." (let ((loader (ess-file-content (expand-file-name "ESSR/LOADREMOTE" ess-etc-directory))) (essr (or essr-version ;; FIXME: Hack: on MELPA essr-version is not set (lm-with-file (expand-file-name "ess.el" ess-lisp-directory) (lm-header "ESSR-Version")) (error "`essr-version' could not be automatically inferred from ess.el file")))) (or (with-temp-message "Fetching and loading ESSR into the remote ..." (ess-boolean-command (format loader essr))) (let ((errmsg (with-current-buffer " *ess-command-output*" (buffer-string)))) (message (format "Couldn't load or download ESSR.rds on the remote.\n Error: %s\n Injecting local copy of ESSR." errmsg)) nil)))) (cl-defmethod ess-quit--override (arg &context (ess-dialect "R")) "With ARG, do not offer to save the workspace." (let ((cmd (format "base::q('%s')\n" (if arg "no" "default"))) (sprocess (ess-get-process ess-current-process-name))) (when (not sprocess) (error "No ESS process running")) (ess-cleanup) (ess-send-string sprocess cmd))) (defcustom inferior-ess-r-reload-hook nil "Hook run when reloading the R inferior buffer." :type 'hook :group 'ess-R) (cl-defmethod inferior-ess-reload--override (start-name start-args &context (ess-dialect "R")) "Call `run-ess-r' with START-ARGS. Then run `inferior-ess-r-reload-hook'." (let ((inferior-ess-r-program start-name)) (run-ess-r start-args)) (run-hooks 'inferior-ess-r-reload-hook)) (defun inferior-ess-r-force (&optional prompt force no-autostart ask-if-1) (setq-local ess-dialect "R") (ess-force-buffer-current prompt force no-autostart ask-if-1)) ;;*;; Editing Tools ;;;*;;; Indentation Engine ;; Written by Lionel Henry in mid 2015 (defun ess-r-indent-line () "Indent current line as ESS R code. Return the amount the indentation changed by." (when-let ((indent (ess-calculate-indent))) (let ((case-fold-search nil) (pos (- (point-max) (point))) beg shift-amt) (beginning-of-line) (setq beg (point)) (skip-chars-forward " \t") (setq shift-amt (- indent (current-column))) (if (zerop shift-amt) (if (> (- (point-max) pos) (point)) (goto-char (- (point-max) pos))) (delete-region beg (point)) (indent-to indent) ;; If initial point was within line's indentation, ;; position after the indentation. ;; Else stay at same point in text. (when (> (- (point-max) pos) (point)) (goto-char (- (point-max) pos)))) shift-amt))) (defun ess-r-indent-exp () (save-excursion (when current-prefix-arg (ess-climb-to-top-level)) (let* ((bounds (ess-continuations-bounds)) (end (cadr bounds)) (beg (if current-prefix-arg (car bounds) (forward-line) (point)))) (indent-region beg end)))) (defun ess-indent-call (&optional start) (save-excursion (when (ess-escape-calls) (setq start (or start (point))) (skip-chars-forward "^[(") (forward-char) (ess-up-list) (indent-region start (point))))) (defun ess-offset (offset) (setq offset (symbol-value (intern (concat "ess-offset-" (symbol-name offset))))) (when (and (not (eq offset nil)) (listp offset) (or (numberp (cadr offset)) (eq (cadr offset) t) (error "Malformed offset"))) (setq offset (cadr offset))) (cond ((numberp offset) offset) ((null offset) 0) (t ess-indent-offset))) (defun ess-offset-type (offset) (setq offset (symbol-value (intern (concat "ess-offset-" (symbol-name offset))))) (if (listp offset) (car offset) offset)) (defun ess-overridden-blocks () (append (when (memq 'fun-decl ess-align-blocks) (list (car ess-prefixed-block-patterns))) (when (memq 'control-flow ess-align-blocks) (append (cdr ess-prefixed-block-patterns) '("}?[ \t]*else"))))) (defun ess-calculate-indent () "Return appropriate indentation for current line as ESS code. In usual case returns an integer: the column to indent to. Returns nil if line starts inside a string, t if in a comment." (save-excursion (beginning-of-line) (let* ((indent-point (point)) (state (syntax-ppss)) (containing-sexp (cadr state)) (prev-containing-sexp (car (last (butlast (nth 9 state)))))) (back-to-indentation) (cond ;; Strings ((ess-inside-string-p) (current-indentation)) ;; Comments ((ess-calculate-indent--comments)) ;; Indentation of commas ((looking-at ",") (ess-calculate-indent--comma)) ;; Arguments: Closing ((ess-call-closing-p) (ess-calculate-indent--call-closing-delim)) ;; Block: Contents (easy cases) ((ess-calculate-indent--block-relatively)) ;; Block: Prefixed block ((ess-calculate-indent--prefixed-block-curly)) ;; Continuations ((ess-calculate-indent--continued)) ;; Block: Overridden contents ((ess-calculate-indent--aligned-block)) ;; Block: Opening ((ess-block-opening-p) (ess-calculate-indent--block-opening)) ;; Bare line ((and (null containing-sexp) (not (ess-unbraced-block-p))) 0) ;; Block: Closing ((ess-block-closing-p) (ess-calculate-indent--block 0)) ;; Block: Contents ((ess-block-p) (ess-calculate-indent--block)) ;; Arguments: Nested calls override ((ess-calculate-indent--nested-calls)) ;; Arguments: Contents (t (ess-calculate-indent--args)))))) (defun ess-calculate-indent--comments () (when ess-indent-with-fancy-comments (cond ;; ### or #! ((or (looking-at "###") (and (looking-at "#!") (= 1 (line-number-at-pos)))) 0) ;; Single # comment ((looking-at "#[^#']") comment-column)))) (defun ess-calculate-indent--comma () (when (ess-inside-call-p) (let ((indent (save-excursion (ess-calculate-indent--args))) (unindent (progn (skip-chars-forward " \t") ;; return number of skipped chars (skip-chars-forward ", \t")))) (- indent unindent)))) (defun ess-calculate-indent--call-closing-delim () (cond ((save-excursion (ess-skip-blanks-backward t) (eq (char-before) ?,)) (ess-calculate-indent--args nil)) ((save-excursion (and (ess-ahead-operator-p) (or (ess-ahead-definition-op-p) (not ess-align-continuations-in-calls)))) (ess-calculate-indent--continued)) (t (ess-calculate-indent--args 0)))) (defun ess-calculate-indent--block-opening () (cond ;; Block is an argument in a function call ((when containing-sexp (ess-at-containing-sexp (ess-behind-call-opening-p "[[(]"))) (ess-calculate-indent--block 0)) ;; Top-level block ((null containing-sexp) 0) ;; Block is embedded in another block ((ess-at-containing-sexp (+ (current-indentation) (ess-offset 'block)))))) (defun ess-calculate-indent--aligned-block () ;; Check for `else' opening (if (and (memq 'control-flow ess-align-blocks) (looking-at "else\\b") (ess-climb-if-else)) (progn (when (looking-at "else\\b") (ess-skip-curly-backward)) (current-column)) ;; Check for braced and unbraced blocks (ess-save-excursion-when-nil (let ((offset (if (looking-at "[{})]") 0 (ess-offset 'block)))) (when (and (cond ;; Unbraced blocks ((ess-climb-block-prefix)) ;; Braced blocks (containing-sexp (when (ess-at-containing-sexp (looking-at "{")) (ess-escape-prefixed-block)))) (cl-some #'looking-at (ess-overridden-blocks))) (+ (current-column) offset)))))) (defun ess-calculate-indent--block-relatively () (ess-save-excursion-when-nil (let ((offset (if (looking-at "[})]") 0 (ess-offset 'block))) (start-line (line-number-at-pos))) (cond ;; Braceless block continuations: only when not in a call ((ess-save-excursion-when-nil (and (not (looking-at "{")) (ess-goto-char (ess-unbraced-block-p)) (not (looking-at "function\\b")) (or (null containing-sexp) (ess-at-containing-sexp (not (looking-at "(")))))) (ess-maybe-climb-broken-else 'same-line) (ess-skip-curly-backward) (+ (current-column) (ess-offset 'block))) ;; Don't indent relatively other continuations ((ess-ahead-continuation-p) nil) ;; If a block already contains an indented line, we can indent ;; relatively from that first line ((ess-save-excursion-when-nil (and (not (looking-at "}")) containing-sexp (goto-char containing-sexp) (looking-at "{") (progn (forward-line) (back-to-indentation) (/= (line-number-at-pos) start-line)) (not (looking-at "[ \t]*\\(#\\|$\\)")) (save-excursion (or (ess-jump-expression) (ess-jump-continuations)) (< (line-number-at-pos) start-line)))) (current-column)) ;; If a block is not part of a call, we can indent relatively ;; from the opening {. First check that enclosing { is first ;; thing on line ((and containing-sexp (not (ess-unbraced-block-p)) (goto-char containing-sexp) (ess-block-opening-p) (equal (point) (save-excursion (back-to-indentation) (point)))) (+ (current-column) offset)))))) (defun ess-arg-block-p () (unless (or (null containing-sexp) ;; Unbraced blocks in a { block are not arg blocks (and (ess-unbraced-block-p) (ess-at-containing-sexp (looking-at "{")))) (cond ;; Unbraced body ((ess-at-indent-point (and (ess-unbraced-block-p) (goto-char containing-sexp) (ess-behind-call-opening-p "[[(]"))) 'body) ;; Indentation of opening brace as argument ((ess-at-containing-sexp (ess-behind-call-opening-p "[[(]")) 'opening) ;; Indentation of body or closing brace as argument ((ess-at-containing-sexp (and (or (looking-at "{") (ess-behind-block-paren-p)) prev-containing-sexp (goto-char prev-containing-sexp) (ess-behind-call-opening-p "[[(]"))) 'body)))) (defun ess-calculate-indent--block (&optional offset) (let ((arg-block (ess-arg-block-p))) (cond (arg-block (ess-calculate-indent--arg-block offset arg-block)) (t ;; Block is not part of an arguments list. Climb over any ;; block opening (function declaration, etc) to indent from ;; starting indentation. (or (ess-climb-block-prefix) (and (goto-char containing-sexp) (ess-climb-block-prefix))) (+ (current-indentation) (or offset (ess-offset 'block))))))) (defun ess-calculate-indent--arg-block (offset arg-block) (let* ((block-type (cond ((or (ess-at-containing-sexp (and (eq arg-block 'body) (ess-climb-block-prefix "function"))) (ess-at-indent-point (and (eq arg-block 'opening) (ess-backward-sexp 2) (looking-at "function\\b")))) 'fun-decl) ((ess-at-indent-point (ess-unbraced-block-p)) 'unbraced) ((ess-at-containing-sexp (not (ess-ahead-attached-name-p))) 'bare-block) (t))) (call-pos (if (and (not (eq block-type 'unbraced)) (not (eq arg-block 'opening))) (goto-char prev-containing-sexp) (prog1 containing-sexp (goto-char indent-point))))) (ess-calculate-indent--args offset (ess-offset-type 'block) call-pos indent-point block-type))) ;; This function is currently the speed bottleneck of the indentation ;; engine. This is due to the need to call (ess-maximum-args-indent) ;; to check if some previous arguments have been pushed off from their ;; natural indentation: we need to check the whole call. This is very ;; inefficient especially when indenting a region containing a large ;; function call (e.g. some dplyr's data cleaning code). Should be ;; solved by implementing a cache as in (syntax-ppss), though it's ;; probably not worth the work. (defun ess-calculate-indent--args (&optional offset type call-pos to block) (let* ((call-pos (or call-pos containing-sexp)) (max-col (prog1 (unless (eq type 'prev-line) (ess-maximum-args-indent call-pos to)) (goto-char call-pos))) (override (and ess-align-arguments-in-calls (save-excursion (ess-climb-object) (cl-some #'looking-at ess-align-arguments-in-calls)))) (type-sym (cond (block 'block) ((looking-at "[[:blank:]]*[([][[:blank:]]*\\($\\|#\\)") 'arguments-newline) (t 'arguments))) (type (or type (and override 'open-delim) (ess-offset-type type-sym))) (offset (or offset (and (not block) (eq type 'open-delim) 0) (ess-offset type-sym))) (indent (cond ;; Indent from opening delimiter ((eq type 'open-delim) (ess-calculate-indent--args-open-delim)) ;; Indent from attached name ((eq type 'prev-call) (ess-calculate-indent--args-prev-call block)) ;; Indent from previous line indentation ((eq type 'prev-line) (let ((out (ess-calculate-indent--args-prev-line type block offset))) (setq offset (pop out)) (pop out))) (t (error "Malformed offset"))))) (if max-col (ess-adjust-argument-indent indent offset max-col block) (+ indent offset)))) (defun ess-calculate-indent--args-open-delim () (forward-char) (current-column)) (defun ess-calculate-indent--args-prev-call (block) ;; Handle brackets chains such as ][ (cf data.table) (ess-climb-chained-delims) ;; Handle call chains (if ess-indent-from-chain-start (while (and (ess-backward-sexp) (when (looking-back "[[(][ \t,]*" (line-beginning-position)) (goto-char (match-beginning 0))))) (ess-backward-sexp)) (when ess-indent-from-lhs (ess-climb-lhs)) (if (and nil (eq block 'fun-decl) (not (eq arg-block 'opening)) (not (eq (ess-offset-type type-sym) 'open-delim))) (+ (ess-offset 'block) (current-column)) (current-column))) (defun ess-calculate-indent--args-prev-line (type block offset) (ess-at-indent-point (cond ;; Closing delimiters are actually not indented at ;; prev-line, but at opening-line ((looking-at "[]})]") (ess-up-list -1) (when (looking-at "{") (ess-climb-block-prefix)) (list offset (current-indentation))) ;; Function blocks need special treatment ((and (eq type 'prev-line) (eq block 'fun-decl)) (goto-char containing-sexp) (ess-climb-block-prefix) (list offset (current-indentation))) ;; Regular case (t ;; Find next non-empty line to indent from (while (and (= (forward-line -1) 0) (looking-at "[ \t]*\\($\\|#\\)"))) (goto-char (ess-code-end-position)) ;; Climb relevant structures (unless (ess-climb-block-prefix) (when (eq (char-before) ?,) (forward-char -1)) (ess-climb-expression) (ess-climb-continuations)) ;; The following ensures that only the first line ;; counts. Otherwise consecutive statements would get ;; increasingly more indented. (let ((offset (if (and block containing-sexp (not (eq block 'unbraced)) (save-excursion (/= (line-number-at-pos) (progn (goto-char containing-sexp) (line-number-at-pos))))) 0 offset))) (list offset (current-indentation))))))) ;; Indentation of arguments needs to keep track of how previous ;; arguments are indented. If one of those has a smaller indentation, ;; we push off the current line from its natural indentation. For ;; block arguments, we still need to push off this column so we ignore ;; it. (defun ess-adjust-argument-indent (base offset max-col push) (if push (+ (min base max-col) offset) (min (+ base offset) max-col))) ;; When previous arguments are shifted to the left (can happen in ;; several situations) compared to their natural indentation, the ;; following lines should not get indented past them. The following ;; function checks the minimum indentation for all arguments of the ;; current function call or bracket indexing. (defun ess-maximum-args-indent (&optional from to) (let* ((to (or to (point))) (to-line (line-number-at-pos to)) (from-line (progn (goto-char (1+ (or from containing-sexp))) (line-number-at-pos))) max-col) (while (< (line-number-at-pos) to-line) (forward-line) (back-to-indentation) ;; Ignore the line with the function call, the line to be ;; indented, and empty lines. (unless (or (>= (line-number-at-pos) to-line) (looking-at "[ \t]*\\($\\|#\\)")) (let ((indent (cond ;; First line: minimum indent is right after ( ((= (line-number-at-pos) from-line) (save-excursion (goto-char (1+ containing-sexp)) (current-column))) ;; Handle lines starting with a comma ((save-excursion (looking-at ",")) (+ (current-indentation) 2)) (t (current-indentation))))) (setq max-col (min indent (or max-col indent)))))) max-col)) ;; Move to leftmost side of a call (either the first letter of its ;; name or its closing delim) (defun ess-move-to-leftmost-side () (when (or (looking-at "[({]") (ess-behind-call-p)) (ess-save-excursion-when-nil (let ((start-col (current-column))) (skip-chars-forward "^{[(") (forward-char) (ess-up-list) (forward-char -1) (< (current-column) start-col))))) (defun ess-max-col () (let ((max-col (point))) (save-excursion (while (< (point) indent-point) (unless (and ess-indent-with-fancy-comments (looking-at "### ")) (setq max-col (min max-col (current-column)))) (forward-line) (back-to-indentation))) max-col)) (defun ess-calculate-indent--prefixed-block-curly () (when (looking-at "{") (ess-save-excursion-when-nil (let ((block-type (ess-climb-block-prefix))) (cond ((ess-save-excursion-when-nil (and (memq 'fun-decl-opening ess-indent-from-lhs) (string= block-type "function") (ess-climb-operator) (ess-behind-assignment-op-p) (ess-climb-expression))) (current-column)) ((= (save-excursion (back-to-indentation) (point)) (point)) (ess-calculate-indent--continued))))))) (defun ess-calculate-indent--continued () "If a continuation line, return an indent of this line, otherwise nil." (save-excursion (let* ((cascade (eq (ess-offset-type 'continued) 'cascade)) (climbed (ess-climb-continuations cascade)) max-col) (when climbed (cond ;; Overridden calls ((and ess-align-continuations-in-calls (not (eq climbed 'def-op)) containing-sexp (save-excursion (goto-char containing-sexp) (looking-at "[[(]"))) (setq max-col (ess-max-col)) (ess-move-to-leftmost-side) (+ (min (current-column) max-col) (if (eq climbed 'def-op) (ess-offset 'continued) 0))) ;; Regular case (t (let ((first-indent (or (eq climbed 'def-op) (save-excursion (when (ess-ahead-closing-p) (ess-climb-expression)) (not (ess-climb-continuations cascade)))))) ;; Record all indentation levels between indent-point and ;; the line we climbed. Some lines may have been pushed off ;; their natural indentation. These become the new ;; reference. (setq max-col (ess-max-col)) ;; Indenting continuations from the front of closing ;; delimiters looks better (when (ess-ahead-closing-p) (backward-char)) (+ (min (current-column) max-col) (cond ((eq (ess-offset-type 'continued) 'cascade) (ess-offset 'continued)) (first-indent (ess-offset 'continued)) (t 0)))))))))) (defun ess-calculate-indent--nested-calls () (when ess-align-nested-calls (let ((calls (mapconcat #'identity ess-align-nested-calls "\\|")) match) (save-excursion (and containing-sexp (looking-at (concat "\\(" calls "\\)(")) (setq match (match-string 1)) (goto-char containing-sexp) (looking-at "(") (ess-backward-sexp) (looking-at (concat match "(")) (current-column)))))) ;;;*;;; Call filling engine ;; Unroll arguments to a single line until closing marker is found. (defun ess-fill--unroll-lines (bounds &optional jump-cont) (let* ((last-pos (point-min)) (containing-sexp (ess-containing-sexp-position))) (goto-char (car bounds)) (goto-char (ess-code-end-position)) (while (and (/= (point) last-pos) (< (line-end-position) (cadr bounds))) (setq last-pos (point)) ;; Check whether we ended up in a sub call. In this case, jump ;; over it, otherwise, join lines. (let ((contained-sexp (ess-containing-sexp-position))) (cond ((and contained-sexp containing-sexp (not (= containing-sexp contained-sexp))) (goto-char (1+ contained-sexp)) (ess-up-list)) ;; Jump over continued statements ((and jump-cont (ess-ahead-operator-p 'strict)) (ess-climb-token) (ess-jump-continuations)) ;; Jump over comments ((looking-at "#") (forward-line) (funcall indent-line-function)) (t (join-line 1)))) (goto-char (ess-code-end-position))) (goto-char (car bounds)))) (defvar ess-fill--orig-pos nil "Original position of cursor.") (defvar ess-fill--orig-state nil "Backup of original code to cycle back to original state.") (defvar ess-fill--second-state nil "Backup of code produce by very first cycling. If this is equal to orig-state, no need to cycle back to original state.") (defvar ess-fill--style-level nil "Filling style used in last cycle.") (defun ess-fill--substring (bounds) (buffer-substring (car bounds) (marker-position (cadr bounds)))) ;; Detect repeated commands (defun ess-fill-style (type bounds) (let ((max-level ;; This part will be simpler once we have the style alist (cond ((eq type 'calls) ;; No third style either when ess-offset-arguments is ;; set to 'open-delim, or when ess-fill-calls-newlines ;; is nil and no numeric prefix is given (if (and (not (eq (ess-offset-type 'arguments) 'open-delim)) (or ess-fill-calls-newlines (numberp current-prefix-arg))) 3 2)) ((eq type 'continuations) 2)))) (if (not (memq last-command '(fill-paragraph-or-region fill-paragraph))) (progn ;; Record original state on first cycling (setq ess-fill--orig-state (ess-fill--substring bounds)) (setq ess-fill--orig-pos (point)) (setq ess-fill--second-state nil) (setq ess-fill--style-level 1)) ;; Also record state on second cycling (when (and (= ess-fill--style-level 1) (null ess-fill--second-state)) (setq ess-fill--second-state (ess-fill--substring bounds))) (cond ((>= ess-fill--style-level max-level) (let ((same-last-and-orig (string= (ess-fill--substring bounds) ess-fill--orig-state)) (same-2nd-and-orig (string= ess-fill--orig-state ess-fill--second-state))) ;; Avoid cycling to the same state twice (cond ((and same-last-and-orig same-2nd-and-orig) (setq ess-fill--style-level 2)) ((or same-last-and-orig same-2nd-and-orig) (setq ess-fill--style-level 1)) (t (setq ess-fill--style-level 0))))) (ess-fill--style-level (setq ess-fill--style-level (1+ ess-fill--style-level)))))) ess-fill--style-level) (let (_) ;; FIXME: Transform these dynamic bindings to a state object (defvar ess--infinite) (defvar ess--prefix-break) (defvar ess--start-pos) (defvar ess--last-pos) (defvar ess--last-newline) (declare-function ess-fill-args--roll-lines "ess-r-mode") (defun ess-fill-args (&optional style) (let ((ess--start-pos (point-min)) (bounds (ess-args-bounds 'marker)) ;; Set undo boundaries manually (undo-inhibit-record-point t) ess--last-pos ess--last-newline ess--prefix-break ess--infinite) (when (not bounds) (error "Could not find function bounds")) (setq style (or style (ess-fill-style 'calls bounds))) (if (= style 0) (progn (delete-region (car bounds) (marker-position (cadr bounds))) (insert ess-fill--orig-state) ;; Restore the point manually. (save-excursion) wouldn't ;; work here because we delete the text rather than just ;; modifying it. (goto-char ess-fill--orig-pos) (message "Back to original formatting")) (when ess-blink-refilling (ess-blink-region (nth 2 bounds) (1+ (marker-position (cadr bounds))))) (undo-boundary) (save-excursion (ess-fill--unroll-lines bounds t) (cond ;; Some styles start with first argument on a newline ((and (memq style '(2 4)) ess-fill-calls-newlines (not (looking-at "[ \t]*#"))) (newline-and-indent)) ;; Third level, start a newline after N arguments ((and (= style 3) (not (looking-at "[ \t]*#"))) (let ((i (if (numberp current-prefix-arg) current-prefix-arg 1))) (while (and (> i 0) (ess-jump-arg) (ess-jump-char ",")) (setq i (1- i)))) (newline-and-indent))) (ess-fill-args--roll-lines style) ;; Reindent surrounding context (ess-indent-call (car bounds))) ;; Signal marker for garbage collection (set-marker (cadr bounds) nil) (undo-boundary)))) (defun ess-fill-args--roll-lines (style) (while (and (not (looking-at "[])]")) (/= (point) (or ess--last-pos 1)) (not ess--infinite)) (setq ess--prefix-break nil) ;; Record ess--start-pos as future breaking point to avoid breaking ;; at `=' sign (while (looking-at "[ \t]*[\n#]") (forward-line) (back-to-indentation)) (setq ess--start-pos (point)) (while (and (< (current-column) fill-column) (not (looking-at "[])]")) (/= (point) (or ess--last-pos 1)) ;; Break after one pass if prefix is active (not ess--prefix-break)) (when (memq style '(2 3)) (setq ess--prefix-break t)) (ess-jump-token ",") (setq ess--last-pos (point)) ;; Jump expression and any continuations. Reindent all lines ;; that were jumped over (let ((cur-line (line-number-at-pos)) end-line) (cond ((ess-jump-arg) (setq ess--last-newline nil)) ((ess-token-after= ",") (setq ess--last-newline nil) (setq ess--last-pos (1- (point))))) (save-excursion (when (< cur-line (line-number-at-pos)) (setq end-line (line-number-at-pos)) (ess-goto-line (1+ cur-line)) (while (and (<= (line-number-at-pos) end-line) (/= (point) (point-max))) (funcall indent-line-function) (forward-line)))))) (when (or (>= (current-column) fill-column) ess--prefix-break ;; Ensures closing delim on a newline (and (= style 4) (looking-at "[ \t]*[])]") (setq ess--last-pos (point)))) (if (and ess--last-pos (/= ess--last-pos ess--start-pos)) (goto-char ess--last-pos) (ess-jump-char ",")) (cond ((looking-at "[ \t]*[#\n]") (forward-line) (funcall indent-line-function) (setq ess--last-newline nil)) ;; With levels 2 and 3, closing delim goes on a newline ((looking-at "[ \t]*[])]") (when (and (memq style '(2 3 4)) ess-fill-calls-newlines (not ess--last-newline)) (newline-and-indent) ;; Prevent indenting infinitely (setq ess--last-newline t))) ((not ess--last-newline) (newline-and-indent) (setq ess--last-newline t)) (t (setq ess--infinite t))))))) (defun ess-fill-continuations (&optional style) (let ((bounds (ess-continuations-bounds 'marker)) (undo-inhibit-record-point t) (last-pos (point-min)) last-newline infinite) (when (not bounds) (error "Could not find statements bounds")) (setq style (or style (ess-fill-style 'continuations bounds))) (if (= style 0) (progn (delete-region (car bounds) (marker-position (cadr bounds))) (insert ess-fill--orig-state) (goto-char ess-fill--orig-pos) (message "Back to original formatting")) (when ess-blink-refilling (ess-blink-region (car bounds) (marker-position (cadr bounds)))) (undo-boundary) (save-excursion (ess-fill--unroll-lines bounds) (while (and (< (point) (cadr bounds)) (/= (point) (or last-pos 1)) (not infinite)) (setq last-pos (point)) (when (and (ess-jump-expression) (indent-according-to-mode) (not (> (current-column) fill-column))) (setq last-newline nil)) (ess-jump-operator) (if (or (and (> (current-column) fill-column) (goto-char last-pos)) (= style 2)) (progn (ess-jump-operator) (unless (= (point) (cadr bounds)) (when last-newline (setq infinite t)) (newline-and-indent) (setq last-newline t))) (setq last-newline nil))) (ess-indent-call (car bounds))) (set-marker (cadr bounds) nil) (undo-boundary)))) ;;;*;;; Inferior R mode (defvar inferior-ess-r-mode-map (let ((map (make-sparse-keymap))) (define-key map "\M-\r" #'ess-dirs) (define-key map (kbd "C-c C-=") #'ess-cycle-assign) (define-key map (kbd "C-c C-.") 'ess-rutils-map) map) "Keymap for `inferior-ess-r-mode'.") ;; TOTHINK: Prevent string delimiting characters from messing up output in the ;; inferior buffer (defvar inferior-ess-r-mode-syntax-table (let ((table (copy-syntax-table ess-r-mode-syntax-table))) (modify-syntax-entry ?% "." table) (modify-syntax-entry ?\' "." table) table) "Syntax table for `inferior-ess-r-mode'.") (define-derived-mode inferior-ess-r-mode inferior-ess-mode "iESS" "Major mode for interacting with inferior R processes." :group 'ess-proc (ess-setq-vars-local ess-r-customize-alist) (setq-local ess-font-lock-keywords 'inferior-ess-r-font-lock-keywords) (setq-local font-lock-syntactic-face-function #'ess-r-font-lock-syntactic-face-function) (setq-local comint-process-echoes (eql ess-eval-visibly t)) (setq-local comint-prompt-regexp inferior-S-prompt) (setq-local syntax-propertize-function ess-r--syntax-propertize-function) (setq comint-input-sender 'inferior-ess-r-input-sender) (remove-hook 'completion-at-point-functions #'ess-filename-completion 'local) ;; should be first (add-hook 'completion-at-point-functions #'ess-r-object-completion nil 'local) (add-hook 'completion-at-point-functions #'ess-filename-completion nil 'local) (add-hook 'xref-backend-functions #'ess-r-xref-backend nil 'local) (add-hook 'project-find-functions #'ess-r-project nil 'local) ;; eldoc (ess--setup-eldoc #'ess-r-eldoc-function) ;; auto-complete (ess--setup-auto-complete ess-r-ac-sources t) ;; company (ess--setup-company ess-r-company-backends t) (setq comint-get-old-input #'inferior-ess-get-old-input) (add-hook 'comint-input-filter-functions #'ess-search-path-tracker nil 'local)) ;;;*;;; R Help mode (defvar ess-r-help-mode-map (let ((map (make-sparse-keymap))) (set-keymap-parent map (make-composed-keymap button-buffer-map ess-help-mode-map)) (define-key map "s<" #'beginning-of-buffer) (define-key map "s>" #'end-of-buffer) (define-key map "sa" #'ess-skip-to-help-section) (define-key map "sd" #'ess-skip-to-help-section) (define-key map "sD" #'ess-skip-to-help-section) (define-key map "st" #'ess-skip-to-help-section) (define-key map "se" #'ess-skip-to-help-section) (define-key map "sn" #'ess-skip-to-help-section) (define-key map "sr" #'ess-skip-to-help-section) (define-key map "ss" #'ess-skip-to-help-section) (define-key map "su" #'ess-skip-to-help-section) (define-key map "sv" #'ess-skip-to-help-section) map) "Keymap for `ess-r-help-mode'.") (cl-defmethod ess--help-major-mode (&context (ess-dialect "R")) (ess-r-help-mode)) (define-derived-mode ess-r-help-mode ess-help-mode "R Help" "Major mode for help buffers." :group 'ess-help (setq ess-dialect "R" ess-help-sec-regex ess-help-r-sec-regex ess-help-sec-keys-alist ess-help-r-sec-keys-alist ; TODO: Still necessary? inferior-ess-help-command inferior-ess-r-help-command) (ess-r-help--add-links)) (define-button-type 'ess-r-help--link 'follow-link t 'action (lambda (_) (ess-r-help--button-action))) (defun ess-r-help--button-action () "Display help for button at point." (let ((text (get-text-property (point) 'ess-r-help--link-text))) (ess-display-help-on-object text))) (defun ess-r-help--add-links () "Add links to the help buffer." (let ((links (when (ess-process-live-p) (ess-get-words-from-vector (ess-r--format-call ".ess.helpLinks('%s' %s)\n" ess-r-help--local-object (ess-r-arg "package" ess-r-help--local-package t))))) (inhibit-read-only t)) (save-excursion ;; Search for fancy quotes only. If users have ;; options(useFancyQuotes) set to something other than TRUE this ;; probably won't work. If it's FALSE, R outputs ascii ', but ;; searching through the whole buffer takes too long. (while (re-search-forward "â€\\([^[:space:]]+?\\)’" nil t) (let* ((text (match-string 1)) (text-stripped (if (string-match-p ".*()\\'" text) (substring text nil (- (length text) 2)) text))) (when (member text-stripped links) (delete-region (match-beginning 0) (match-end 0)) (insert-text-button text 'ess-r-help--link-text text-stripped 'type 'ess-r-help--link 'help-echo (format "mouse-2, RET: Help on %s" text)))))))) (cl-defmethod ess--display-vignettes-override (all &context (ess-dialect "R")) "Display R vignettes in ess-help-like buffer.. With (prefix) ALL non-nil, use `vignette(*, all=TRUE)`, i.e., from all installed packages, which can be very slow." (inferior-ess-r-force) (let* ((vslist (with-current-buffer (ess-command (format ".ess_vignettes(%s)\n" (if all "TRUE" ""))) (goto-char (point-min)) (when (re-search-forward "(list" nil t) (goto-char (match-beginning 0)) (ignore-errors (eval (read (current-buffer)) t))))) (proc-name ess-current-process-name) (alist ess-local-customize-alist) (remote (file-remote-p default-directory)) (buff (get-buffer-create (format "*[%s]vignettes*" ess-dialect))) (inhibit-modification-hooks t) (inhibit-read-only t)) (with-current-buffer buff (setq buffer-read-only nil) (delete-region (point-min) (point-max)) (ess-setq-vars-local (eval alist t)) (setq ess-local-process-name proc-name) (ess--help-major-mode) (setq ess-help-sec-regex "^\\w+:$" ess-help-type 'vignettes) (set-buffer-modified-p 'nil) (goto-char (point-min)) (dolist (el vslist) (let ((pack (car el))) (insert (format "\n\n%s:\n\n" (propertize pack 'face 'underline))) (dolist (el2 (cdr el)) (let ((path (if remote (with-no-warnings ;; Have to wrap this in with-no-warnings because ;; otherwise the byte compiler complains about ;; calling tramp-make-tramp-file-name with an ;; incorrect number of arguments on Both 26+ and 25 emacses. (if (>= emacs-major-version 26) (with-parsed-tramp-file-name default-directory nil (tramp-make-tramp-file-name method user domain host port (nth 1 el2))) (with-parsed-tramp-file-name default-directory nil (tramp-make-tramp-file-name method user host (nth 1 el2))))) (nth 1 el2)))) (insert-text-button "doc" 'mouse-face 'highlight 'action (if remote #'ess--action-open-in-emacs #'ess--action-R-open-vignette) 'follow-link t 'vignette (file-name-sans-extension (nth 2 el2)) 'package pack 'help-echo (concat path "/doc/" (nth 2 el2))) (insert " ") (insert-text-button "source" 'mouse-face 'highlight 'action #'ess--action-open-in-emacs 'follow-link t 'help-echo (concat path "/doc/" (nth 3 el2))) (insert " ") (insert-text-button "R" 'mouse-face 'highlight 'action #'ess--action-open-in-emacs 'follow-link t 'help-echo (concat path "/doc/" (nth 4 el2))) (insert (format "\t%s\n" (nth 0 el2))))))) (goto-char (point-min)) (insert (propertize "\t\t**** Vignettes ****\n" 'face 'bold-italic)) (unless (eobp) (delete-char 1)) (setq buffer-read-only t)) (ess-display-help buff))) ;; Support for listing R packages (define-obsolete-variable-alias 'ess-rutils-buf 'ess-r-package-menu-buf "ESS 19.04") (define-obsolete-variable-alias 'ess-rutils-mode-map 'ess-r-package-menu-mode-map "ESS 19.04") (define-obsolete-function-alias 'ess-rutils-mode #'ess-r-package-menu-mode "ESS 19.04") (defvar ess-rutils-map (let ((map (define-prefix-command 'ess-rutils-map))) (define-key map "l" #'ess-r-package-list-local-packages) (define-key map "r" #'ess-r-package-list-available-packages) (define-key map "u" #'ess-r-package-update-packages) (define-key map "a" #'ess-display-help-apropos) (define-key map "m" #'ess-rutils-rm-all) (define-key map "o" #'ess-rdired) (define-key map "w" #'ess-rutils-load-workspace) (define-key map "s" #'ess-rutils-save-workspace) (define-key map "d" #'ess-change-directory) (define-key map "H" #'ess-rutils-html-docs) map)) (easy-menu-define ess-rutils-mode-menu inferior-ess-mode-menu "Package management." '("Package management" ["List local packages" ess-r-package-list-local-packages t] ["List available packages" ess-r-package-list-available-packages t] ["Update packages" ess-r-package-update-packages t])) (easy-menu-add-item inferior-ess-mode-menu nil ess-rutils-mode-menu "Utils") (easy-menu-add-item ess-mode-menu nil ess-rutils-mode-menu "Process") (defvar ess-r-package-menu-buf "*R packages*" "Name of buffer to display R packages in.") (defvar ess-r-package-menu-mode-map (let ((map (make-sparse-keymap))) (define-key map "l" #'ess-r-package-load) (define-key map "i" #'ess-r-package-mark-install) (define-key map "x" #'ess-r-package-execute-marks) (define-key map "u" #'ess-r-package-unmark) map) "Keymap for `ess-rutils-mode'.") (define-derived-mode ess-r-package-menu-mode tabulated-list-mode "R utils" "Major mode for `ess-rutils-local-pkgs' and `ess-rutils-repos-pkgs'." :group 'ess-R (setq ess-dialect "R") (setq mode-name (concat "R packages: " ess-local-process-name)) (setq tabulated-list-padding 2) (setq tabulated-list-format `[("Name" 10 t) ("Description" 50 nil) ("Version" 5 t)]) (tabulated-list-init-header)) (define-obsolete-function-alias 'ess-rutils-local-pkgs #'ess-r-package-list-local-packages "ESS 19.04") (defun ess-r-package-list-local-packages () "List all packages in all libraries." (interactive) (ess-r-package--list-packages (concat ".ess.rutils.ops <- options(width = 10000);" "print(installed.packages(fields=c(\"Title\"))[, c(\"Title\", \"Version\")]);" "options(.ess.rutils.ops); rm(.ess.rutils.ops);" "\n"))) (defun ess-r-package--list-packages (cmd) "Use CMD to list packages." (let ((process ess-local-process-name) des-col-beginning des-col-end entries) (with-current-buffer (ess-command cmd (get-buffer-create " *ess-rutils-pkgs*")) (goto-char (point-min)) (delete-region (point) (1+ (line-end-position))) ;; Now we have a buffer with package name, description, and ;; version. description and version are surrounded by quotes, ;; description is separated by whitespace. (re-search-forward "\\>[[:space:]]+") (setq des-col-beginning (current-column)) (goto-char (line-end-position)) ;; Unless someone has a quote character in their package version, ;; two quotes back will be the end of the package description. (dotimes (_ 2) (search-backward "\"")) (re-search-backward "[[:space:]]*") (setq des-col-end (current-column)) (beginning-of-line) (while (not (eobp)) (beginning-of-line) (let* ((name (string-trim (buffer-substring (point) (progn (forward-char (1- des-col-beginning)) (point))))) (description (string-trim (buffer-substring (progn (forward-char 1) (point)) (progn (forward-char (- des-col-end des-col-beginning)) (point))))) (version (buffer-substring (progn (end-of-line) (search-backward "\"") (search-backward "\"") (forward-char 1) (point)) (progn (search-forward "\"") (backward-char 1) (point))))) (push (list name `[(,name help-echo "mouse-2, RET: help on this package" action ess-rutils-help-on-package) ,description ,version]) entries) (forward-line))) (pop-to-buffer ess-rutils-buf) (setq ess-local-process-name process) (setq tabulated-list-entries entries) (ess-r-package-menu-mode) (tabulated-list-print)))) (define-obsolete-function-alias 'ess-rutils-loadpkg #'ess-r-package-load "ESS 19.04") (defun ess-r-package-load () "Load package from a library." (interactive) (ess-execute (concat "library('" (tabulated-list-get-id) "', character.only = TRUE)") 'buffer)) (defun ess-rutils-help-on-package (&optional _button) "Display help on the package at point." (interactive) ;; FIXME: Should go to a help buffer (ess-execute (concat "help(" (tabulated-list-get-id) ", package = '" (tabulated-list-get-id)"')") 'buffer)) (define-obsolete-function-alias 'ess-rutils-repos-pkgs #'ess-r-package-list-available-packages "ESS 19.04") (defun ess-r-package-list-available-packages () "List available packages. Use the repositories as listed by getOptions(\"repos\") in the current R session." (interactive) (ess-r-package--list-packages "{ .ess.rutils.ops <- options(width = 10000) print(available.packages(fields=c(\"Title\"))[, c(\"Title\", \"Version\")]) options(.ess.rutils.ops); rm(.ess.rutils.ops) }\n")) (define-obsolete-function-alias 'ess-rutils-mark-install #'ess-r-package-mark-install "ESS 19.04") (defun ess-r-package-mark-install () "Mark the current package for installing." (interactive) (tabulated-list-put-tag "i" t)) (define-obsolete-function-alias 'ess-rutils-unmark #'ess-r-package-unmark "ESS 19.04") (defun ess-r-package-unmark () "Unmark the packages." (interactive) (tabulated-list-put-tag " " t)) (define-obsolete-function-alias 'ess-rutils-execute-marks #'ess-r-package-execute-marks "ESS 19.04") (defun ess-r-package-execute-marks () "Perform all marked actions." (interactive) ;; Install (save-excursion (let ((cmd "install.packages(c(") pkgs) (goto-char (point-min)) (while (not (eobp)) (when (looking-at-p "i") (setq pkgs (concat "\"" (tabulated-list-get-id) "\", " pkgs)) (tabulated-list-put-tag " ")) (forward-line)) (if pkgs (progn (setq pkgs (substring pkgs 0 (- (length pkgs) 2))) (setq cmd (concat cmd pkgs "))")) (ess-execute cmd 'buffer)) (message "No packages marked for install"))))) (define-obsolete-function-alias 'ess-rutils-update-pkgs #'ess-r-package-update-packages "ESS 19.04") (defun ess-r-package-update-packages (lib repo) "Update packages in library LIB and repo REPO. This also uses checkBuilt=TRUE to rebuild installed packages if needed." (interactive (list (ess-completing-read "Library to update: " (ess-get-words-from-vector "as.character(.libPaths())\n")) (ess-completing-read "Repo: " (ess-get-words-from-vector "as.character(getOption(\"repos\"))\n")))) (ess-execute (format "update.packages(lib.loc='%s', repos='%s', ask=FALSE, checkBuilt=TRUE)" lib repo) 'buffer)) (define-obsolete-function-alias 'ess-rutils-apropos #'ess-display-help-apropos "ESS 19.04") ;; Miscellaneous helper functions (defun ess-rutils-rm-all () "Remove all R objects." (interactive) (when (y-or-n-p "Delete all objects? ") (ess-execute "rm(list=ls())" 'buffer))) (defun ess-rutils-load-workspace (file) "Load workspace FILE into R." (interactive "fFile with workspace to load: ") (ess-execute (concat "load('" file "')") 'buffer)) (define-obsolete-function-alias 'ess-rutils-load-wkspc #'ess-rutils-load-workspace "ESS 19.04") (defun ess-rutils-save-workspace (file) "Save FILE workspace as file.RData." (interactive "FSave workspace to file (no extension): ") (ess-execute (concat "save.image('" file ".RData')") 'buffer)) (define-obsolete-function-alias 'ess-rutils-save-wkspc #'ess-rutils-save-workspace "ESS 19.04") (defun ess-rutils-quit () "Kill the ess-rutils buffer and return to the iESS buffer." (interactive) (ess-switch-to-end-of-ESS) (kill-buffer ess-rutils-buf)) (defun ess-rutils-html-docs (&optional remote) "Use `browse-url' to navigate R html documentation. Documentation is produced by a modified help.start(), that returns the URL produced by GNU R's http server. If called with a prefix, the modified help.start() is called with update=TRUE. The optional REMOTE argument should be a string with a valid URL for the 'R_HOME' directory on a remote server (defaults to NULL)." (interactive) (let* ((update (if current-prefix-arg "update=TRUE" "update=FALSE")) (remote (if (or (and remote (not (string= "" remote)))) (concat "remote=" remote) "remote=NULL")) (proc ess-local-process-name) (rhtml (format ".ess_help_start(%s, %s)\n" update remote))) (with-temp-buffer (ess-command rhtml (current-buffer) nil nil nil (get-process proc)) (let* ((begurl (search-backward "http://")) (endurl (search-forward "index.html")) (url (buffer-substring-no-properties begurl endurl))) (browse-url url))))) (defun ess-rutils-rsitesearch (string) "Search the R archives for STRING, and show results using `browse-url'. If called with a prefix, options are offered (with completion) for matches per page, sections of the archives to search, displaying results in long or short formats, and sorting by any given field. Options should be separated by value of `crm-default-separator'." (interactive "sSearch string: ") (let ((site "https://search.r-project.org/cgi-bin/namazu.cgi?query=") (okstring (replace-regexp-in-string " +" "+" string))) (browse-url (if current-prefix-arg (let ((mpp (concat "&max=" (completing-read "Matches per page: " '(("20" 1) ("30" 2) ("40" 3) ("50" 4) ("100" 5))))) (format (concat "&result=" (completing-read "Format: " '(("normal" 1) ("short" 2)) nil t "normal" nil "normal"))) (sortby (concat "&sort=" (completing-read "Sort by: " '(("score" 1) ("date:late" 2) ("date:early" 3) ("field:subject:ascending" 4) ("field:subject:descending" 5) ("field:from:ascending" 6) ("field:from:descending" 7) ("field:size:ascending" 8) ("field:size:descending" 9)) nil t "score" nil "score"))) (restrict (concat "&idxname=" (mapconcat #'identity (completing-read-multiple "Limit search to: " '(("Rhelp02a" 1) ("functions" 2) ("docs" 3) ("Rhelp01" 4)) nil t "Rhelp02a,functions,docs" nil "Rhelp02a,functions,docs") "&idxname=")))) (concat site okstring mpp format sortby restrict)) (concat site okstring "&max=20&result=normal&sort=score" "&idxname=Rhelp02a&idxname=functions&idxname=docs"))))) (defun ess-rutils-help-search (string) "Search for STRING using help.search()." (interactive "sString to search for? ") (let ((proc ess-local-process-name)) (pop-to-buffer "foobar") (ess-command (concat "help.search('" string "')\n") (current-buffer) nil nil nil (get-process proc)))) (make-obsolete 'ess-rutils-rhtml-fn "overwrite .ess_help_start instead." "ESS 18.10") ;; Create functions that can be called for running different versions ;; of R. ;; FIXME: Should be set in ess-custom (setq ess-rterm-version-paths (ess-flatten-list (delete-dups (if (not ess-directory-containing-R) (if (getenv "ProgramW6432") (let ((P-1 (getenv "ProgramFiles(x86)")) (P-2 (getenv "ProgramW6432"))) (nconc ;; Always 32 on 64 bit OS, nil on 32 bit OS (ess-find-rterm (concat P-1 "/R/") "bin/Rterm.exe") (ess-find-rterm (concat P-1 "/R/") "bin/i386/Rterm.exe") ;; Keep this both for symmetry and because it can happen: (ess-find-rterm (concat P-1 "/R/") "bin/x64/Rterm.exe") ;; Always 64 on 64 bit OS, nil on 32 bit OS (ess-find-rterm (concat P-2 "/R/") "bin/Rterm.exe") (ess-find-rterm (concat P-2 "/R/") "bin/i386/Rterm.exe") (ess-find-rterm (concat P-2 "/R/") "bin/x64/Rterm.exe"))) (let ((PF (getenv "ProgramFiles"))) (nconc ;; Always 32 on 32 bit OS, depends on 32 or 64 process on 64 bit OS (ess-find-rterm (concat PF "/R/") "bin/Rterm.exe") (ess-find-rterm (concat PF "/R/") "bin/i386/Rterm.exe") (ess-find-rterm (concat PF "/R/") "bin/x64/Rterm.exe")))) (let ((PF ess-directory-containing-R)) (nconc (ess-find-rterm (concat PF "/R/") "bin/Rterm.exe") (ess-find-rterm (concat PF "/R/") "bin/i386/Rterm.exe") (ess-find-rterm (concat PF "/R/") "bin/x64/Rterm.exe"))))))) (ess-r-define-runners) ;;*;; Provide and auto-loads ;;;###autoload (add-to-list 'auto-mode-alist '("/Makevars\\(\\.win\\)?\\'" . makefile-mode)) ;;;###autoload (add-to-list 'auto-mode-alist '("DESCRIPTION\\'" . conf-colon-mode)) (provide 'ess-r-mode) ;;; ess-r-mode.el ends here ESS-24.01.1/lisp/ess-r-package.el000066400000000000000000000602001455642170100162270ustar00rootroot00000000000000;;; ess-r-package.el --- Package development mode for R. -*- lexical-binding: t; -*- ;; Copyright (C) 2011-2022 Free Software Foundation, Inc. ;; Author: Lionel Henry, Vitalie Spinu ;; Maintainer: ESS-core ;; This file is part of GNU Emacs. ;;; License: ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see ;; ;;; Commentary: ;; see appropriate documentation section of ESS user manual ;;; Code: (require 'cl-lib) (require 'ess-inf) (eval-when-compile (require 'subr-x) (require 'tramp)) ;; Silence the byte compiler, OK because this file is only loaded by ;; ess-r-mode and has no autoloads. (defvar ess-r-customize-alist) (declare-function ess-r-project "ess-r-mode") (declare-function inferior-ess-r-force "ess-r-mode") (declare-function ess-r-get-evaluation-env "ess-r-mode") (declare-function ess-r-set-evaluation-env "ess-r-mode") (declare-function tramp-dissect-file-name "tramp" (name &optional nodefault)) ;; This can be drop after dropping support for Emacs 25: (declare-function tramp-file-name-localname "tramp" (cl-x)) (defvar ess-r-prompt-for-attached-pkgs-only nil "If nil provide completion for all installed R packages. If non-nil, only look for attached packages.") (define-obsolete-variable-alias 'ess-r-package-auto-set-evaluation-env 'ess-r-package-auto-enable-namespaced-evaluation "18.04") (define-obsolete-variable-alias 'ess-r-package-auto-set-evaluation-env 'ess-r-package-auto-enable-namespaced-evaluation "18.04") (defcustom ess-r-package-auto-enable-namespaced-evaluation t "If non-nil, evaluation env is set to package env automatically. See also `ess-r-set-evaluation-env' and `ess-r-evaluation-env'." :group 'ess-r-package :type 'boolean) (defvar-local ess-r-package--info-cache nil "Current package info cache. See `ess-r-package-info' for its structure.") (defcustom ess-r-package-library-paths nil "Default path to find user packages. Can be either a string specifying a directory or a list of directories. This variable is also consulted by `xref-find-definitions' in R buffers. See `ess-r-xref-backend'." :group 'ess-r-package-library-paths :type `(choice string (repeat string))) (defvar ess-r-package-root-file "DESCRIPTION" "Presence of this file indicates the project's root.") (defvar ess-r-package-dirs '(("R" . 1) ("r" . 1) ("tests" . 1) ("testthat" . 2) ("inst" . 1) ("include" . 2) ("src" . 1)) "Alist of directories names and their depth in R package hierarchy. This list is used to figure out whether the current file belongs to an R package. If the file specified in `ess-r-package-root-file' \(DESCRIPTION by default) is found at the presumed root directory of the package, the current directory is considered to be part of a R package.") (defvar ess-r-package-source-roots '("R" "src" "tests" "inst/include") "List of sub-directories within R package where source files are located. All children of these directories are also considered source containing directories. Use `ess-r-package-source-dirs' to get all source dirs recursively within the current package.") ;;;*;;; Package Detection (defun ess-r-package-project (&optional dir) "Return the current package as an Emacs project instance. A project instance is a cons cell of the project type as symbol and the project path as string. If DIR is provided, the package is searched from that directory instead of `default-directory'." (let ((pkg-info (ess-r-package-info dir))) (when (car pkg-info) (cons 'ess-r-package (plist-get pkg-info :root))))) ;; FIXME: remove when emacs 27 is dropped (unless (eval-when-compile (get 'project-roots 'byte-obsolete-info)) (cl-defmethod project-roots ((project (head ess-r-package))) "Return the project root for ESS R packages" (list (cdr project)))) (cl-defmethod project-root ((project (head ess-r-package))) "Return the project root for ESS R packages" (cdr project)) (defun ess-r-package-name (&optional dir) "Return the name of the current package as a string." (plist-get (ess-r-package-info dir) :name)) (defun ess-r-package-info (&optional dir) "Get the description of the R project in directory DIR. Return an plist with the keys :name and :root. When not in a package return \\='(nil). This value is cached buffer-locally for efficiency reasons." (if (and (null dir) (car ess-r-package--info-cache)) ess-r-package--info-cache (let* ((path (ess-r-package--find-package-path (or dir default-directory))) (name (when path (ess-r-package--find-package-name path))) (local (if (and path (file-remote-p path)) (tramp-file-name-localname (tramp-dissect-file-name path)) path)) (info (if name (list :name name :root local) '(nil)))) ;; If DIR was supplied we cannot cache in the current buffer. (if dir info (setq-local ess-r-package--info-cache info))))) (defun ess-r-package--all-source-dirs (dir) (when (file-directory-p dir) (cl-loop for f in (directory-files-and-attributes dir t "\\`[^.]") if (cadr f) append (cons (car f) (ess-r-package--all-source-dirs (car f)))))) (defun ess-r-package-source-dirs () "Get paths within current R package with source files. Return nil if not in a package. Search sub-directories listed in `ess-r-package-source-roots' are searched recursively and return all physically present directories." (let ((pkg-root (plist-get (ess-r-package-info) :root))) (when pkg-root (let ((files (directory-files-and-attributes pkg-root t "\\`[^.]"))) (cl-loop for f in files if (and (cadr f) (cl-some (lambda (el) (string-match-p (concat "/" el "$") (car f))) ess-r-package-source-roots)) append (cons (car f) (ess-r-package--all-source-dirs (car f)))))))) (defun ess-r--select-package-name () (inferior-ess-r-force) (let ((pkgs (ess-get-words-from-vector (format "print(.packages(%s), max = 1e6)\n" (if ess-r-prompt-for-attached-pkgs-only "FALSE" "TRUE")))) (current-pkg (ess-r-package-name))) (let ((env (ess-r-get-evaluation-env))) (when env (setq pkgs (append '("*none*") pkgs)) (when (equal env current-pkg) (setq current-pkg "*none*")))) (ess-completing-read "Package" pkgs nil nil nil nil current-pkg))) (defun ess-r-package--find-package-path (&optional dir) "Get the root of R package in directory DIR. DIR defaults to the current buffer's file name (if non-nil) or `default-directory'. Root is determined by locating `ess-r-package-root-file'." (when-let ((path (cond (dir) ((buffer-file-name) (file-name-directory (buffer-file-name))) (t default-directory))) (pkg-path (when path (or ;; First check current directory (and (file-exists-p (expand-file-name ess-r-package-root-file path)) path) ;; Check for known directories in current path (let ((current-dir (file-name-nondirectory (directory-file-name path))) known-pkg-dir known-path presumptive-path) (while (and path (not presumptive-path)) (setq current-dir (file-name-nondirectory (directory-file-name path))) (if (and (setq known-pkg-dir (assoc current-dir ess-r-package-dirs)) (setq known-path (ess--parent-dir path (cdr known-pkg-dir))) (file-exists-p (expand-file-name ess-r-package-root-file known-path))) (setq presumptive-path known-path) (setq path (ess--parent-dir path 1)))) presumptive-path))))) (directory-file-name pkg-path))) (defun ess-r-package--find-package-name (path) (let ((file (expand-file-name ess-r-package-root-file path)) (case-fold-search t)) (when (file-exists-p file) (with-temp-buffer (insert-file-contents-literally file) (goto-char (point-min)) (when (re-search-forward "package: \\(.*\\)" nil t) (match-string 1)))))) ;;;*;;; UI (defun ess-r-package-use-dir () "Set process directory to current package directory." (interactive) (let ((pkg-root (plist-get (ess-r-package-info) :root))) (if pkg-root (ess-set-working-directory (abbreviate-file-name pkg-root)) (user-error "Not in a project")))) ;;;*;;; Evaluation (defun ess-r-package-enable-namespaced-evaluation () "Enable namespaced evaluation in current buffer. Namespaced evaluation is enabled if `ess-r-package-auto-enable-namespaced-evaluation' is non-nil." (when ess-r-package-auto-enable-namespaced-evaluation (let ((root (plist-get (ess-r-package-info) :root))) ;; Check that we are in a file within R/ (when (and root default-directory (> (length default-directory) (1+ (length root))) (let ((subpath (substring default-directory (1+ (length root)) (length default-directory)))) (string= (directory-file-name subpath) "R"))) (ess-r-set-evaluation-env (ess-r-package-name)))))) (add-hook 'ess-r-mode-hook #'ess-r-package-enable-namespaced-evaluation) (defun ess-r-package-eval-linewise (command &optional msg p actions) "Send COMMAND to R process. COMMAND is a command string with %s placeholder for the arguments. MSG is the message displayed in minibuffer with %s placeholder for the package name. P is the value of universal argument usually received from the upstream command and indicates which action in ACTIONS list to perform; if 0 or nil, first action, if 1 or (4) second if 2 or (16) third etc. ACTIONS is a list of strings (R arguments), or functions which return R arguments, or expressions which return R arguments." (inferior-ess-r-force) (let ((pkg-info (ess-r-package-info)) (args (ess-r-command--build-args p actions))) (unless (car pkg-info) (user-error "Not in a package")) (ess-project-save-buffers) (message msg (plist-get pkg-info :name)) (display-buffer (ess-get-process-buffer)) (let ((pkg-path (concat "'" (abbreviate-file-name (plist-get pkg-info :root)) "'"))) (ess-eval-linewise (format command (concat pkg-path args)))))) (defun ess-r-command--build-args (ix &optional actions) (let* ((n (cond ((null ix) 0) ((listp ix) (round (log (car ix) 4))) ((integerp ix) ix) (t (error "Invalid index")))) (action (nth n actions)) (args (cond ((null action) "") ((stringp action) action) ((functionp action) (funcall action)) ((listp action) (eval action t)) (t (error "Invalid action"))))) (if (string= "" args) args (concat ", " args)))) ;;;*;;; Devtools Integration (defun ess-r-devtools-load-package (&optional arg) "Interface for `devtools::load_all()'. With prefix ARG ask for extra args." (interactive "P") (ess-r-package-eval-linewise "devtools::load_all(%s)\n" "Loading %s" arg '("" (read-string "Arguments: " "recompile = TRUE")))) (defun ess-r-devtools-unload-package () "Interface to `devtools::unload()'." (interactive) (ess-r-package-eval-linewise "devtools::unload(%s)\n" "Unloading %s")) (defun ess-r-devtools-check-package (&optional arg) "Interface for `devtools::check()'. With prefix ARG ask for extra args." (interactive "P") (ess-r-package-eval-linewise "devtools::check(%s)\n" "Checking %s" arg '("" (read-string "Arguments: " "vignettes = FALSE")))) (defun ess-r-devtools-check-with-winbuilder (&optional arg) "Interface for `devtools::check_win_XYZ()'. With prefix argument, as for arguments to `devtools::check_win_XYZ()' function." (interactive "P") (let ((type (completing-read "Release: " '("devel" "release" "oldrelease") nil t))) (ess-r-package-eval-linewise (format "devtools:::check_win_%s(%%s)\n" type) "Checking %s on CRAN's Windows server" arg '("" (read-string "Arguments: "))))) (defvar ess-r-rhub--history nil) (declare-function ess-r-check-install-package "ess-r-mode.el") (defun ess-r-rhub-check-package (&optional arg) "Interface for `rhub::check()'. With prefix ARG allow for editing of the `rhub::check_for_cran()' arguments." (interactive "P") (inferior-ess-r-force) (ess-r-check-install-package "rhub") (let* ((platforms (cons "RECOMMENDED" (ess-get-words-from-vector "rhub::platforms()$name\n"))) (platform (completing-read "Platform: " platforms nil t nil ess-r-rhub--history (car ess-r-rhub--history))) (cmd (if (string= "RECOMMENDED" platform) "rhub::check_for_cran(%s)\n" (format "rhub::check_for_cran(%%s, platforms = '%s')\n" platform))) (msg (format "Checking %%s on RHUB (%s)" platform)) ;; Solaris check is flaky and it seems that solaris check is not run on ;; CRAN itself with --as-cran options https://github.com/r-hub/rhub/issues/339 (args (cond ((string-match-p "solaris" platform) "check_args = c('--no-stop-on-test-error', '--no-vignettes')") (t "check_args = c('--as-cran', '--no-stop-on-test-error')")))) (ess-r-package-eval-linewise cmd msg arg `(,args (read-string "Arguments: " ,(concat args ", valgrind = FALSE")))))) (defun ess-r-devtools-build (&optional arg) "Interface for `devtools::build()'. With prefix ARG, build with `vignettes = FALSE'." (interactive "P") (ess-r-package-eval-linewise "devtools::build(%s)\n" "Building %s" arg '("" "vignettes = FALSE"))) (defun ess-r-devtools-test-package (&optional arg) "Interface for `devtools::test()'. With prefix argument ARG, run tests on current file only." (interactive "P") (ess-r-package-eval-linewise "devtools::test(%s)\n" "Testing %s" arg '("" ess-r-devtools--cur-file-filter))) (defun ess-r-devtools--cur-file-filter () (let ((file (or (and buffer-file-name (file-name-nondirectory buffer-file-name)) (error "Buffer not visiting a file")))) (format "filter = \"%s\"" (if (string-match "test-\\([[:alnum:]_-]+\\)\\.[rR]" file) (match-string-no-properties 1 file) (file-name-base buffer-file-name))))) (defvar ess-r-devtools-revdep-check-cmd "local({ pkg_path <- %s res <- devtools::revdep_check(pkg_path) if (file.exists(file.path(pkg_path, 'revdep'))) { save_path <- file.path(pkg_path, 'revdep') } else { save_path <- file.path(pkg_path, '.metadata', 'revdep') } devtools::revdep_check_save_summary(res, save_path) logs_path <- file.path(save_path, 'logs') if (!dir.exists(logs_path)) { dir.create(logs_path) } devtools::revdep_check_save_logs(res, logs_path) }) ") (defun ess-project-save-buffers () "Offer to save modified files in the current project. Respects `ess-save-silently', which see." (let ((cur-proj ess-r-package--info-cache)) (dolist (buf (buffer-list)) (when-let ((file (buffer-file-name buf)) (buf-proj (buffer-local-value 'ess-r-package--info-cache buf))) (when (equal cur-proj buf-proj) (ess-save-file file)))))) (defun ess-r-devtools-document-package (&optional arg) "Interface for `devtools::document()'. With prefix ARG ask for extra arguments." (interactive "P") (ess-r-package-eval-linewise "devtools::document(%s)\n" "Documenting %s" arg '("" (read-string "Arguments: ")))) (defun ess-r-devtools-install-package (&optional arg) "Interface to `devtools::install()'. By default the installation is \"quick\" with arguments quick = TRUE, upgrade = FALSE, build = FALSE. On prefix ARG \\[universal-argument] install with the default `devtools::install()' arguments." (interactive "P") (ess-r-package-eval-linewise "devtools::install(%s)\n" "Installing %s" arg '("quick = TRUE, build = FALSE, upgrade = FALSE, keep_source = TRUE" (read-string "Arguments: " "keep_source = TRUE, force = TRUE")))) (defvar ess-r-devtools--install-github-history nil) (defun ess-r-devtools-install-github (&optional arg) "Interface to `devtools::install_github()'. Asks for GitHub repository in the form of user/repo. Force re-installation when called with a prefix ARG." (interactive "P") (let ((command "devtools::install_github(%s%s)") (repo (format "'%s'" (read-string "User/Repo: " nil 'ess-r-devtools--install-github-history (car ess-r-devtools--install-github-history)))) (args (if arg (ess-r-command--build-args 0 '((read-string "Arguments: " "force = TRUE"))) ""))) (inferior-ess-r-force) (unless (derived-mode-p 'inferior-ess-mode) (display-buffer (ess-get-process-buffer) '(nil . ((inhibit-same-window . t))))) (message "Installing %s from github" repo) (ess-eval-linewise (format command repo args)))) (defun ess-r-devtools-create-package () "Interface to `devtools::create()'. Default location is determined by the first element of `ess-r-package-library-paths'." (interactive) (let* ((command "devtools::create(\"%s\")") (default-path (if (stringp ess-r-package-library-paths) ess-r-package-library-paths (car ess-r-package-library-paths))) (path (read-directory-name "Path: " default-path))) (ess-eval-linewise (format command path)))) (defun ess-r-devtools-execute-command (&optional arg) "Asks with completion for a devtools command. When called with prefix ARG asks for additional arguments." (interactive "P") (inferior-ess-r-force) (let* ((devtools-funs (ess-get-words-from-vector ".ess_devtools_functions()\n")) (fun (completing-read "Function: " devtools-funs)) (command (format "devtools::%s(%%s)\n" fun))) (ess-r-package-eval-linewise command (format "Running %s" fun) arg '("" (read-string "Arguments: "))))) ;;;*;;; Minor Mode (defcustom ess-r-package-auto-activate t "If non-nil, `ess-r-package-mode' is turned on within R packages. If `t' the minor mode auto-activates in R packages. See `ess-r-package-exclude-modes' if you wish to inhibit `ess-r-package-mode' in specific buffers." :group 'ess-r-package :type 'boolean) (defcustom ess-r-package-exclude-modes '(fundamental-mode) "A list of modes where `ess-r-package' must not be activated. The check is done with `derived-mode-p'." :group 'ess-r-package :type '(repeat symbol) :package-version '(ess "18.10")) (defcustom ess-r-package-enter-hook nil "Normal hook run on entering `ess-r-package-mode'." :group 'ess-r-package :type 'hook) (defcustom ess-r-package-exit-hook nil "Normal hook run on exiting `ess-r-package-mode'." :group 'ess-r-package :type 'hook) (defcustom ess-r-package-mode-line ;; FIXME Emacs 25.1: Use `when-let' '(:eval (let ((pkg-name (ess-r-package-name))) (when pkg-name (format " [pkg:%s]" pkg-name)))) "Mode line for ESS developer. Set this variable to nil to disable the mode line entirely." :group 'ess-r-package :type 'sexp :risky t) (defvar ess-r-package-mode-map (let ((ess-r-package-mode-map (make-sparse-keymap))) (define-key ess-r-package-mode-map "\C-c\C-w" 'ess-r-package-dev-map) ess-r-package-mode-map)) (define-minor-mode ess-r-package-mode "Minor mode for enabling R package development features. \\{ess-r-package-mode-map}" :init-value nil :keymap ess-r-package-mode-map :lighter ess-r-package-mode-line (if ess-r-package-mode (progn ;; Forward relevant R settings for interacting with inferior ;; processes from any mode (let ((vars '(ess-dialect ess-setwd-command ess-getwd-command ess-quit-function inferior-ess-reload-function))) (mapc (lambda (var) (set (make-local-variable var) (eval (cdr (assq var ess-r-customize-alist)) t))) vars)) (add-hook 'project-find-functions #'ess-r-project nil 'local) (run-hooks 'ess-r-package-enter-hook)) (remove-hook 'project-find-functions #'ess-r-project) (run-hooks 'ess-r-package-exit-hook))) (add-hook 'after-change-major-mode-hook #'ess-r-package-auto-activate) ;;;*;;; Activation (defun ess-r-package-auto-activate () "Activate developer if current file is part of a package." (when (and ess-r-package-auto-activate (or (buffer-name) default-directory) (not (eq major-mode 'minibuffer-inactive-mode)) (or ;; users probably have these in fundamental mode (member (buffer-name) '("DESCRIPTION" "NAMESPACE")) (if ess-r-package-exclude-modes (not (apply #'derived-mode-p ess-r-package-exclude-modes)) t))) (when (car (ess-r-package-info)) (ess-r-package-mode 1)))) (defun ess-r-package-re-activate () "Restart `ess-r-package-mode'. First, deactivate package mode if active, and activate if in package mode. Use this function if state of the buffer such as `default-directory' has changed." (when ess-r-package-mode (ess-r-package-mode -1)) (setq ess-r-package--info-cache nil) (ess-r-package-auto-activate)) (defvar-local ess-r--old-default-dir nil) (defun ess-r-package-default-directory-tracker (&rest _) (unless (equal ess-r--old-default-dir default-directory) (setq ess-r--old-default-dir default-directory) (ess-r-package-re-activate))) (defun ess-r-package-activate-directory-tracker () (add-hook 'after-change-functions #'ess-r-package-default-directory-tracker t t)) (add-hook 'shell-mode-hook #'ess-r-package-activate-directory-tracker t) (add-hook 'eshell-mode-hook #'ess-r-package-activate-directory-tracker t) ;; (require 'shell) (advice-add 'shell-resync-dirs :after #'ess-r-package-re-activate) ;;;*;;; Deprecated variables and functions (defun ess-developer (&optional _val) (error "As of ESS 16.04, `ess-developer' is deprecated. Use `ess-r-set-evaluation-env' instead")) (defalias 'ess-toggle-developer #'ess-developer) (define-obsolete-function-alias 'ess-r-devtools-check-package-buildwin #'ess-r-devtools-check-with-winbuilder "18.04") (define-obsolete-function-alias 'ess-r-devtools-ask #'ess-r-devtools-execute-command "18.04") (make-obsolete-variable 'ess-developer "Please use `ess-developer-select-package' and `ess-r-set-evaluation-env' instead." "16.04") (make-obsolete-variable 'ess-developer-root-file "Please use `ess-r-package-root-file' instead." "16.04") (make-obsolete-variable 'ess-developer-packages "Please use `ess-r-package-set-package' and `ess-r-set-evaluation-env' instead." "16.04") (make-obsolete-variable 'ess-developer-load-on-add-commands "Please use `ess-r-package-set-package' and `ess-r-set-evaluation-env' instead." "16.04") (make-obsolete-variable 'ess-developer-activate-in-package "Please use `ess-r-package-auto-activate' instead." "16.04") (make-obsolete-variable 'ess-developer-enter-hook "Please use `ess-r-package-enter-hook' instead." "16.04") (make-obsolete-variable 'ess-developer-exit-hook "Please use `ess-r-package-exit-hook' instead." "16.04") (provide 'ess-r-package) ;;; ess-r-package.el ends here ESS-24.01.1/lisp/ess-r-syntax.el000066400000000000000000001214201455642170100161640ustar00rootroot00000000000000;;; ess-r-syntax.el --- Utils to work with R code -*- lexical-binding: t; -*- ;; Copyright (C) 2015-2022 Free Software Foundation, Inc. ;; Author: Lionel Henry ;; Created: 12 Oct 2015 ;; Maintainer: ESS-core ;; This file is part of GNU Emacs. ;;; License: ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see ;; ;;; Commentary: ;; API is not yet stable. ;;; Code: (require 'ess-utils) (require 'regexp-opt) (eval-when-compile (require 'cl-lib)) ;;*;; Utils ;; The three following wrappers return t if successful, nil on error (defun ess-backward-sexp (&optional N) (ess-forward-sexp (- (or N 1)))) (defun ess-forward-sexp (&optional N) (or N (setq N 1)) (condition-case nil (prog1 t (goto-char (or (scan-sexps (point) N) (buffer-end N)))) (error nil))) (defun ess-up-list (&optional N) (condition-case nil (let (forward-sexp-function) (progn (up-list N) t)) (error nil))) (defun ess-backward-up-list (&optional N) (ess-up-list (- (or N 1)))) (defun ess-forward-char (&optional N) (unless (= (point) (point-max)) (forward-char (or N 1)) t)) (defun ess-backward-char (&optional N) (unless (bobp) (forward-char (- (or N 1))) t)) (defun ess-goto-char (pos) "Go to POS if it is non-nil. If POS is nil, return nil. Otherwise return position itself." (when pos (goto-char pos))) (defun ess-looking-at (regex &optional newlines) "Like `looking-at' but consumes blanks and comments first." (save-excursion (ess-skip-blanks-forward newlines) (looking-at regex))) (defmacro ess-save-excursion-when-nil (&rest body) (declare (indent 0) (debug (&rest form))) `(let ((orig-point (point))) (cond ((progn ,@body)) (t (prog1 nil (goto-char orig-point)))))) (defmacro ess-while (test &rest body) "Like `while' for TEST but return t when BODY gets executed once." (declare (indent 1) (debug (&rest form))) `(let (executed) (while ,test (setq executed t) ,@body) executed)) (defmacro ess-at-indent-point (&rest body) (declare (indent 0) (debug (&rest form))) `(save-excursion (goto-char indent-point) (back-to-indentation) (progn ,@body))) (defvar containing-sexp) (defmacro ess-at-containing-sexp (&rest body) (declare (indent 0) (debug (&rest form))) '(when (not (bound-and-true-p containing-sexp)) (error "Internal error: containing-sexp is nil or undefined")) `(save-excursion (goto-char containing-sexp) (progn ,@body))) (defmacro ess-any (&rest forms) "Evaluate all arguments and return non-nil if one of the arguments is non-nil. This is useful to trigger side-effects. FORMS follows the same syntax as arguments to `cond'." (declare (indent 0) (debug nil)) `(let ((forms (list ,@(mapcar (lambda (form) `(progn ,@form)) forms)))) (cl-some #'identity (mapcar (lambda (e) (eval e t)) forms)))) (defun ess-char-syntax (string) (char-to-string (char-syntax (string-to-char string)))) ;;*;; Tokenisation (defun ess-token-type (token) (car (nth 0 token))) (defun ess-token-value (token) (cdr (nth 0 token))) (defun ess-token-start (token) (car (nth 1 token))) (defun ess-token-end (token) (cdr (nth 1 token))) (defun ess-token-refined-type (token) (ess-token-type (ess-refine-token token))) (defun ess-token-after (&optional token) "Return next TOKEN. Cons cell containing the token type and string representation." (save-excursion (when token (goto-char (ess-token-end token))) (ess-jump-token))) (defun ess-token-before (&optional token) "Return previous TOKEN. Cons cell containing the token type and string representation." (save-excursion (when token (goto-char (ess-token-start token))) (ess-climb-token))) (defun ess-climb-token (&optional type string) (ess-save-excursion-when-nil (ess-escape-comment) (ess-skip-blanks-backward t) (let ((token (or (ess-climb-token--back) (ess-climb-token--back-and-forth) (progn (forward-char -1) (ess-token-after))))) (if (or type string) (when (ess-token= token type string) token) token)))) (defun ess-token--cons (type value) (if (eq type 'self) (cons value nil) (cons type value))) (defun ess-climb-token--back () (let* ((token-end (point)) (token-type (if (bobp) "buffer-start" (ess-climb-token--operator))) (token-value (buffer-substring-no-properties (point) token-end))) (unless (null token-type) (list (ess-token--cons token-type token-value) (cons (point) token-end))))) (defsubst ess-climb-token--char (&rest chars) (ess-while (and chars (eq (char-before) (car chars)) (ess-backward-char)) (setq chars (cdr chars)))) ;; Difficult to use regexps here because we want to match greedily ;; backward (defun ess-climb-token--operator () (when (pcase (char-before) ((or `?+ `?/ `?^ `?~ `?? `?!) (ess-backward-char)) (`?= (prog1 (ess-backward-char) (or (ess-climb-token--char ?=) (ess-climb-token--char ?!) (ess-climb-token--char ?:) (ess-climb-token--char ?>) (ess-climb-token--char ?<)))) ((or `?& `?| `?* `?@ `?$) (prog1 (ess-backward-char) (ess-climb-token--char (char-after)))) (`?< (ess-backward-char)) (`?> (prog1 (ess-backward-char) (or (ess-climb-token--char ?|) (ess-climb-token--char ?=) (ess-climb-token--char ?-) (and (looking-back "->" (- (point) 2)) (goto-char (- (point) 2)))))) (`?- (prog1 (ess-backward-char) (ess-climb-token--char ?< ?<))) (`?: (prog1 (ess-backward-char) (ess-climb-token--char ?: ?:)))) 'self)) (defun ess-climb-token--back-and-forth () (let ((limit (point))) (when (ess-skip-token-backward) (save-restriction (narrow-to-region (point) limit) (ess-token-after))))) (defun ess-skip-token-backward () (ess-save-excursion-when-nil (cond ;; Punctuation ((memq (char-before) '(?, ?\;)) (ess-backward-char)) ;; Quoting delimiters ((memq (char-syntax (char-before)) '(?\" ?$)) (ess-backward-sexp)) ;; Syntaxic delimiters ((memq (char-syntax (char-before)) '(?\( ?\))) (prog1 (ess-backward-char) ;; Also skip double brackets (ess-save-excursion-when-nil (when (let ((current-delim (char-after))) (ess-skip-blanks-backward) (and (memq (char-before) '(?\[ ?\])) (eq current-delim (char-before)))) (ess-backward-char))))) ;; Identifiers and numbers ((/= (skip-syntax-backward "w_") 0))))) (defun ess-jump-token (&optional type string) "Consume a token forward. Return a cons cell containing the token type and the token string content. Return nil when the end of the buffer is reached." (ess-save-excursion-when-nil (ess-skip-blanks-forward t) (let* ((token-start (point)) (token-type (or (ess-jump-token--regexps) (ess-jump-token--literal) (ess-jump-token--infix-op) (ess-jump-token--punctuation) (progn (forward-char) "unknown"))) (token-value (buffer-substring-no-properties token-start (point)))) (let ((token (list (ess-token--cons token-type token-value) (cons token-start (point))))) (if (or type string) (when (ess-token= token type string) token) token))))) (defun ess-jump-token--literal () (cond ;; Simply assume anything starting with a digit is a number. May be ;; too liberal but takes care of fractional numbers, integers such ;; as 10L, etc. False positives are not valid R code anyway. ((looking-at "[0-9]") (ess-forward-sexp) "number") ((or (looking-at "\\sw\\|\\s_") (eq (char-after) ?`)) (ess-forward-sexp) "identifier") ((memq (char-after) '(?\" ?\')) (ess-forward-sexp) "string"))) (defun ess-jump-token--punctuation () (or (when (= (point) (point-max)) "buffer-end") (pcase (char-after) (`?\; (forward-char) 'self) (`?, (forward-char) ;; Treat blanks after comma as part of an argument (ess-skip-blanks-forward t) ",")))) (defvar ess-r-prefix-keywords-list '("if" "for" "while" "function")) (defvar ess-r-keywords-list (append ess-r-prefix-keywords-list '("else"))) (defvar ess-r-delimiters-list '("(" ")" "{" "}" "[" "]" "[[" "]]")) (defvar ess-r-operators-list '("+" "-" "*" "/" "%%" "**" "^" "&" "&&" "|" "||" "!" "?" "~" "==" "!=" "<" "<=" ">=" ">" "=" "<-" "<<-" "->" "->>" "$" "@" ":" "::" ":::" ":=" "|>" "=>")) (defvar ess-r-keywords-re (concat (regexp-opt ess-r-keywords-list) "\\_>")) (defvar ess-r-delimiters-re (regexp-opt ess-r-delimiters-list)) (defvar ess-r-operators-re (regexp-opt ess-r-operators-list)) (defun ess-jump-token--regexps () (when (or (looking-at ess-r-keywords-re) (looking-at ess-r-delimiters-re) (looking-at ess-r-operators-re)) (goto-char (match-end 0)) 'self)) (defun ess-jump-token--infix-op () (or (when (looking-at ess-r-operators-re) (goto-char (match-end 0)) 'self) (when (eq (char-after) ?%) (ess-forward-sexp) "%infix%"))) (defun ess-refine-token (token) (let ((refined-type (pcase (ess-token-type token) ;; Parameter assignment (`"=" (save-excursion (goto-char (ess-token-start token)) (let ((containing-sexp (ess-containing-sexp-position))) (when (and containing-sexp (ess-at-containing-sexp (and (ess-token-after= "(") (ess-token-before= '("identifier" "string")))) (save-excursion (and (ess-climb-token) (ess-token-before= '("," "("))))) "param-assign")))) ;; Quoted identifiers (`"string" (when (or ;; Quoted parameter names (ess-refined-token= (ess-token-after) "param-assign") ;; Quoted call names (ess-token-after= "(")) "identifier")) ((or `"(" `")") (or (save-excursion (if (ess-token-close-delimiter-p token) (ess-climb-paired-delims nil token) (goto-char (ess-token-start token))) (when (ess-token-keyword-p (ess-token-before)) "prefixed-expr-delimiter")) ;; Fixme: probably too crude. Better handled in parser (when (ess-token= token ")") (save-excursion (ess-climb-paired-delims ")" token) (when (ess-token-before= '("identifier" "string" ")" "]" "]]" "}")) "argslist-delimiter"))))) ((or `"{" `"}") (save-excursion (unless (ess-climb-paired-delims "}" token) (goto-char (ess-token-start token))) (when (ess-refined-token= (ess-token-before) "prefixed-expr-delimiter") "prefixed-expr-delimiter")))))) (if refined-type (list (cons refined-type (ess-token-value token)) (nth 1 token)) token))) ;;;*;;; Token predicates (defun ess-token= (token &optional type string) (when (and (null type) (null string)) (error "No condition supplied")) (let ((type (if (stringp type) (list type) type)) (string (if (stringp string) (list string) string))) (and (if type (member (ess-token-type token) type) t) (if string (member (ess-token-value token) string) t)))) (defun ess-refined-token= (token type &optional string) (ess-token= (ess-refine-token token) type string)) (defun ess-token-after= (type &optional string) (ess-token= (ess-token-after) type string)) (defun ess-token-before= (type &optional string) (ess-token= (ess-token-before) type string)) (defun ess-token-open-delimiter-p (token) (string= (ess-char-syntax (ess-token-type token)) "(")) (defun ess-token-close-delimiter-p (token) (string= (ess-char-syntax (ess-token-type token)) ")")) (defun ess-token-delimiter-p (token) (or (ess-token-open-delimiter-p token) (ess-token-close-delimiter-p token))) (defun ess-token-operator-p (token &optional strict) (and (or (member (ess-token-type token) ess-r-operators-list) (string= (ess-token-type token) "%infix%")) (or (null strict) (not (ess-refined-token= token "param-assign"))))) (defun ess-token-keyword-p (token) (member (ess-token-type token) ess-r-keywords-list)) ;;*;; Point predicates (defun ess-inside-call-p (&optional call) "Return non-nil if point is in a function or indexing call." (let ((containing-sexp (or (bound-and-true-p containing-sexp) (ess-containing-sexp-position)))) (save-excursion (and (prog1 (ess-goto-char containing-sexp) (ess-climb-chained-delims)) (save-excursion (forward-char) (ess-up-list)) (or (ess-behind-call-opening-p "(") (looking-at "\\[")) (ess-inside-call-name-p call))))) (defun ess-inside-continuation-p () (unless (or (looking-at ",") (ess-behind-call-opening-p "[[(]")) (or (save-excursion (ess-jump-object) (and (not (ess-ahead-param-assign-p)) (ess-behind-operator-p))) (save-excursion (ess-climb-object) (ess-climb-operator) (and (ess-behind-operator-p) (not (ess-ahead-param-assign-p))))))) (defun ess-inside-call-name-p (&optional call) (save-excursion (ess-climb-call-name call))) (defun ess-inside-prefixed-block-p (&optional call) "Return non-nil if point is in a prefixed block. Prefixed blocks refer to the blocks following function declarations, control flow statements, etc. If CALL is not nil, check if the prefix corresponds to CALL. If nil, return the prefix." (save-excursion (ess-escape-prefixed-block call))) ;;*;; Syntactic Travellers and Predicates ;;;*;;; Blanks, Characters, Comments and Delimiters (defun ess-skip-blanks-backward (&optional newlines) "Skip blanks and newlines backward, taking end-of-line comments into account." (ess-any ((ess-skip-blanks-backward-1)) ((when newlines (ess-while (and (not (bobp)) (= (point) (line-beginning-position))) (forward-line -1) (goto-char (ess-code-end-position)) (ess-skip-blanks-backward-1)))))) (defun ess-skip-blanks-backward-1 () (and (not (bobp)) (/= 0 (skip-syntax-backward " ")))) (defun ess-skip-blanks-forward (&optional newlines) "Skip blanks and newlines forward, taking end-of-line comments into account." (ess-any ((/= 0 (skip-syntax-forward " "))) ((ess-while (and newlines (= (point) (ess-code-end-position)) (when (ess-save-excursion-when-nil ;; Handles corner cases such as point being on last line (let ((orig-point (point))) (forward-line) (back-to-indentation) (> (point) orig-point))) (skip-chars-forward " \t") t)))))) (defun ess-jump-char (char) (ess-save-excursion-when-nil (ess-skip-blanks-forward t) (when (looking-at char) (goto-char (match-end 0))))) (defun ess-escape-comment () (when (ess-inside-comment-p) (prog1 (comment-beginning) (skip-chars-backward "#+[ \t]*")))) (defun ess-ahead-closing-p () (memq (char-before) '(?\] ?\} ?\)))) (defun ess-ahead-boundary-p () (looking-back "[][ \t\n(){},]" (1- (point)))) (defun ess-escape-string () (and (nth 3 (syntax-ppss)) (ess-goto-char (nth 8 (syntax-ppss))))) (defun ess-climb-paired-delims (&optional type token) (ess-save-excursion-when-nil (let ((token (or token (ess-token-before)))) (goto-char (ess-token-end token)) (when (if type (ess-token= token type) (ess-token-delimiter-p token)) (and (ess-backward-sexp) (ess-token-after)))))) (defun ess-jump-paired-delims (&optional type token) (ess-save-excursion-when-nil (let ((token (or token (ess-token-after)))) (goto-char (ess-token-start token)) (when (if type (ess-token= token type) (ess-token-delimiter-p token)) (and (ess-forward-sexp) (ess-token-before)))))) ;;;*;;; Blocks (defun ess-block-opening-p () (save-excursion (cond ((looking-at "{")) ;; Opening parenthesis not attached to a function opens up a ;; block too. Only pick up those that are last on their line ((ess-behind-block-paren-p))))) (defun ess-block-closing-p () (save-excursion (cond ((looking-at "}")) ((looking-at ")") (forward-char) (backward-sexp) (not (looking-back (concat ess-r-name-pattern "[[:blank:]]*") (line-beginning-position))))))) (defun ess-block-p () (or (save-excursion (when containing-sexp (goto-char containing-sexp) (ess-block-opening-p))) (ess-unbraced-block-p))) ;; Parenthesised expressions (defun ess-behind-block-paren-p () (and (looking-at "(") (not (ess-ahead-attached-name-p)))) (defun ess-climb-block (&optional ignore-ifelse) (ess-save-excursion-when-nil (cond ((and (not ignore-ifelse) (ess-climb-if-else 'to-start))) ((and (eq (char-before) ?\}) (prog2 (forward-char -1) (ess-up-list -1) (ess-climb-block-prefix))))))) (defvar ess-prefixed-block-patterns (mapcar (lambda (fun) (concat fun "[ \t\n]*(")) '("function" "if" "for" "while"))) (defun ess-behind-prefixed-block-p (&optional call) (if call (looking-at (concat call "[ \t]*(")) (cl-some #'looking-at ess-prefixed-block-patterns))) (defun ess-unbraced-block-p (&optional ignore-ifelse) "This indicates whether point is in front of an unbraced prefixed block following a control flow statement. Returns position of the control flow function (if, for, while, etc)." (save-excursion (and (ess-backward-sexp) (or (and (looking-at "else\\b") (not ignore-ifelse)) (and (looking-at "(") (ess-backward-sexp) (cl-some #'looking-at ess-prefixed-block-patterns) (if ignore-ifelse (not (looking-at "if\\b")) t))) (point)))) (defun ess-climb-block-prefix (&optional call ignore-ifelse) "Climb the prefix of a prefixed block. Prefixed blocks refer to the blocks following function declarations, control flow statements, etc. Should be called either in front of a naked block or in front of the curly brackets of a braced block. If CALL not nil, check if the prefix corresponds to CALL. If nil, return the prefix." (ess-save-excursion-when-nil (or (and (not ignore-ifelse) (prog1 (and (ess-climb-if-else-call) (or (null call) (looking-at call))) (when (ess-token-after= "else") (ess-climb-token "}")))) (let ((pos (ess-unbraced-block-p ignore-ifelse))) (and (ess-goto-char pos) (if call (looking-at call) (cond ((looking-at "function") "function") ((looking-at "for") "for") ((looking-at "if") "if") ((looking-at "else") "else")))))))) (defun ess-escape-prefixed-block (&optional call) "Climb outside of a prefixed block." (let ((containing-sexp (or (bound-and-true-p containing-sexp) (ess-containing-sexp-position)))) (or (ess-save-excursion-when-nil (and (ess-goto-char containing-sexp) (looking-at "{") (ess-climb-block-prefix call))) (ess-escape-unbraced-block call)))) (defun ess-escape-unbraced-block (&optional call) (ess-save-excursion-when-nil (while (and (not (ess-unbraced-block-p)) (or (ess-escape-continuations) (ess-escape-call)))) (ess-climb-block-prefix call))) (defun ess-jump-block () (cond ;; if-else blocks ((ess-jump-if-else)) ;; Prefixed blocks such as `function() {}' ((ess-behind-prefixed-block-p) (ess-jump-prefixed-block)) ;; Naked blocks ((and (or (looking-at "{") (ess-behind-block-paren-p)) (ess-forward-sexp))))) (defun ess-jump-prefixed-block (&optional call) (ess-save-excursion-when-nil (when (ess-behind-prefixed-block-p call) (ess-forward-sexp 2) (ess-skip-blanks-forward t) (if (looking-at "{") (ess-forward-sexp) (prog1 (ess-jump-expression) (ess-jump-continuations)))))) ;;;*;;; Calls (defun ess-call-closing-p () (save-excursion (when (cond ((looking-at ")") (ess-up-list -1)) ((looking-at "]") (when (ess-up-list -1) (prog1 t (ess-climb-chained-delims))))) (ess-ahead-attached-name-p)))) (defun ess-behind-call-opening-p (pattern) (and (looking-at pattern) (ess-ahead-attached-name-p))) ;; Should be called just before the opening brace (defun ess-ahead-attached-name-p () (save-excursion (ess-climb-object))) (defun ess-ahead-param-assign-p () "Return non-nil if looking at a function argument. To be called just before the `=' sign." (ess-refined-token= (ess-token-before) "param-assign")) (defun ess-behind-arg-p () (save-excursion (ess-jump-arg))) (defun ess-behind-parameter-p () (save-excursion (ess-jump-parameter))) (defun ess-jump-parameter () (ess-save-excursion-when-nil (and (ess-jump-name) (when (looking-at "[ \t]*=\\([^=]\\)") (goto-char (match-beginning 1)) (ess-skip-blanks-forward) t)))) (defun ess-jump-arg () (ess-save-excursion-when-nil (ess-skip-blanks-forward t) (ess-any ((ess-jump-parameter)) ((ess-jump-expression)) ((ess-jump-continuations))))) (defun ess-arg-bounds () "Should be called in front of the argument." (save-excursion (let ((beg (point))) (and (ess-jump-arg) (list beg (point)))))) (defun ess-climb-call (&optional call) "Climb functions (e.g. ggplot) and parenthesised expressions." (or (ess-while (ess-save-excursion-when-nil (ess-climb-name) (and (ess-climb-chained-delims ?\]) ;; (ess-climb-expression) (if (eq (char-before) ?\)) (ess-climb-call) (ess-climb-name)) ))) (ess-save-excursion-when-nil (when (and (memq (char-before) '(?\] ?\) ?\})) (ess-backward-sexp)) (if call (and (ess-climb-name) (looking-at call))) (prog1 t (ess-climb-name)))))) (defun ess-climb-call-name (&optional call) (ess-save-excursion-when-nil (ess-jump-name) (ess-skip-blanks-forward) (and (ess-behind-call-opening-p "[[(]") (ess-climb-name) (or (null call) (looking-at call))))) (defun ess-step-to-first-arg () (let ((containing-sexp (ess-containing-sexp-position))) (cond ((ess-inside-call-p) (goto-char containing-sexp) (forward-char) t) ((ess-inside-call-name-p) (ess-jump-name) (ess-skip-blanks-forward) (forward-char) t)))) (defun ess-jump-to-next-arg () (and (ess-jump-arg) (prog1 (ess-jump-char ",") (ess-skip-blanks-forward t)))) (defun ess-jump-call () (ess-save-excursion-when-nil (or (and (ess-jump-object) (cond ((eq (char-before) ?\))) ((looking-at "\\[") (ess-jump-chained-brackets)) ((looking-at "(") (ess-forward-sexp)))) (and (looking-at "[ \t]*(") (ess-forward-sexp))))) (defun ess-behind-call-p () (save-excursion (ess-jump-object) (ess-skip-blanks-forward) (looking-at "[[(]"))) (defun ess-climb-chained-delims (&optional delim) "Should be called with point between delims, e.g. `]|['." (setq delim (if delim (list delim) '(?\] ?\)))) (ess-while (ess-save-excursion-when-nil (when (memq (char-before) delim) (ess-backward-sexp))))) (defun ess-jump-chained-brackets () (ess-while (ess-save-excursion-when-nil (when (eq (char-after) ?\[) (ess-forward-sexp))))) (defun ess-escape-call (&optional call) (let ((containing-sexp (ess-containing-sexp-position))) (if (ess-inside-call-p) (ess-save-excursion-when-nil (goto-char containing-sexp) (ess-climb-chained-delims) (and (ess-climb-name) (or (null call) (looking-at call)))) ;; At top level or inside a block, check if point is on the ;; function name. (ess-save-excursion-when-nil (let ((orig-pos (point))) (and (ess-jump-name) (looking-at "[[(]") (ess-climb-name) (or (null call) (looking-at call)) (/= (point) orig-pos))))))) (defun ess-escape-calls () (ess-while (ess-escape-call))) (defun ess-jump-inside-call () (ess-save-excursion-when-nil (when (ess-jump-name) (ess-skip-blanks-forward) (when (looking-at "(") (forward-char) t)))) (defun ess-args-bounds (&optional marker) (let ((containing-sexp (ess-containing-sexp-position))) (when (ess-inside-call-p) (save-excursion (let ((beg (1+ containing-sexp)) (call-beg (ess-at-containing-sexp (ess-climb-name) (point)))) ;; (ess-up-list) can't find its way when point is on a ;; backquoted name, so start from `beg'. (and (goto-char beg) (ess-up-list) (prog1 t (forward-char -1)) (let ((end (if marker (point-marker) (point)))) (list beg end call-beg)))))))) (defun ess-args-alist () "Return all arguments as an alist with cars set to argument names and cdrs set to the expressions given as argument. Both cars and cdrs are returned as strings." (save-excursion (when (ess-step-to-first-arg) (let (args current-arg) (while (and (setq current-arg (ess-cons-arg)) (setq args (nconc args (list current-arg))) (ess-jump-to-next-arg))) args)))) (defun ess-cons-arg () "Return a cons cell of the current argument with car set to the parameter name (nil if not specified) and cdr set to the argument expression." (save-excursion (ess-skip-blanks-forward t) (let ((param (when (ess-behind-parameter-p) (buffer-substring-no-properties (point) (prog2 (ess-jump-name) (point) (ess-jump-char "=") (ess-skip-blanks-forward))))) (arg (buffer-substring-no-properties (point) (progn (ess-jump-arg) (point))))) (cons param arg)))) ;;;*;;; Statements (defun ess-behind-operator-p (&optional strict) (ess-token-operator-p (ess-token-after) strict)) (defun ess-ahead-operator-p (&optional strict) (ess-token-operator-p (ess-token-before) strict)) (defun ess-climb-lhs (&optional no-fun-arg climb-line) (ess-save-excursion-when-nil (let ((start-line (line-number-at-pos))) (ess-climb-operator) (when (and (or climb-line (equal (line-number-at-pos) start-line)) (ess-behind-definition-op-p no-fun-arg)) (prog1 t (ess-climb-expression)))))) (defun ess-jump-lhs () (ess-save-excursion-when-nil (and (ess-jump-name) (ess-behind-definition-op-p) (ess-jump-operator)))) (defun ess-climb-operator () (when (ess-token-operator-p (ess-token-before)) (prog1 (ess-climb-token) (ess-skip-blanks-backward)))) ;; Currently doesn't check that the operator is not binary (defun ess-climb-unary-operator () (ess-save-excursion-when-nil (let ((token (ess-climb-token))) (member (ess-token-type token) '("+" "-" "!" "?" "~"))))) ;; Currently returns t if we climbed lines, nil otherwise. (defun ess-climb-continuations (&optional cascade ignore-ifelse) (let* ((start-line (line-number-at-pos)) (state (list :start-line start-line :last-line start-line :moved 0 :last-pos (point) :prev-point nil :def-op nil :expr nil))) (when (ess-while (and (<= (plist-get state :moved) 1) (or (ess-save-excursion-when-nil (and (ess-climb-operator) (ess-climb-continuations--update-state state cascade 'op) (ess-climb-expression ignore-ifelse))) (ess-climb-unary-operator)) (/= (plist-get state :last-pos) (point))) (ess-climb-continuations--update-state state cascade nil) (plist-put state :last-pos (point))) (when (and (plist-get state :prev-point) (or (= (plist-get state :moved) 3) (not (plist-get state :expr)))) (goto-char (plist-get state :prev-point))) (if (plist-get state :def-op) 'def-op (< (line-number-at-pos) (plist-get state :start-line)))))) (defun ess-climb-continuations--update-state (state cascade &optional op) ;; Climbing multi-line expressions should not count as moving up (when op (plist-put state :expr (ess-ahead-closing-p))) (let ((cur-line (line-number-at-pos))) (when (and (plist-get state :last-line) (< cur-line (plist-get state :last-line)) (or cascade (not (plist-get state :expr)))) (plist-put state :moved (1+ (plist-get state :moved))) (plist-put state :last-line cur-line))) ;; Don't update counter after climbing operator or climbing too high (when (and (not op) (<= (plist-get state :moved) 1)) (plist-put state :prev-point (point))) (when (and (ess-behind-definition-op-p) (<= (plist-get state :moved) 1)) (plist-put state :def-op t)) t) (defun ess-jump-operator () (when (ess-behind-operator-p) (ess-jump-token) (ess-skip-blanks-forward t) t)) (defun ess-jump-continuation () (and (ess-jump-operator) (ess-jump-expression))) (defun ess-jump-continuations () (let (last-pos) (when (ess-while (and (or (null last-pos) (/= (point) last-pos)) (setq last-pos (point)) (ess-jump-continuation))) ;; In calls, operators can start on newlines (let ((start-line (line-number-at-pos))) (when (ess-save-excursion-when-nil (and (ess-inside-call-p) (ess-skip-blanks-forward t) (/= (line-number-at-pos) start-line) (ess-behind-operator-p))) (ess-jump-continuations))) t))) (defun ess-ahead-continuation-p (&optional or-parameter) (or (ess-token-operator-p (ess-token-before) (not or-parameter)) (save-excursion (ess-climb-block-prefix)) (ess-token-after= "else") (save-excursion (ess-climb-if-else-call)))) (defun ess-token-definition-op-p (token strict) (and (ess-token= token '("<-" "<<-" ":=" "~" "=")) (if strict (not (ess-refined-token= token "param-assign")) t))) (defun ess-behind-definition-op-p (&optional strict) (ess-token-definition-op-p (ess-token-after) strict)) (defun ess-ahead-definition-op-p (&optional strict) (ess-token-definition-op-p (ess-token-before) strict)) (defun ess-behind-assignment-op-p () (let ((token (ess-token-after))) (and (ess-token= token '("<-" "=")) (not (ess-refined-token= token "param-assign"))))) (defun ess-escape-continuations () (ess-any ((unless (ess-ahead-boundary-p) (ess-climb-expression))) ((ess-while (ess-climb-continuations))))) (defun ess-continuations-bounds (&optional marker) (save-excursion (let ((beg (progn (ess-escape-continuations) (point)))) (when beg (ess-jump-expression) (ess-jump-continuations) (let ((end (if marker (point-marker) (point)))) (list beg end)))))) (defun ess-climb-to-top-level () (while (ess-goto-char (ess-containing-sexp-position))) (ess-escape-continuations)) ;;;*;;; Statements: Control Flow (defun ess-climb-if-else-call (&optional multi-line) "Climb if, else, and if else calls." (ess-save-excursion-when-nil (cond ((ess-climb-paired-delims ")") (when (ess-climb-token "if") ;; Check for `else if' (prog1 t (ess-save-excursion-when-nil (let ((orig-line (line-number-at-pos))) (and (ess-climb-token "else") (or multi-line (eq orig-line (line-number-at-pos))))))))) ((ess-climb-token "else"))))) (defun ess-climb-if-else-body (&optional from-else) (cond ;; Climb braced body ((ess-save-excursion-when-nil (and (when (progn (ess-skip-blanks-backward t) (eq (char-before) ?\})) (prog1 t (forward-char -1))) (ess-up-list -1)))) ;; Climb unbraced body ((when from-else (ess-save-excursion-when-nil (ess-skip-blanks-backward t) (prog1 (ess-climb-expression 'ignore-ifelse) (or (ess-climb-continuations nil 'ignore-ifelse) (ess-climb-block-prefix nil 'ignore-ifelse)))))))) (defun ess-climb-if-else (&optional to-start) "Climb horizontal as well as vertical if-else chains, with or without curly braces." ;; Don't climb if we're atop the current chain of if-else (unless (ess-token-after= "if") (ess-save-excursion-when-nil (let ((from-else (ess-token-after= "else"))) (when (and (ess-climb-if-else-body from-else) (ess-climb-if-else-call to-start)) ;; If we start from a final else and climb to another else, we ;; are in the wrong chain of if-else. In that case, ;; climb-recurse to the top of the current chain and climb ;; again to step in the outer chain. (when (save-excursion (and from-else (ess-jump-token "else") (not (ess-jump-token "if")))) (ess-climb-if-else 'to-start) (ess-climb-continuations) (ess-climb-block-prefix nil 'ignore-ifelse) (ess-climb-if-else-call nil)) (ess-maybe-climb-broken-else) (when to-start (ess-climb-if-else to-start)) t))))) ;; Broken else: if \n else (defun ess-maybe-climb-broken-else (&optional same-line) (ess-save-excursion-when-nil ;; Don't record current line if not needed (expensive operation) (let ((cur-line (when same-line (line-number-at-pos)))) (and (ess-climb-token "else") (if same-line (= cur-line (line-number-at-pos)) t))))) (defun ess-skip-curly-backward () (re-search-backward "}[ \t]*" (line-beginning-position) t)) (defun ess-jump-if-else () (let (from) (ess-while (ess-save-excursion-when-nil (ess-skip-blanks-forward t) (cond ((and (not (eq from 'if)) (ess-jump-if) (setq from 'if))) ((looking-at "else") (ess-forward-sexp) (or (ess-jump-if) (progn (ess-skip-blanks-forward t) (ess-jump-expression))) (setq from 'else)) (t nil)))))) (defun ess-jump-if () (ess-save-excursion-when-nil (ess-skip-blanks-forward t) (and (looking-at "if[ \t\n]*(") (ess-forward-sexp 2) (progn (ess-skip-blanks-forward t) (ess-jump-expression))))) ;;;*;;; Function Declarations (defun ess-behind-defun-p () (or (looking-at "function[ \t]*(") (ess-behind-enclosed-defun-p))) (defun ess-behind-enclosed-defun-p () (save-excursion (and (ess-behind-call-p) (ess-jump-inside-call) (cl-some (lambda (arg) (string-match "^function\\b" (cdr arg))) (ess-args-alist))))) ;;;*;;; Names / Objects / Expressions ;; Should climb any names, including backquoted ones or those ;; containing `@' or `$'. Difficult to achieve with regexps, but ;; skipping chars is faster anyway. (defun ess-climb-object () (ess-save-excursion-when-nil (let (climbed) (ess-skip-blanks-backward) ;; Backquoted names can contain any character (if (and (memq (char-before) '(?` ?\" ?\')) (ess-backward-sexp)) (setq climbed t) (while (cl-some (apply-partially '/= 0) `(,(skip-syntax-backward "w_") ,(skip-chars-backward "\"'"))) (setq climbed t))) ;; Recurse if we find an indexing char (let ((tok (ess-token-before))) (when (member (ess-token-type tok) '("$" "@" "::" ":::")) (goto-char (ess-token-start tok)) (ess-climb-object))) climbed))) ;; Todo: split name and object climbing (defun ess-climb-name () (ess-climb-object)) ;; This jumps both object names and atomic objects like strings or ;; numbers. (defun ess-jump-object () (cond ;; Jump over object names ((ess-jump-name)) ;; Jump over strings)) ((ess-save-excursion-when-nil (skip-chars-forward " \t") (memq (char-after) '(?\" ?\'))) (ess-forward-sexp)))) (defun ess-jump-name () (ess-save-excursion-when-nil (let (climbed) (skip-chars-forward " \t") ;; Jump over backquoted names (cond ((and (eq (char-after) ?`) (looking-back ess-r-symbol-pattern (1- (point)))) (forward-char) (setq climbed t)) ((eq (char-after) ?`) (forward-char) (when (ess-while (not (memq (char-after) '(?` ?\C-J))) (forward-char)) (setq climbed t) (forward-char))) ;; Jump over regular names ((when (/= 0 (skip-syntax-forward "w_")) ;; Maybe point was inside backticks (when (eq (char-after) ?`) (forward-char)) (setq climbed t)))) climbed))) (defun ess-climb-expression (&optional ignore-ifelse) (ess-save-excursion-when-nil (or (ess-climb-block ignore-ifelse) (ess-climb-call) (ess-climb-object)))) (defun ess-jump-expression () (or (ess-jump-block) (ess-jump-call) (ess-jump-object))) (provide 'ess-r-syntax) ;;; ess-r-syntax.el ends here ESS-24.01.1/lisp/ess-r-xref.el000066400000000000000000000146251455642170100156120ustar00rootroot00000000000000;;; ess-r-xref.el --- An xref backend for R. -*- lexical-binding: t -*- ;; Copyright (C) 2018-2020 Free Software Foundation, Inc. ;; Author: Aaron Jacobs ;; Created: 21 January 2018 ;; Maintainer: ESS-core ;; This file is part of GNU Emacs. ;;; License: ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see ;; ;;; Commentary: ;; This file contains an xref backend for `ess-r-mode'. ;;; Code: (require 'xref) (require 'ess-inf) (require 'ess-r-package) (require 'ess-tracebug) (eval-when-compile (require 'subr-x)) ;; Silence the byte compiler. OK because this file is only loaded by ess-r-mode. (declare-function inferior-ess-r-force "ess-r-mode") (defvar ess-r-xref-pkg-sources nil "Alist of R package->directory associations. Each element is a cons cell (PACKAGE . DIRECTORY). This variable is used as a cache of package->directory associations, but could be used by the users for a more refined control of package locations than `ess-r-package-library-paths'.") (defun ess-r-xref-backend () "An `xref-backend-functions' implementation for `ess-r-mode'. R's xref backend searches for `ess-r-package-library-paths' when srcrefs point to temporary locations." 'ess-r) (cl-defmethod xref-backend-identifier-at-point ((_backend (eql ess-r))) (when-let ((sym (ess-symbol-at-point))) (symbol-name sym))) (cl-defmethod xref-backend-definitions ((_backend (eql ess-r)) symbol) (when-let ((xref (ess-r-xref--xref symbol))) (list xref))) (cl-defmethod xref-backend-apropos ((_backend (eql ess-r))) ;; Not yet supported. nil) (cl-defmethod xref-backend-identifier-completion-table ((_backend (eql ess-r))) (inferior-ess-r-force) (ess-get-words-from-vector--foreground ".ess_all_functions()\n")) (defun ess-r-xref--srcref (symbol) (inferior-ess-r-force) ;; Look for `symbol' inside the package namespace (let* ((pkg (ess-r-package-name)) (pkg (if pkg (concat "\"" pkg "\"") "NULL"))) (with-current-buffer (ess-command (format ".ess_srcref(\"%s\", %s)\n" symbol pkg)) (goto-char (point-min)) (if (re-search-forward "Error" nil t) (progn (message "R srcref lookup failed:\n%s" (buffer-string)) (sit-for 1) nil) (when (re-search-forward "(" nil 'noerror) (goto-char (match-beginning 0)) (read (current-buffer))))))) (defun ess-r-xref--pkg-srcfile (symbol src-file &optional default-pkg) "Search the R package containing symbol SYMBOL for file SRC-FILE. DEFAULT-PKG is the name of the package where presumably SYMBOL is located." (let* ((pkgs (delq nil (delete-dups (or (cons default-pkg (ess-get-words-from-vector (format ".ess_fn_pkg(\"%s\")\n" symbol))) (user-error "Can't find package for symbol %s" symbol))))) (lib-dirs (cond ((stringp ess-r-package-library-paths) (list ess-r-package-library-paths)) ((listp ess-r-package-library-paths) ess-r-package-library-paths) (t (user-error "Invalid value of `ess-r-package-library-paths'")))) (loc (or (cl-loop for pkg in pkgs for dir = (assoc-default pkg ess-r-xref-pkg-sources) when (and dir (file-exists-p dir)) return (cons pkg dir)) (cl-some (lambda (dir) (cl-loop for pkg in pkgs for path = (expand-file-name pkg dir) when (file-exists-p path) return (cons pkg path))) lib-dirs))) (file (when loc (expand-file-name src-file (cdr loc))))) (when file (unless (file-readable-p file) (error "Can't read %s" file)) ;; Cache package's source directory. (unless (assoc (car loc) ess-r-xref-pkg-sources) (push loc ess-r-xref-pkg-sources)) file))) (defun ess-r-xref--xref (symbol) "Create an xref for the source file reference of R symbol SYMBOL." (when-let ((ref (ess-r-xref--srcref symbol))) (let ((file (nth 0 ref)) (line (nth 1 ref)) (col (nth 2 ref))) (or ;; 1) Result of ESS evaluation (let* ((ess-ref (gethash file ess--srcrefs)) (ess-buff (when ess-ref (ess--dbg-find-buffer (car ess-ref))))) (when ess-buff ;; FIXME: this breaks when eval is on larger spans than function (xref-make symbol (xref-make-buffer-location ess-buff (nth 2 ess-ref))))) ;; 2) Real file from R proc working directory (unless (file-name-absolute-p file) (let ((file (expand-file-name file (ess-get-process-variable 'default-directory)))) (when (file-readable-p file) (xref-make symbol (xref-make-file-location file line col))))) ;; 3) Real file from the R's working directory (unless (file-name-absolute-p file) (when-let ((wdir (car (ess-get-words-from-vector ess-getwd-command)))) (let ((file (expand-file-name file wdir))) (when (file-readable-p file) (xref-make symbol (xref-make-file-location file line col)))))) ;; 4) Real file location from the current directory (when (file-readable-p file) (xref-make symbol (xref-make-file-location file line col))) ;; 5) Temporary sources - truncate and locate in ess-r-package-library-paths (when (string-match "/\\([^/]+\\)/\\(R/.*\\)$" file) (when-let ((pkg-file (ess-r-xref--pkg-srcfile symbol (match-string 2 file) (match-string 1 file)))) (xref-make symbol (xref-make-file-location (expand-file-name pkg-file) line col)))))))) (provide 'ess-r-xref) ;;; ess-r-xref.el ends here ESS-24.01.1/lisp/ess-rd.el000066400000000000000000000416041455642170100150110ustar00rootroot00000000000000;; ess-rd.el --- Support for editing R documentation (Rd) source -*- lexical-binding: t; -*- ;; Copyright (C) 1997-2023 Free Software Foundation, Inc. ;; Author: KH ;; Created: 25 July 1997 ;; Maintainer: ESS-core ;; This file is part of GNU Emacs. ;;; License: ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see ;; ;;; Commentary: ;; ;;; Code: (eval-when-compile (require 'subr-x)) (require 'ess-help) (require 'ess-inf) ;; Silence the byte compiler, see TODO below; can we remove these? (defvar ess-help-r-sec-regex) (defvar ess-help-r-sec-keys-alist) (defvar ess-r-customize-alist) (defcustom Rd-mode-hook nil "Hook to be run when Rd mode is entered." :type 'hook :group 'ess-R :group 'ess-hooks) (define-abbrev-table 'Rd-mode-skeleton-abbrev-table '(("`ag" "\\arguments" nil :system t) ("`al" "\\alias" nil :system t) ("`au" "\\author" nil :system t) ("`bf" "\\bold" nil :system t) ("`co" "\\code" nil :system t) ("`de" "\\describe" nil :system t) ("`dn" "\\description" nil :system t) ("`dt" "\\details" nil :system t) ("`em" "\\emph" nil :system t) ("`en" "\\enumerate" nil :system t) ("`ex" "\\examples" nil :system t) ("`fi" "\\file" nil :system t) ("`fo" "\\format" nil :system t) ("`it" "\\item" nil :system t) ("`iz" "\\itemize" nil :system t) ("`kw" "\\keyword" nil :system t) ("`li" "\\link" nil :system t) ("`me" "\\method" nil :system t) ("`na" "\\name" nil :system t) ("`no" "\\note" nil :system t) ("`re" "\\references" nil :system t) ("`sa" "\\seealso" nil :system t) ("`se" "\\section" nil :system t) ("`so" "\\source" nil :system t) ("`ss" "\\subsection" nil :system t) ("`sy" "\\synopsis" nil :system t) ("`ta" "\\tabular" nil :system t) ("`ti" "\\title" nil :system t) ("`us" "\\usage" nil :system t) ("`va" "\\value" nil :system t)) "Abbrev table for R documentation keywords. All Rd mode abbrevs start with a grave accent (`)." :case-fixed t) (define-abbrev-table 'Rd-mode-abbrev-table () "Abbrev table for Rd mode." :parents (list Rd-mode-skeleton-abbrev-table)) (defvar Rd-mode-syntax-table (let ((tab (copy-syntax-table text-mode-syntax-table))) (modify-syntax-entry ?\\ "\\" tab) (modify-syntax-entry ?\{ "(}" tab) (modify-syntax-entry ?\} "){" tab) ;; Nice for editing, not for parsing ... (modify-syntax-entry ?\( "()" tab) (modify-syntax-entry ?\) ")(" tab) (modify-syntax-entry ?\[ "(]" tab) (modify-syntax-entry ?\] ")[" tab) ;; To get strings right ;; (modify-syntax-entry ?\' "\"" Rd-mode-syntax-table) (modify-syntax-entry ?\" "\"" tab) ;; To make abbrevs starting with a grave accent work ... (modify-syntax-entry ?\` "w" tab) ;; Comments (modify-syntax-entry ?\% "<" tab) (modify-syntax-entry ?\n ">" tab) tab) "Syntax table for `Rd-mode'.") (defvar Rd-mode-parse-syntax-table (let ((tab (copy-syntax-table Rd-mode-syntax-table))) ;; To make parse-partial-sexps do the thing we want for computing ;; indentations (modify-syntax-entry ?\( "_" tab) (modify-syntax-entry ?\) "_" tab) (modify-syntax-entry ?\[ "_" tab) (modify-syntax-entry ?\] "_" tab) tab) "Syntax table for parsing Rd mode.") (defvar Rd-section-names '("Rdversion" "arguments" "alias" "author" "concept" "describe" "description" "details" "docType" "encoding" "enumerate" "examples" "format" "itemize" "keyword" "name" "note" "preformatted" "references" "seealso" "section" "source" "subsection" "synopsis" "tabular" "title" "usage" "value")) (defvar Rd-keywords '( ;; the next two lines: only valid in R <= 2.8.1 ;; commented out on 2011-01-14 for ESS version 5.13: ;; "Alpha" "Gamma" "alpha" "beta" "epsilon" "lambda" "mu" "pi" "sigma" ;; "ge" "le" "left" "right" ;; "RdOpts" "R" "S3method" "S4method" "Sexpr" "abbr" "acronym" "bold" "cite" "code" "command" "cr" "dQuote" "deqn" "dfn" "dontrun" "dontshow" "donttest" "dots" "email" "emph" "enc" "env" "eqn" "figure" "file" "href" "ifelse" "if" "item" "kbd" "ldots" "linkS4class" "link" "method" "newcommand" "option" "out" "pkg" "sQuote" "renewcommand" "samp" "strong" "tab" "url" "var" "verb" ;; System macros (from /share/Rd/macros/system.Rd ): "CRANpkg" "PR" "sspace" "doi" "LaTeX" "proglang" "packageTitle" "packageDescription" "packageAuthor" "packageMaintainer" "packageDESCRIPTION" "packageIndices" )) (defvar Rd-font-lock-keywords (list (cons (concat "\\\\\\(" (mapconcat #'identity Rd-section-names "\\|") "\\>\\)") 'font-lock-constant-face) ; Rd-bold-face (cons (concat "\\\\\\(" (mapconcat #'identity Rd-keywords "\\|") "\\>\\)") 'font-lock-keyword-face) '("^#\\(ifn?def\\)\\s-+\\(\\sw+\\)" (1 font-lock-builtin-face) (2 font-lock-variable-name-face nil t)) '("^#\\(endif\\)" 1 font-lock-builtin-face)) "Additional Rd expressions to highlight.") (defvar Rd-indent-level 2 "Indentation of Rd code with respect to containing blocks.") (defvar Rd-mode-map (let ((map (make-sparse-keymap))) (define-key map "\t" #'indent-according-to-mode) (define-key map "\C-j" #'reindent-then-newline-and-indent) (define-key map "\C-m" #'reindent-then-newline-and-indent) (define-key map "\C-c\C-p" #'Rd-preview-help) (define-key map "\C-c\C-j" #'Rd-mode-insert-item) (define-key map "\C-c\C-e" #'Rd-mode-insert-skeleton) (define-key map "\C-c\C-d" #'Rd-mode-insert-data-skeleton) (define-key map "\C-c\C-f" #'Rd-font) (define-key map "\C-c\C-s" #'Rd-mode-insert-section) (define-key map "\C-c\C-n" #'ess-eval-line-visibly-and-step) (define-key map "\C-c\C-r" #'ess-eval-region) (define-key map "\C-c\C-c" #'ess-eval-region-or-function-or-paragraph-and-step) (define-key map "\C-\M-x" #'ess-eval-region-or-function-or-paragraph) (define-key map "\C-c\C-v" #'ess-display-help-on-object) (define-key map "\C-c\C-w" #'ess-switch-process) (define-key map "\C-c\C-y" #'ess-switch-to-ESS) (define-key map "\C-c\C-z" #'ess-switch-to-end-of-ESS) map) "Keymap used in Rd mode.") (defvar Rd-mode-menu (list "Rd" ["Markup [word]" Rd-font t] ["Insert Item" Rd-mode-insert-item t] ["Insert Section" Rd-mode-insert-section t] ["Insert Skeleton" Rd-mode-insert-skeleton t] ["Insert Data Skeleton" Rd-mode-insert-data-skeleton t] "-" ["Preview" Rd-preview-help t] "-" ["Eval Line" ess-eval-line-visibly-and-step t] ["Eval Region" ess-eval-region t] ["Switch to ESS Process" ess-switch-to-ESS t] ["Switch the ESS Process" ess-switch-process t] ["Switch to end{ESS Pr}" ess-switch-to-end-of-ESS t] "-" ["Toggle Abbrev Mode" abbrev-mode t] ["Toggle Auto-Fill Mode" auto-fill-mode t] "-" ["Submit Bug Report" ess-submit-bug-report t] "-" ["Describe Rd Mode" describe-mode t]) "Menu used in Rd mode.") (defvar Rd-to-help-command "R CMD Rd2txt" "Shell command for converting R documentation source to help text.") (defvar Rd-font-list '((?\C-b "\\bold{" "}") (?\C-c "\\code{" "}") (?\C-e "\\emph{" "}") (?\C-l "\\link{" "}") (?l "\\code{\\link{" "}}") (?\C-m "\\email{" "}") (?\C-q "\\eqn{" "}") (?\C-u "\\url{" "}") ) "List of \"fonts\" used by `Rd-font'. Each entry is a list. The first element is the key to activate the font. The second element is the string to insert before point, and the third element is the string to insert after point.") ;;;###autoload (define-derived-mode Rd-mode text-mode "Rd" "Major mode for editing R documentation source files. Type \\[list-abbrevs] to display the built-in abbrevs for Rd keywords.To automatically turn on the abbrev(iate) features, add the following to your Emacs configuration file: (add-hook \\='Rd-mode-hook #\\='abbrev-mode)" (setq ess-language "S" ess-dialect "R") (require 'ess-r-mode) (ess-setq-vars-local ess-r-customize-alist) (setq-local indent-line-function #'Rd-mode-indent-line) (setq fill-column 72) (setq-local comment-start-skip "\\s<+\\s-*") (setq-local comment-start "% ") (setq-local comment-end "") (setq font-lock-defaults '(Rd-font-lock-keywords nil nil)) ;; Here is a workaround for an Emacs bug related to indirect buffers and ;; spurious lockfiles that rears its ugly head with .Rd files ;; https://lists.gnu.org/archive/html/bug-gnu-emacs/2013-02/msg01368.html ;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=14328 (setq-local create-lockfiles nil) (easy-menu-define Rd-mode-menu-map Rd-mode-map "Menu keymap for Rd mode." Rd-mode-menu) (turn-on-auto-fill)) ;;;###autoload (add-to-list 'auto-mode-alist '("\\.Rd\\'" . Rd-mode)) (defun Rd-describe-major-mode () "Describe the current major mode." (declare (obsolete describe-mode "ESS 19.04")) (describe-function major-mode)) (defun Rd-mode-in-verbatim-p () "Return non-nil if in a usage, examples, or synopsis." (let ((pos (point))) (save-excursion (if (and (re-search-backward "\\\\\\(usage\\|examples\\|synopsis\\)" nil t) (re-search-forward "\\s(" nil t)) (condition-case () (progn (up-list 1) (< pos (point))) (error t)) nil)))) (defun Rd-mode-in-preprocessor-line-p () "Return non-nil if in a preprocessor line." (save-excursion (beginning-of-line) (looking-at "[ \t]*#\\(ifdef\\|endif\\)"))) (defun Rd-mode-calculate-indent () "Return appropriate indentation for current line in Rd mode." (save-excursion (beginning-of-line) (cond ((Rd-mode-in-verbatim-p) ;; Don't do anything in verbatims nil) ((Rd-mode-in-preprocessor-line-p) ;; Indent to 0 0) (t (let ((p (progn (re-search-forward "[ \t]*\\s)*" (line-end-position) t) (point)))) (if (or (< (forward-line -1) 0) (Rd-mode-in-verbatim-p)) 0 (set-syntax-table Rd-mode-parse-syntax-table) (while (and (or (looking-at "[ \t]*$") (Rd-mode-in-preprocessor-line-p)) (not (bobp))) (forward-line -1)) (re-search-forward "[ \t]*\\s)*" (line-end-position) t) (prog1 (+ (current-indentation) (* (car (parse-partial-sexp (point) p)) Rd-indent-level)) (set-syntax-table Rd-mode-syntax-table)))))))) (defun Rd-mode-indent-line () "Indent current line as Rd source." (when-let ((ic (Rd-mode-calculate-indent)) (rp (- (current-column) (current-indentation)))) (when (< ic 0) (error "Unmatched parenthesis")) (indent-line-to ic) (when (> rp 0) (move-to-column (+ ic rp))))) (defun Rd-mode-insert-item () "Insert \\item{ on a newline." (interactive) (reindent-then-newline-and-indent) (insert "\\item{") ) (defun Rd-mode-insert-section () "Insert a section from `Rd-section-names'." (interactive) (let ((s (ess-completing-read "Insert section: " (mapcar (lambda (x) (cons x x)) Rd-section-names) nil t))) (if (string= s "") (progn (insert "\\section{}{") (backward-char 2)) (insert (format "\\%s{" s))))) (defun Rd-mode-insert-skeleton () "Insert several empty Rd fields." (interactive) ;; Hmm: in theory this should be kept in sync with prompt() ;; --- maybe using prompt() [or promptClass()...] would be better anyway?! (insert "\\name{}\n") (insert "\\alias{}\n") (insert "\\title{}\n") (insert "\\description{\n}\n") (insert "\\usage{\n}\n") (insert "\\arguments{\n}\n") (insert "\\value{\n}\n") (insert "\\details{\n}\n") (insert "\\references{\n}\n") (insert "\\seealso{\n}\n") (insert "\\examples{\n}\n") (insert "\\author{}\n") (insert "\\keyword{}\n")) (defun Rd-mode-insert-data-skeleton () "Insert several empty Rd fields." (interactive) ;; Hmm: in theory this should be kept in sync with prompt() ;; --- maybe using prompt() [or promptClass()...] would be better anyway?! (insert "\\name{}\n") (insert "\\docType{}\n") (insert "\\alias{}\n") (insert "\\title{}\n") (insert "\\description{\n}\n") (insert "\\usage{\n}\n") (insert "\\format{\n}\n") (insert "\\details{\n}\n") (insert "\\source{}\n") (insert "\\references{\n}\n") (insert "\\examples{\n}\n") (insert "\\keyword{datasets}\n")) ;; This is an `easy' version of (defun TeX-font ..) in AUCtex's tex.el ; ;; see TeX-font-list and also LaTeX-font-list in latex.el (defun Rd-font (what) "Insert template for font command. WHAT determines the font to use, as specified by `Rd-font-list'." (interactive "c") ;;TeX had : (Rd-update-style) (let* ((entry (assoc what Rd-font-list)) (before (nth 1 entry)) (after (nth 2 entry))) (cond ((null entry) ;; help on possibilities : (let ((help (concat "Rd Markup (available from C-c C-f):\n\n\t" "KEY Rd-Markup\n\n" (mapconcat (lambda (entry) ;; A textual description of an ENTRY in TeX-font-list. (concat (format "%11s " (key-description (char-to-string (nth 0 entry)))) (format "%14s %-3s" (nth 1 entry) (nth 2 entry)))) Rd-font-list "\n")))) (with-output-to-temp-buffer "*Help*" (set-buffer "*Help*") (insert help)))) ((region-active-p) (save-excursion (cond ((> (mark) (point)) (insert before) (goto-char (mark)) (insert after)) (t (insert after) (goto-char (mark)) (insert before))))) (t (insert before) (save-excursion (insert after)))))) (defun Rd-preview-help (&optional via-shell) "Preview the current Rd buffer contents as help. If the current buffer is not associated with a file, create a temporary one in variable `temporary-file-directory'." (declare (advertised-calling-convention () "ESS 19.04")) (interactive "P") ; If optional VIA-SHELL is set, using `Rd-to-help-command'. (let ((file buffer-file-name) (pbuf (get-buffer-create "R Help Preview")) del-p) (unless file (setq file (make-temp-file "RD_" nil ".Rd")) (write-region (point-min) (point-max) file) (setq del-p t)) (if via-shell ;; FIXME eventually get rid of this option ;; only method in ESS <= 14.09 -- calls "R" even if in "R-devel"; slower (let ((shcmd (format "%s '%s'" Rd-to-help-command file))) (set-buffer pbuf) (erase-buffer) (ess-write-to-dribble-buffer (format "Rd-preview-help: (shell-command |%s| t)" shcmd)) (shell-command shcmd t)) ;; else directly: (ess-force-buffer-current "R process to use: ") (ess--foreground-command (format ".ess_Rd2txt(\"%s\")\n" file) pbuf) (set-buffer pbuf)) ;; FIXME(2): once got rid of via-shell, consider ;; (ess--flush-help-into-current-buffer file "tools::Rd2txt(\"%s\")\n") ;; instead of all this : (ess-setq-vars-local ess-r-customize-alist) ;; mostly cut'n'paste from ess--flush-help* (see FIXME(2)): (ess-help-underline) (ess--help-major-mode) ;; FIXME: Is this really needed? (setq ess-help-sec-regex ess-help-r-sec-regex ess-help-sec-keys-alist ess-help-r-sec-keys-alist) (goto-char (point-min)) (set-buffer-modified-p 'nil) (setq buffer-read-only t) (setq truncate-lines nil) (when del-p (delete-file file)) (unless (get-buffer-window pbuf 'visible) (display-buffer pbuf t)))) (define-obsolete-function-alias 'Rd-submit-bug-report #'ess-submit-bug-report "2018-08-16") (provide 'ess-rd) ;;; ess-rd.el ends here ESS-24.01.1/lisp/ess-rdired.el000066400000000000000000000256031455642170100156560ustar00rootroot00000000000000;;; ess-rdired.el --- prototype object browser for R, looks like dired mode. -*- lexical-binding: t; -*- ;; Copyright (C) 2002-2022 Free Software Foundation, Inc. ;; Author: Stephen Eglen ;; Created: Thu 24 Oct 2002 ;; Maintainer: ESS-core ;; This file is part of GNU Emacs. ;;; License: ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see ;; ;;; Commentary: ;; This provides a dired-like buffer for R objects. Instead of ;; operating on files, we operate on R objects in the current ;; environment. Objects can be viewed, edited, deleted, plotted and ;; so on. ;; Do "M-x R" to start an R session, then create a few variables: ;; ;; s <- sin(seq(from=0, to=8*pi, length=100)) ;; x <- c(1, 4, 9) ;; y <- rnorm(20) ;; z <- TRUE ;; Then in Emacs, do "M-x ess-rdired" and you should see the following in ;; the buffer *R dired*: ;; Name Class Length Size ;; s numeric 100 848 bytes ;; x numeric 3 80 bytes ;; y numeric 20 208 bytes ;; z logical 1 56 bytes ;; Type "?" in the buffer to see the documentation. e.g. when the ;; cursor is on the line for `s', type 'p' to plot it, or `v' to view ;; its contents in a buffer. Then type 'd' to delete it. ;; How it works. ;; Most of the hard work is done by the R routine .rdired.objects(), ;; which, when called, produces the list of objects in a tidy format. ;; This function is stored within the Lisp variable `ess-rdired-objects'. ;; Todo - How to select alternative environments? Currently only ;; shows objects in the .GlobalEnv? See BrowseEnv() in 1.6.x for way ;; of browsing other environments. ;; Todo - problem with fix -- have to wait for fix() command to return ;; before *R* buffer can be used again. This can get stuck, umm. not ;; sure what is going wrong here. Maybe add a hook to the temp buffer ;; so that when buffer is killed, we send an instruction to R to ;; update the value of the variable to the contents of the buffer. ;; This way *R* doesn't have to wait. ;; Todo - small bug in .rdired.objects -- if we have a variable called ;; `my.x', its value is replaced by the value of my.x used in the ;; sapply() calls within .rdired.objects(). ;;; Code: (require 'ess-inf) (eval-when-compile (require 'subr-x)) (defvar ess-rdired-objects ".ess.rdired()\n" "Function to call within R to print information on objects.") (defvar ess-rdired-buffer "*R dired*" "Name of buffer for displaying R objects.") (defvar ess-rdired-auto-update-timer nil "The timer object for auto updates.") (defcustom ess-rdired-auto-update-interval 5 "Seconds between refreshes of the `ess-rdired' buffer." :type '(choice (const nil :tag "No auto updates") (integer :tag "Seconds")) :group 'ess-R :package-version '(ess . "19.04")) (defvar ess-rdired-mode-map (let ((map (make-sparse-keymap))) (define-key map "d" #'ess-rdired-delete) (define-key map "x" #'ess-rdired-delete) (define-key map "v" #'ess-rdired-view) (define-key map "V" #'ess-rdired-View) (define-key map "p" #'ess-rdired-plot) (define-key map "y" #'ess-rdired-type) (define-key map "\C-c\C-s" #'ess-rdired-switch-process) (define-key map "\C-c\C-y" #'ess-switch-to-ESS) (define-key map "\C-c\C-z" #'ess-switch-to-end-of-ESS) map)) (define-derived-mode ess-rdired-mode tabulated-list-mode "Rdired" "Major mode for output from `ess-rdired'. `ess-rdired' provides a dired-like mode for R objects. It shows the list of current objects in the current environment, one-per-line. You can then examine these objects, plot them, and so on." :group 'ess-R (setq mode-name (concat "RDired " ess-local-process-name)) (setq tabulated-list-format `[("Name" 18 t) ("Class" 10 t) ("Length" 10 ess-rdired--length-predicate) ("Size" 10 ess-rdired--size-predicate)]) (add-hook 'tabulated-list-revert-hook #'ess-rdired-refresh nil t) (when (and (not ess-rdired-auto-update-timer) ess-rdired-auto-update-interval) (setq ess-rdired-auto-update-timer (run-at-time t ess-rdired-auto-update-interval #'ess-rdired-refresh))) (add-hook 'kill-buffer-hook #'ess-rdired-cancel-auto-update-timer nil t) (tabulated-list-init-header)) ;;;###autoload (defun ess-rdired () "Show R objects from the global environment in a separate buffer. You may interact with these objects, see `ess-rdired-mode' for details." (interactive) (unless (and (string= "R" ess-dialect) ess-local-process-name) (error "Not in an R buffer with attached process")) (let ((proc ess-local-process-name)) (pop-to-buffer (get-buffer-create ess-rdired-buffer)) (setq ess-local-process-name proc) (ess-rdired-mode) (ess-rdired-refresh))) (defun ess-rdired-refresh () "Refresh the `ess-rdired' buffer." (let* ((buff (get-buffer-create ess-rdired-buffer)) (proc-name (buffer-local-value 'ess-local-process-name buff)) (proc (get-process proc-name)) (out-buff (get-buffer-create " *ess-rdired-output*")) text) (when (and proc-name proc (not (process-get proc 'busy))) (ess--foreground-command ess-rdired-objects out-buff nil nil nil proc) (with-current-buffer out-buff (goto-char (point-min)) ;; Delete two lines. One filled with +'s from R's prompt ;; printing, the other with the header info from the data.frame (delete-region (point-min) (1+ (line-end-position 2))) (setq text (split-string (buffer-string) "\n" t "\n")) (erase-buffer)) (with-current-buffer buff (setq tabulated-list-entries (mapcar #'ess-rdired--tabulated-list-entries text)) (let ((entry (tabulated-list-get-id)) (col (current-column))) (tabulated-list-print) (while (not (equal entry (tabulated-list-get-id))) (forward-line)) (move-to-column col)))))) (defun ess-rdired-cancel-auto-update-timer () "Cancel the timer `ess-rdired-auto-update-timer'." (setq ess-rdired-auto-update-timer (cancel-timer ess-rdired-auto-update-timer))) (defun ess-rdired--tabulated-list-entries (text) "Return a value suitable for `tabulated-list-entries' from TEXT." (let (name class length size) (if (not (string-match-p " +\"" text)) ;; Normal-world (setq text (split-string text " " t) name (nth 0 text) text (cdr text)) ;; Else, someone has spaces in their variable names (string-match "\"\\([^\"]+\\)" text) (setq name (substring (match-string 0 text) 1) text (split-string (substring text (1+ (match-end 0))) " " t))) (setq class (nth 0 text) length (nth 1 text) size (nth 2 text)) (list name `[(,name help-echo "mouse-2, RET: View this object" action ess-rdired-view) ,class ,length ,size]))) (defun ess-rdired-edit () "Edit the object at point." (interactive) (ess-command (concat "edit(" (tabulated-list-get-id) ")\n"))) (defun ess-rdired-view (&optional _button) "View the object at point." (interactive) (ess-execute (ess-rdired-get (tabulated-list-get-id)) nil "R view" )) (defun ess-rdired-get (name) "Generate R code to get the value of the variable NAME. This is complicated because some variables might have spaces in their names. Otherwise, we could just pass the variable name directly to *R*." (concat "get(" (ess-rdired-quote name) ")") ) (defun ess-rdired-quote (name) "Quote NAME if not already quoted." (if (equal (substring name 0 1) "\"") name (concat "\"" name "\""))) (defun ess-rdired-View () "View the object at point in its own buffer. Like `ess-rdired-view', but the object gets its own buffer name." (interactive) (let ((objname (tabulated-list-get-id))) (ess-execute (ess-rdired-get objname) nil (concat "R view " objname )))) (defun ess-rdired-plot () "Plot the object on current line." (interactive) (let ((objname (tabulated-list-get-id))) (ess-eval-linewise (format "plot(%s)" (ess-rdired-get objname))))) (defun ess-rdired-type () "Run the mode() on command at point." (interactive) (let ((objname (tabulated-list-get-id)) ;; create a temp buffer, and then show output in echo area (tmpbuf (get-buffer-create "**ess-rdired-mode**"))) (if objname (progn (ess-command (concat "mode(" (ess-rdired-get objname) ")\n") tmpbuf ) (set-buffer tmpbuf) (message "%s" (concat objname ": " (buffer-substring (+ 4 (point-min)) (1- (point-max))))) (kill-buffer tmpbuf))))) (defalias 'ess-rdired-expunge #'ess-rdired-delete) (defun ess-rdired-delete () "Delete the object at point." (interactive) (let ((objname (tabulated-list-get-id))) (when (yes-or-no-p (format "Really delete %s? " objname)) (ess-eval-linewise (format "rm(%s)" (ess-rdired-quote objname)) nil nil nil t) (revert-buffer)))) (defun ess-rdired-switch-process () "Switch to examine different *R* process. If you have multiple R processes running, e.g. *R*, *R:2*, *R:3*, you can use this command to choose which R process you would like to examine. After switching to a new process, the buffer is updated." (interactive) (ess-switch-process) (ess-rdired)) (defun ess-rdired--length-predicate (A B) "Enable sorting by length in `ess-rdired' buffers. Return t if A's length is < than B's length." (let ((lenA (aref (cadr A) 2)) (lenB (aref (cadr B) 2))) (< (string-to-number lenA) (string-to-number lenB)))) (defun ess-rdired--size-predicate (A B) "Enable sorting by size in `ess-rdired' buffers. Return t if A's size is < than B's size." (let ((lenA (aref (cadr A) 3)) (lenB (aref (cadr B) 3))) (< (string-to-number lenA) (string-to-number lenB)))) (define-obsolete-function-alias 'ess-rdired-quit #'quit-window "ESS 19.04") (define-obsolete-function-alias 'ess-rdired-next-line #'forward-to-indentation "ESS 19.04") (define-obsolete-function-alias 'ess-rdired-previous-line #'backward-to-indentation "ESS 19.04") (define-obsolete-function-alias 'ess-rdired-move-to-object #'back-to-indentation "ESS 19.04") (provide 'ess-rdired) ;;; ess-rdired.el ends here ESS-24.01.1/lisp/ess-roxy.el000066400000000000000000001151261455642170100154060ustar00rootroot00000000000000;;; ess-roxy.el --- convenient editing of in-code roxygen documentation -*- lexical-binding: t; -*- ;; Copyright (C) 2009-2022 Free Software Foundation, Inc. ;; Author: Henning Redestig ;; This file is part of GNU Emacs. ;;; License: ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see ;; ;;; Commentary: ;; Lots of inspiration from doc-mode, ;; https://nschum.de/src/emacs/doc-mode/ ;; ;; Features:: ;; ;; - basic highlighting ;; - generating and updating templates from function definition and customized default template ;; - C-c C-o C-o :: update template ;; - navigating and filling roxygen fields ;; - C-c TAB, M-q, C-a, ENTER, M-h :: advised tag completion, fill-paragraph, ;; ess-roxy-move-beginning-of-line, newline-and-indent ;; - C-c C-o n,p :: next, previous roxygen entry ;; - C-c C-o C-c :: Unroxygen region. Convenient for editing examples. ;; - folding visibility using hs-minor-mode ;; - TAB :: advised ess-indent-command, hide entry if in roxygen doc. ;; - preview ;; - C-c C-o C-r :: create a preview of the Rd file as generated ;; using roxygen ;; - C-c C-o C-t :: create a preview of the Rd HTML file as generated ;; using roxygen and the tools package ;; - C-c C-o t :: create a preview of the Rd text file ;; ;; Known issues: ;; ;; - hideshow mode does not work very well. In particular, if ordinary ;; comments precede a roxygen entry, then both will be hidden in the ;; same overlay from start and not unfoldable using TAB since the ;; roxygen prefix is not present. The planned solution is implement ;; a replacement for hideshow. ;; - only limited functionality for S4 documentation. ;;; Code: (require 'ess-utils) (require 'hideshow) (require 'outline) (eval-when-compile (require 'cl-lib) (require 'subr-x)) (require 'ess-rd) (require 'ess-r-syntax) (defvar roxy-str) (defvar ess-r-mode-syntax-table) (declare-function ess-fill-args "ess-r-mode") (declare-function ess-fill-continuations "ess-r-mode") (declare-function inferior-ess-r-force "ess-r-mode") (defvar-local ess-roxy-re nil "Regular expression to recognize roxygen blocks.") ;;*;; Roxy Minor Mode (defvar ess-roxy-mode-map (let ((map (make-sparse-keymap))) (define-key map (kbd "C-c C-o h") #'ess-roxy-hide-all) (define-key map (kbd "C-c C-o n") #'ess-roxy-next-entry) (define-key map (kbd "C-c C-o p") #'ess-roxy-previous-entry) (define-key map (kbd "C-c C-o C-o") #'ess-roxy-update-entry) (define-key map (kbd "C-c C-o C-r") #'ess-roxy-preview-Rd) (define-key map (kbd "C-c C-o C-w") #'ess-roxy-preview-HTML) (define-key map (kbd "C-c C-o C-t") #'ess-roxy-preview-text) (define-key map (kbd "C-c C-o C-c") #'ess-roxy-toggle-roxy-region) (define-key map [remap back-to-indentation] #'ess-roxy-goto-end-of-roxy-comment) (define-key map [remap newline] #'ess-roxy-newline) (define-key map [remap newline-and-indent] #'ess-roxy-newline) (define-key map [remap ess-indent-command] #'ess-roxy-ess-indent-command) (define-key map [remap move-beginning-of-line] #'ess-roxy-move-beginning-of-line) (define-key map [remap beginning-of-visual-line] #'ess-roxy-move-beginning-of-line) map)) (defvar ess-roxy-font-lock-keywords nil "Cache set by `ess-roxy-generate-keywords'. Used to remove keywords added by function `ess-roxy-mode'.") (defun ess-roxy-generate-keywords () "Generate a list of keywords suitable for `font-lock-add-keywords'." (setq-local ess-roxy-font-lock-keywords `((,(concat ess-roxy-re " *\\([@\\]" (regexp-opt ess-roxy-tags-param t) "\\)\\>") (1 'font-lock-keyword-face prepend)) (,(concat ess-roxy-re " *\\(@" (regexp-opt '("param" "importFrom" "importClassesFrom" "importMethodsFrom" "describeIn") 'words) "\\)\\(?:[ \t]+\\(\\(?:\\sw+,?\\)+\\)\\)") (1 'font-lock-keyword-face prepend) (3 'font-lock-variable-name-face prepend)) (,(concat "[@\\]" (regexp-opt ess-roxy-tags-noparam t) "\\>") (0 'font-lock-variable-name-face prepend)) (,(concat ess-roxy-re) (0 'bold prepend))))) (defvar ess-roxy-fold-examples nil "Whether to fold `@examples' when opening a buffer. Use you regular key for `outline-show-entry' to reveal it.") ;;;###autoload (define-minor-mode ess-roxy-mode "Minor mode for editing ROxygen documentation." :keymap ess-roxy-mode-map (if ess-roxy-mode ;; Turn on `ess-roxy-mode': (progn (setq-local ess-roxy-re (concat "^" (string-trim comment-start) "+'")) (font-lock-add-keywords nil (ess-roxy-generate-keywords)) (add-hook 'completion-at-point-functions #'ess-roxy-complete-tag nil t) ;; Hideshow Integration (when ess-roxy-hide-show-p (hs-minor-mode 1) (when ess-roxy-start-hidden-p (ess-roxy-hide-all))) ;; Outline Integration (when ess-roxy-fold-examples (ess-roxy-hide-all-examples)) ;; Autofill (setq-local paragraph-start (concat "\\(" ess-roxy-re "\\)*" paragraph-start)) (setq-local paragraph-separate (concat "\\(" ess-roxy-re "\\)*" paragraph-separate)) (setq-local adaptive-fill-function #'ess-roxy-adaptive-fill-function) ;; Hooks (add-hook 'ess-presend-filter-functions #'ess-roxy-remove-roxy-re nil t)) ;; Turn off `ess-roxy-mode': ;; Hideshow (when (and ess-roxy-hide-show-p hs-minor-mode) (hs-show-all) (hs-minor-mode)) ;; Hooks (remove-hook 'ess-presend-filter-functions #'ess-roxy-remove-roxy-re t) (font-lock-remove-keywords nil ess-roxy-font-lock-keywords) ;; (setq-local syntax-propertize-function nil) ;; (setq-local font-lock-fontify-region-function nil) ;; (setq-local font-lock-unfontify-region-function nil) ) ;; Regardless of turning on or off we need to re-fontify the buffer: (when font-lock-mode (font-lock-flush))) ;;*;; Outline Integration (defvar ess-roxy-outline-regexp "^#+' +@examples\\|^[^#]") (defun ess-roxy-substitute-outline-regexp (command) (let ((outline-regexp (if (ess-roxy-entry-p "examples") ess-roxy-outline-regexp outline-regexp))) (funcall command))) (declare-function outline-cycle "outline-magic") (defun ess-roxy-cycle-example () (interactive) (unless (featurep 'outline-magic) (error "Please install and load outline-magic")) ;; Don't show children when cycling @examples (let ((this-command 'outline-cycle-overview)) (ess-roxy-substitute-outline-regexp #'outline-cycle))) (defun ess-roxy-show-example () (interactive) (ess-roxy-substitute-outline-regexp #'outline-show-entry)) (defun ess-roxy-hide-example () (interactive) (ess-roxy-substitute-outline-regexp #'outline-hide-entry)) (defun ess-roxy-hide-all-examples () (interactive) (save-excursion (goto-char (point-min)) (while (re-search-forward "^#+' +@examples\\b" nil t) ;; Handle edge cases (when (ess-roxy-entry-p "examples") (ess-roxy-hide-example))))) (substitute-key-definition #'outline-hide-entry #'ess-roxy-hide-example ess-roxy-mode-map outline-minor-mode-map) (substitute-key-definition #'outline-show-entry #'ess-roxy-show-example ess-roxy-mode-map outline-minor-mode-map) ;;*;; Function definitions (defun ess-back-to-roxy () "Go to roxy prefix." (end-of-line) (re-search-backward (concat ess-roxy-re " ?") (line-beginning-position)) (goto-char (match-end 0))) (defun ess-roxy-beg-of-entry () "Get point number at start of current entry, 0 if not in entry." (save-excursion (let (beg) (beginning-of-line) (setq beg -1) (if (not (ess-roxy-entry-p)) (setq beg 0) (setq beg (point))) (while (and (= (forward-line -1) 0) (ess-roxy-entry-p)) (setq beg (point))) beg))) (defun ess-roxy-in-header-p () "True if point is the description / details field." (save-excursion (let ((res t) (cont (ess-roxy-entry-p))) (beginning-of-line) (while cont (if (looking-at (concat ess-roxy-re " *[@].+")) (progn (setq res nil) (setq cont nil))) (setq cont (and (= (forward-line -1) 0) (ess-roxy-entry-p))) )res))) (defun ess-roxy-beg-of-field () "Get point number at beginning of current field, 0 if not in entry." (save-excursion (let (cont beg) (beginning-of-line) (setq beg 0) (setq cont t) (while (and (ess-roxy-entry-p) cont) (setq beg (point)) (if (looking-at (concat ess-roxy-re " *[@].+")) (setq cont nil)) (if (ess-roxy-in-header-p) (if (looking-at (concat ess-roxy-re " *$")) (progn (forward-line 1) (setq beg (point)) (setq cont nil)))) (if cont (setq cont (= (forward-line -1) 0)))) beg))) (defun ess-roxy-end-of-entry () "Get point number at end of current entry, 0 if not in entry." (save-excursion (let ((end)) (end-of-line) (setq end -1) (if (not (ess-roxy-entry-p)) (setq end 0) (setq end (point))) (while (and (= (forward-line 1) 0) (ess-roxy-entry-p)) (end-of-line) (setq end (point))) end))) (defun ess-roxy-end-of-field () "Get point number at end of current field, 0 if not in entry." (save-excursion (let ((end nil) (cont nil)) (setq end 0) (if (ess-roxy-entry-p) (progn (end-of-line) (setq end (point)))) (beginning-of-line) (forward-line 1) (setq cont t) (while (and (ess-roxy-entry-p) cont) (save-excursion (end-of-line) (setq end (point))) (if (or (and (ess-roxy-in-header-p) (looking-at (concat ess-roxy-re " *$"))) (looking-at (concat ess-roxy-re " *[@].+"))) (progn (forward-line -1) (end-of-line) (setq end (point)) (setq cont nil))) (if cont (setq cont (= (forward-line 1) 0)))) end))) (defun ess-roxy-entry-p (&optional field) "Non-nil if point is in a roxy entry. FIELD allows checking for a specific field with `ess-roxy-current-field'." (and ess-roxy-mode (save-excursion (beginning-of-line) (looking-at-p ess-roxy-re)) (or (null field) (string= (ess-roxy-current-field) field)))) (defun ess-roxy-narrow-to-field () "Go to to the start of current field." (interactive) (let ((beg (ess-roxy-beg-of-field)) (end (ess-roxy-end-of-field))) (narrow-to-region beg end))) (defun ess-roxy-extract-field () (let ((field (buffer-substring (ess-roxy-beg-of-entry) (ess-roxy-end-of-entry))) (prefix-re (ess-roxy-guess-str)) (roxy-re ess-roxy-re)) (with-temp-buffer (setq ess-roxy-re roxy-re) (insert field) (goto-char (point-min)) (while (re-search-forward prefix-re (point-max) 'noerror) (replace-match "")) (buffer-substring (point-min) (point-max))))) (defun ess-roxy-adaptive-fill-function () "Return prefix for filling paragraph or nil if not determined." (when (ess-roxy-entry-p) (let ((roxy-str (car (split-string (ess-roxy-guess-str) "'")))) (if (ess-roxy-in-header-p) (save-excursion (ess-back-to-roxy) (re-search-forward "\\([ \t]*\\)" (line-end-position) t) (concat roxy-str "' " (match-string 1))) (concat roxy-str "' " (make-string ess-indent-offset ? )))))) (defun ess-roxy-current-field () "Return the name of the field at point." (and (not (ess-roxy-in-header-p)) (save-excursion (goto-char (ess-roxy-beg-of-field)) (if (re-search-forward (concat ess-roxy-re "[ \t]+@\\([[:alpha:]]+\\)") (line-end-position) t) (match-string-no-properties 1))))) (defun ess-roxy-maybe-indent-line () "Indent line when point is in a field, but not in its first line." (when (and (not (ess-roxy-in-header-p)) (not (equal (ess-roxy-current-field) "examples")) (save-excursion (beginning-of-line) (let ((line-n (count-lines 1 (point)))) (goto-char (ess-roxy-beg-of-field)) (not (equal line-n (count-lines 1 (point))))))) (ess-back-to-roxy) (delete-region (point) (progn (skip-chars-forward " \t") (point))) (insert (make-string ess-indent-offset ? )))) (defun ess-roxy-goto-func-def () "Put point at start of function. Go to the beginning of the current one or below the current roxygen entry, error otherwise" (if (ess-roxy-entry-p) (progn (ess-roxy-goto-end-of-entry) (forward-line 1) (beginning-of-line)) (unless (looking-at-p ess-function-pattern) (beginning-of-defun)))) (defun ess-roxy-get-args-list-from-def () "Get args list for current function." (save-excursion (ess-roxy-goto-func-def) (let ((args (ess-roxy-get-function-args))) (mapcar (lambda (x) (cons x '(""))) args)))) (defun ess-roxy-insert-args (args &optional here) "Insert an ARGS list to the end of the current roxygen entry. If HERE is supplied start inputting `here'. Finish at end of line." (let* ((roxy-str (ess-roxy-guess-str)) arg-des) (if (and here (< 1 here)) (goto-char here) (ess-roxy-goto-end-of-entry) (beginning-of-line) (when (not (looking-at-p "=")) (end-of-line))) (while (stringp (caar args)) (setq arg-des (pop args)) (unless (string= (car arg-des) "") (insert (concat "\n" roxy-str " @param " (car arg-des) " ")) (insert (ess-replace-in-string (concat (car (cdr arg-des))) "\n" (concat "\n" roxy-str))) (when ess-roxy-fill-param-p (fill-paragraph)))))) (defun ess-roxy-merge-args (fun ent) "Take two args lists (alists) and return their union. The result holds all keys from both FUN and ENT but no duplicates and association from ent are preferred over entries from fun. Also, drop entries from ent that are not in fun and are associated with the empty string." (let ((res-arg nil) (arg-des)) (while (stringp (caar fun)) (setq arg-des (pop fun)) (if (assoc (car arg-des) ent) (setq res-arg (cons (cons (car arg-des) (cdr (assoc (car arg-des) ent))) res-arg)) (setq res-arg (cons (cons (car arg-des) '("")) res-arg)))) (while (stringp (caar ent)) (setq arg-des (pop ent)) (if (and (not (assoc (car arg-des) res-arg)) (not (string= (car (cdr arg-des)) ""))) (setq res-arg (cons (cons (car arg-des) (cdr arg-des)) res-arg)))) (nreverse res-arg))) (defun ess-roxy-update-entry () "Update the entry at point or the entry above the current function. Add a template empty roxygen documentation if no roxygen entry is available. The template can be customized via the variable `ess-roxy-template-alist'. The parameter descriptions can are filled if `ess-roxy-fill-param-p' is non-nil." (interactive) (unless (derived-mode-p 'ess-r-mode) (user-error "%s mode not yet supported" major-mode)) (save-excursion (let* ((args-fun (ess-roxy-get-args-list-from-def)) (args-ent (ess-roxy-get-args-list-from-entry)) (args (ess-roxy-merge-args args-fun args-ent)) (roxy-str (ess-roxy-guess-str)) (line-break "") template tag-def) (ess-roxy-goto-func-def) (when (not (= (forward-line -1) 0)) (insert "\n") (forward-line -1)) (when (and (not (looking-at "^\n")) (not (ess-roxy-entry-p))) (end-of-line) (insert "\n")) (if (ess-roxy-entry-p) (ess-roxy-insert-args args (1- (ess-roxy-delete-args))) (setq template (copy-sequence ess-roxy-template-alist)) (while (stringp (caar template)) (setq tag-def (pop template)) (if (string= (car tag-def) "param") (ess-roxy-insert-args args (point)) (if (string= (car tag-def) "description") (insert (concat line-break roxy-str " " (cdr tag-def) "\n" roxy-str)) (if (string= (car tag-def) "details") (insert (concat line-break roxy-str " " (cdr tag-def))) (insert (concat line-break roxy-str " @" (car tag-def) " " (cdr tag-def)))))) (setq line-break "\n")))))) (defun ess-roxy-goto-end-of-entry () "Put point at the bottom of the current entry or above the function at point. Return t if the point is left in a roxygen entry, otherwise nil. Error if point is not in function or roxygen entry." (when (not (ess-roxy-entry-p)) (beginning-of-defun) (forward-line -1)) (if (ess-roxy-entry-p) (progn (goto-char (ess-roxy-end-of-entry)) t) (forward-line) nil) (ess-roxy-entry-p)) (defun ess-roxy-goto-beg-of-entry () "Put point at the top of the entry at point or above the function at point. Return t if the point is left in a roxygen entry, otherwise nil. Error if point is not in function or roxygen entry." (if (not (ess-roxy-entry-p)) (progn (goto-char (nth 0 (end-of-defun))) (forward-line -1))) (if (ess-roxy-entry-p) (progn (goto-char (ess-roxy-beg-of-entry)) t) (forward-line) nil)) (defun ess-roxy-delete-args () "Remove all args from the entry at point or above the function at point. Return 0 if no deletions were made other wise the point at where the last deletion ended" (save-excursion (let* ((cont t) (field-beg 0) entry-beg entry-end field-end) (ess-roxy-goto-end-of-entry) (setq entry-beg (ess-roxy-beg-of-entry)) (setq entry-end (ess-roxy-end-of-entry)) (goto-char entry-end) (beginning-of-line) (while (and (<= entry-beg (point)) (> entry-beg 0) cont) (if (looking-at (concat ess-roxy-re " *@param")) (progn (setq field-beg (ess-roxy-beg-of-field)) (setq field-end (ess-roxy-end-of-field)) (delete-region field-beg (+ field-end 1)))) (setq cont nil) (if (= (forward-line -1) 0) (setq cont t))) field-beg))) (defun ess-roxy-get-args-list-from-entry () "Fill an args list from the entry above the function where the point is." (save-excursion (let* (args entry-beg field-beg field-end args-text arg-name desc) (if (ess-roxy-goto-end-of-entry) (progn (setq roxy-str (ess-roxy-guess-str)) (beginning-of-line) (setq entry-beg (ess-roxy-beg-of-entry)) (while (and (< entry-beg (point)) (> entry-beg 0)) (if (looking-at (concat ess-roxy-re " *@param")) (progn (setq field-beg (ess-roxy-beg-of-field)) (setq field-end (ess-roxy-end-of-field)) (setq args-text (buffer-substring-no-properties field-beg field-end)) (setq args-text (ess-replace-in-string args-text roxy-str "")) (setq args-text (ess-replace-in-string args-text "[[:space:]]*@param *" "")) ;; (setq args-text ;; (ess-replace-in-string args-text "\n" "")) (string-match "[^[:space:]]*" args-text) (setq arg-name (match-string 0 args-text)) (setq desc (replace-regexp-in-string (concat "^" (regexp-quote arg-name) " *") "" args-text)) (setq args (cons (list (concat arg-name) (concat desc)) args)))) (forward-line -1)) args) nil)))) (defun ess-roxy-toggle-roxy-region (beg end) "Toggle prefix roxygen string from BEG to END. Add the prefix if missing, remove if found. BEG and END default to the region, if active, and otherwise the entire line. This is convenient for editing example fields." (interactive "r") (unless (and beg end) (setq beg (line-beginning-position) end (line-end-position))) (ess-roxy-roxy-region beg end (ess-roxy-entry-p))) (defun ess-roxy-roxy-region (beg end &optional on) (save-excursion (let (RE to-string (roxy-str (ess-roxy-guess-str))) (narrow-to-region beg (- end 1)) (if on (progn (setq RE (concat ess-roxy-re " +?")) (setq to-string "")) (setq RE "^") (setq to-string (concat roxy-str " "))) (goto-char beg) (while (re-search-forward RE (point-max) 'noerror) (replace-match to-string)) (widen)))) (defun ess-roxy-preview () "Generate documentation for roxygen entry at point. Use a connected R session (starting one if necessary) and `ess-roxy-package' to generate the Rd code for the entry at point. Place it in a buffer and return that buffer." (unless (derived-mode-p 'ess-r-mode) (user-error "Preview only supported in R buffers, try `ess-r-devtools-document-package' instead")) (let* ((beg (ess-roxy-beg-of-entry)) (tmpf (make-temp-file "ess-roxy")) (roxy-buf (get-buffer-create " *RoxygenPreview*")) (R-old-roxy (concat "..results <- roxygen2:::roc_process(rd_roclet(), parse.files(P), \"\");" "cat(vapply(..results, function(x) roxygen2:::rd_out_cache$compute(x, format(x)), character(1)), \"\\n\")" )) (R-new-roxy (concat "..results <- roc_proc_text(rd_roclet(), readChar(P, file.info(P)$size));" "cat(vapply(..results, format, character(1)), \"\\n\")" )) (out-rd-roclet (cond ((string= "roxygen" ess-roxy-package) "make.Rd2.roclet()$parse") ;; must not line break strings to avoid getting +s in the output ((string= "roxygen2" ess-roxy-package) (concat "(function(P) { if(packageVersion('roxygen2') < '3.0.0') {" R-old-roxy "} else {" R-new-roxy "} })")) (t (error "Need to hard code the roclet output call for roxygen package '%s'" ess-roxy-package))))) (when (= beg 0) (error "Point is not in a Roxygen entry")) (save-excursion (goto-char (ess-roxy-end-of-entry)) (forward-line 1) (if (end-of-defun) (append-to-file beg (point) tmpf) (while (and (forward-line 1) (not (looking-at-p "^$")) (not (eobp)) (not (looking-at-p ess-roxy-re)))) (append-to-file beg (point) tmpf)) (inferior-ess-r-force) (ess-force-buffer-current) (unless (ess-boolean-command (concat "print(suppressWarnings(require(" ess-roxy-package ", quietly=TRUE)))\n")) (error (concat "Failed to load the " ess-roxy-package " package; " "in R, try install.packages(\"" ess-roxy-package "\")"))) (ess-command (concat out-rd-roclet "(\"" tmpf "\")\n") roxy-buf) (with-current-buffer roxy-buf ;; Kill characters up to % in case we missed stripping prompts ;; or +'s: (goto-char (point-min)) (when (re-search-forward "%" (line-end-position) t) (backward-char) (delete-region (line-beginning-position) (point))))) (delete-file tmpf) roxy-buf)) (defun ess-roxy-preview-HTML (&optional visit-instead-of-browse) "Use a (possibly newly) connected R session and the roxygen package to generate a HTML page for the roxygen entry at point and open that buffer in a browser. Visit the HTML file instead of showing it in a browser if `visit-instead-of-browse' is non-nil." (interactive "P") (let* ((roxy-buf (ess-roxy-preview)) (rd-tmp-file (make-temp-file "ess-roxy-" nil ".Rd")) (html-tmp-file (make-temp-file "ess-roxy-" nil ".html")) (rd-to-html (concat "Rd2HTML(\"" rd-tmp-file "\",\"" html-tmp-file "\", stages=c(\"render\"))")) ) (with-current-buffer roxy-buf (set-visited-file-name rd-tmp-file) (save-buffer) (kill-buffer roxy-buf)) (ess-force-buffer-current) (ess-command "print(suppressWarnings(require(tools, quietly=TRUE)))\n") (if visit-instead-of-browse (progn (ess-command (concat rd-to-html "\n")) (find-file html-tmp-file)) (ess-command (concat "browseURL(" rd-to-html ")\n"))))) (defun ess-roxy-preview-text () "Use the connected R session and the roxygen package to generate the text help page of the roxygen entry at point." (interactive) (with-current-buffer (ess-roxy-preview) (Rd-preview-help))) (defun ess-roxy-preview-Rd (&optional name-file) "Preview Rd for the roxygen entry at point. Use the connected R session and the roxygen package to generate the Rd code for the roxygen entry at point. If called with a non-nil NAME-FILE (\\[universal-argument]), also set the visited file name of the created buffer to facilitate saving that file." (interactive "P") (let ((roxy-buf (ess-roxy-preview))) (pop-to-buffer roxy-buf) (if name-file (save-excursion (goto-char 1) (search-forward-regexp "name{\\(.+\\)}") (set-visited-file-name (concat (match-string 1) ".Rd")))) (Rd-mode) ;; why should the following be needed here? [[currently has no effect !!]] ;; usually in a *.Rd file fontification happens automatically (font-lock-ensure))) (defun ess-roxy-guess-str (&optional not-here) "Guess the prefix used in the current roxygen block. If NOT-HERE is non-nil, guess the prefix for nearest roxygen block before the point." (save-excursion (if (ess-roxy-entry-p) (progn (goto-char (line-beginning-position)) (search-forward-regexp ess-roxy-re)) (if not-here (search-backward-regexp ess-roxy-re))) (if (or not-here (ess-roxy-entry-p)) (match-string 0) (if (derived-mode-p 'ess-r-mode) ess-roxy-str (concat (string-trim comment-start) "'"))))) (defun ess-roxy-hide-block () "Hide current roxygen comment block." (interactive) (save-excursion (let ((end-of-entry (ess-roxy-end-of-entry)) (beg-of-entry (ess-roxy-beg-of-entry))) (hs-hide-block-at-point nil (list beg-of-entry end-of-entry))))) (defun ess-roxy-toggle-hiding () "Toggle hiding/showing of a block. See `hs-show-block' and `ess-roxy-hide-block'." (interactive) (hs-life-goes-on (if (hs-overlay-at (line-end-position)) (hs-show-block) (ess-roxy-hide-block)))) (defun ess-roxy-show-all () "Hide all Roxygen entries in current buffer." (interactive) (ess-roxy-hide-all t)) (defun ess-roxy-hide-all (&optional show) "Hide all Roxygen entries in current buffer." (interactive) (when (not ess-roxy-hide-show-p) (user-error "First enable hide-show with `ess-roxy-hide-show-p'")) (hs-life-goes-on (save-excursion (goto-char (point-min)) (while (re-search-forward (concat ess-roxy-re) (point-max) t 1) (let ((end-of-entry (ess-roxy-end-of-entry))) (if show (hs-show-block) (ess-roxy-hide-block)) (goto-char end-of-entry) (forward-line 1)))))) (defun ess-roxy-previous-entry () "Go to beginning of previous Roxygen entry." (interactive) (if (ess-roxy-entry-p) (progn (goto-char (ess-roxy-beg-of-entry)) (forward-line -1))) (search-backward-regexp ess-roxy-re (point-min) t 1) (goto-char (ess-roxy-beg-of-entry))) (defun ess-roxy-next-entry () "Go to beginning of next Roxygen entry." (interactive) (if (ess-roxy-entry-p) (progn (goto-char (ess-roxy-end-of-entry)) (forward-line 1))) (search-forward-regexp ess-roxy-re (point-max) t 1) (goto-char (ess-roxy-beg-of-entry))) (defun ess-roxy-get-function-args () "Return the arguments specified for the current function as a list of strings. Assumes point is at the beginning of the function." (save-excursion (let ((args-txt (buffer-substring-no-properties (progn (search-forward-regexp "\\([=,-]+ *function *\\|^\s*function\\)" nil nil 1) (+ (point) 1)) (progn (ess-roxy-match-paren) (point))))) (setq args-txt (replace-regexp-in-string "#+[^\"']*\n" "" args-txt)) (setq args-txt (replace-regexp-in-string "([^)]+)" "" args-txt)) (setq args-txt (replace-regexp-in-string "=[^,]+" "" args-txt)) (setq args-txt (replace-regexp-in-string "[ \t\n]+" "" args-txt)) (split-string args-txt ",")))) (defun ess-roxy-match-paren () "Go to the matching parenthesis." (cond ((looking-at "\\s\(") (forward-list 1) (backward-char 1)) ((looking-at "\\s\)") (forward-char 1) (backward-list 1)))) (defun ess-roxy-complete-tag () "Complete the tag at point." (let ((bounds (ess-bounds-of-symbol))) (when (and bounds (save-excursion (goto-char (car bounds)) (eq (following-char) ?@))) (list (1+ (car bounds)) (cdr bounds) (append ess-roxy-tags-noparam ess-roxy-tags-param))))) (defun ess-roxy-tag-completion () "Completion data for Emacs >= 24." (when (save-excursion (re-search-backward "@\\<\\(\\w*\\)" (line-beginning-position) t)) (let ((beg (match-beginning 1)) (end (match-end 1))) (when (and end (= end (point))) (list beg end (append ess-roxy-tags-noparam ess-roxy-tags-param) :exclusive 'no))))) (defun ess-roxy-remove-roxy-re (string) "Remove `ess-roxy-str' from STRING before sending to R process. Useful for sending code from example section. This function is placed in `ess-presend-filter-functions'." ;; In the future we might want to detect chunks between markdown ;; fences and strip everything that comes before `@examples` (if (ess-roxy--all-prefixed string) (replace-regexp-in-string (concat ess-roxy-re "\\s-*") "" string) string)) (defun ess-roxy--all-prefixed (string) (let ((ess-roxy-re-lexical ess-roxy-re)) (with-temp-buffer (insert string) (goto-char 0) (while (and (looking-at-p ess-roxy-re-lexical) (re-search-forward "\n" nil t))) (looking-at-p ess-roxy-re-lexical)))) (defun ess-roxy-find-par-end (stop-point &rest stoppers) (mapc #'(lambda (stopper) (when (and (> stop-point (point)) (save-excursion (re-search-forward stopper stop-point t))) (setq stop-point (match-beginning 0)))) stoppers) (save-excursion (goto-char stop-point) (line-end-position 0))) ;;*;; Advices (defmacro ess-roxy-with-filling-context (examples &rest body) "Setup context (e.g. `comment-start') for filling roxygen BODY. EXAMPLES should be non-nil if filling an example block." (declare (indent 2) (debug (&rest form))) `(let ((comment-start (concat ess-roxy-re "[ \t]+#")) (comment-start-skip (concat ess-roxy-re "[ \t]+# *")) (comment-use-syntax nil) (adaptive-fill-first-line-regexp (concat ess-roxy-re "[ \t]*")) (paragraph-start (concat "\\(" ess-roxy-re "\\(" paragraph-start "\\|[ \t]*@" "\\)" "\\)\\|\\(" paragraph-start "\\)")) (temp-table (if ,examples (make-syntax-table ess-r-mode-syntax-table) Rd-mode-syntax-table))) (when ,examples ;; Prevent the roxy prefix to be interpreted as comment or string ;; starter (modify-syntax-entry ?# "w" temp-table) (modify-syntax-entry ?' "w" temp-table)) ;; Neutralize (comment-normalize-vars) because it modifies the ;; comment-start regexp in such a way that paragraph filling of ;; comments in @examples fields does not work (cl-letf (((symbol-function 'comment-normalize-vars) #'ignore)) (with-syntax-table temp-table ,@body)))) (defun ess-roxy-ess-indent-command (&optional whole-exp) "Hide this block if we are at the beginning of the line. Else call `ess-indent-command'." (interactive "P") (if (and (bolp) (ess-roxy-entry-p) ess-roxy-hide-show-p) (progn (ess-roxy-toggle-hiding)) (ess-indent-command whole-exp))) (defun ess--roxy-fill-block (fun &optional args) "Fill a roxygen block. FUN should be a filling function and ARGS gets passed to it." (let* ((saved-pos (point)) (par-start (save-excursion (if (save-excursion (and (backward-paragraph) (forward-paragraph) (<= (point) saved-pos))) (line-beginning-position) (progn (backward-paragraph) (point))))) (par-end (ess-roxy-find-par-end (save-excursion (forward-paragraph) (point)) (concat ess-roxy-re "[ \t]*@examples\\b") "^[^#]"))) ;; Refill the whole structural paragraph sequentially, field by ;; field, stopping at @examples (ess-roxy-with-filling-context nil (save-excursion (save-restriction (narrow-to-region par-start par-end) (goto-char (point-min)) (while (< (point) (point-max)) (ess-roxy-maybe-indent-line) (apply fun args) (forward-paragraph))))))) (defun ess-r--fill-paragraph (orig-fun &rest args) "ESS fill paragraph for R mode. Overrides `fill-paragraph' which is ORIG-FUN when necessary and passes ARGS to it." (cond ;; Regular case ((not (derived-mode-p 'ess-r-mode)) (apply orig-fun args)) ;; Filling of code comments in @examples roxy field ((and (ess-roxy-entry-p) (save-excursion (ess-roxy-goto-end-of-roxy-comment) (looking-at "#"))) (ess-roxy-with-filling-context t (apply orig-fun args))) ((and (not (ess-roxy-entry-p)) (ess-inside-comment-p)) (apply orig-fun args)) ;; Filling of call arguments with point on call name ((and ess-fill-calls (ess-inside-call-name-p)) (save-excursion (skip-chars-forward "^([") (forward-char) (ess-fill-args))) ;; Filling of continuations ((and ess-fill-continuations (ess-inside-continuation-p)) (ess-fill-continuations)) ;; Filling of call arguments ((and ess-fill-calls (ess-inside-call-p)) (ess-fill-args)) ;; Filling of roxy blocks ((ess-roxy-entry-p) (ess--roxy-fill-block orig-fun args)) (t (apply orig-fun args)))) (advice-add 'fill-paragraph :around #'ess-r--fill-paragraph) (defun ess-roxy-move-beginning-of-line (arg) "Move point to the beginning of the current line or roxygen comment. If not in a roxygen comment, call `move-beginning-of-line', which see for ARG. If in a roxygen field, leave point at the end of a roxygen comment. If already there, move to the beginning of the line." (interactive "^p") (if (ess-roxy-entry-p) (let ((pos (point))) (ess-roxy-goto-end-of-roxy-comment) (when (eql (point) pos) (move-beginning-of-line nil))) (move-beginning-of-line arg))) (defun ess-roxy-goto-end-of-roxy-comment () "Leave point at the end of a roxygen comment. If not in a roxygen entry, call `back-to-indentation'." (interactive) (if (ess-roxy-entry-p) (progn (end-of-line) (re-search-backward (concat ess-roxy-re " *") (line-beginning-position) t) (goto-char (match-end 0))) (back-to-indentation))) (defun ess-roxy-indent-new-comment-line () (if (not (ess-roxy-entry-p)) (indent-new-comment-line) (ess-roxy-indent-on-newline))) (define-obsolete-function-alias 'ess-roxy-newline-and-indent #'ess-roxy-newline "ESS 19.04") (defun ess-roxy-newline () "Start a newline and insert the roxygen prefix. Only do this if in a roxygen block and `ess-roxy-insert-prefix-on-newline' is non-nil." (interactive) (if (and (ess-roxy-entry-p) ess-roxy-insert-prefix-on-newline) (ess-roxy-indent-on-newline) (newline nil t))) (defun ess-roxy-indent-on-newline () "Insert a newline in a roxygen field." (cond ;; Point at beginning of first line of entry; do nothing ((= (point) (ess-roxy-beg-of-entry)) (newline-and-indent)) ;; Otherwise: skip over roxy comment string if necessary and then ;; newline and then inset new roxy comment string (t (let ((point-after-roxy-string (save-excursion (forward-line 0) (ess-back-to-roxy) (point)))) (goto-char (max (point) point-after-roxy-string))) (newline-and-indent) (insert (concat (ess-roxy-guess-str t) " "))))) (defun ess-roxy-cpp-fill-paragraph (&rest _args) "Advice for `c-fill-paragraph' that accounts for roxygen comments." (cond ;; Fill roxy @example's. ((ess-roxy-entry-p "examples") (ess--roxy-fill-block 'fill-paragraph) nil) ;; Fill roxy entries. ((ess-roxy-entry-p) (ess--roxy-fill-block 'fill-paragraph) nil) ;; Return t to signal to go on to `c-fill-paragraph'. (t t))) (advice-add 'c-fill-paragraph :before-while #'ess-roxy-cpp-fill-paragraph) (defun ess-roxy-enable-in-cpp () "Enable `ess-roxy-mode' in C++ buffers in R packages." (when (and (fboundp 'ess-r-package-project) (ess-r-package-project)) (ess-roxy-mode))) (with-eval-after-load "cc-mode" (add-hook 'c++-mode-hook #'ess-roxy-enable-in-cpp)) (defun ess-roxy--region-p (beg end) (when ess-roxy-re (save-excursion (goto-char beg) (catch 'ess-r-not-roxy (while (< (point) end) (unless (looking-at-p ess-roxy-re) (throw 'ess-r-not-roxy nil)) (forward-line)) t)))) (provide 'ess-roxy) ;;; ess-roxy.el ends here ESS-24.01.1/lisp/ess-s-lang.el000066400000000000000000000530341455642170100155650ustar00rootroot00000000000000;;; ess-s-lang.el --- Support for editing S source code -*- lexical-binding: t; -*- ;; Copyright (C) 1989-2022 Free Software Foundation, Inc. ;; Author: A.J. Rossini ;; Created: 26 Aug 1997 ;; Maintainer: ESS-core ;; This file is part of GNU Emacs. ;;; License: ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see ;; ;;; Commentary: ;; Code for general editing S source code (specializes to S, S+, R). ;;; Code: (require 'ess-mode) (require 'ess-help) (require 'ess-inf) (declare-function speedbar-add-supported-extension "speedbar" (extension)) ; Configuration variables (defvar S-syntax-table (let ((S-syntax-table (make-syntax-table))) (modify-syntax-entry ?\\ "\\" S-syntax-table) (modify-syntax-entry ?+ "." S-syntax-table) (modify-syntax-entry ?- "." S-syntax-table) (modify-syntax-entry ?= "." S-syntax-table) (modify-syntax-entry ?% "." S-syntax-table) (modify-syntax-entry ?< "." S-syntax-table) (modify-syntax-entry ?> "." S-syntax-table) (modify-syntax-entry ?& "." S-syntax-table) (modify-syntax-entry ?| "." S-syntax-table) (modify-syntax-entry ?\' "\"" S-syntax-table) (modify-syntax-entry ?\" "\"" S-syntax-table) (modify-syntax-entry ?# "<" S-syntax-table) ; open comment (modify-syntax-entry ?\n ">" S-syntax-table) ; close comment ;;(modify-syntax-entry ?. "w" S-syntax-table) ; "." used in S obj names (modify-syntax-entry ?. "_" S-syntax-table) ; see above/below, ; plus consider separation. (modify-syntax-entry ?$ "_" S-syntax-table); foo$comp = 1 symbol(completion) (modify-syntax-entry ?@ "_" S-syntax-table); foo@slot = 1 symbol(completion) (modify-syntax-entry ?_ "_" S-syntax-table) (modify-syntax-entry ?: "_" S-syntax-table) (modify-syntax-entry ?* "." S-syntax-table) (modify-syntax-entry ?< "." S-syntax-table) (modify-syntax-entry ?> "." S-syntax-table) (modify-syntax-entry ?/ "." S-syntax-table) S-syntax-table) "Syntax table for S code." ) (defvar S-editing-alist '((paragraph-start . (concat "\\s-*$\\|" page-delimiter)) (paragraph-separate . (concat "\\s-*$\\|" page-delimiter)) (paragraph-ignore-fill-prefix . t) ;;(comment-indent-function . 'S-comment-indent) ;;(ess-comment-indent . 'S-comment-indent) ;;(ess-calculate-indent . 'ess-calculate-indent) ;;(ess-keep-dump-files . 'ask) ;; For Changelog add, require ' ' before <- : "attr<-" is a function name : (add-log-current-defun-header-regexp . "^\\(.+\\)\\s-+<-[ \t\n]*function")) "General options for S and S+ source files.") (defvar inferior-S-language-start '(concat "options(" "STERM='" ess-STERM "'" ", str.dendrogram.last=\"'\"" (if ess-editor (concat ", editor='" ess-editor "'")) (if ess-pager (concat ", pager='" ess-pager "', help.pager='" ess-pager "'")) ", show.error.locations=TRUE" ")") "S language expression for startup -- default for all S dialects.") (defconst S-common-cust-alist '((ess-language . "S") (inferior-ess-exit-command . "q()\n") (inferior-ess-language-start . (eval inferior-S-language-start)) (comint-use-prompt-regexp . t) ;;use fields if nil (comint-process-echoes . t) ;; these prompt are the same for all S-languages As long as custom prompt ;; ends in inferior-ess-primary-prompt everything should work as expected. (inferior-ess-primary-prompt . "> ") ;; (inferior-ess-secondary-prompt . "[+:] ") ;; catch Selection: and alike (inferior-ess-secondary-prompt . "+ ") ;; catch Selection: and alike (comment-start . "#") (comment-add . 1) (comment-start-skip . "#+ *") (comment-use-syntax . t) ; see log for bug report 2013-06-07 (comment-column . 40) (ess-no-skip-regexp . (concat "^ *@\\|" (default-value 'ess-no-skip-regexp))) ;; inferior-ess-prompt is used by comint for navigation, only if ;; comint-use-prompt-regexp is t; (transcript-mode also relies on this regexp) (inferior-ess-prompt . inferior-S-prompt) (ess-getwd-command . "getwd()\n") (ess-setwd-command . "setwd('%s')\n") (ess-funargs-command . ".ess_funargs(\"%s\")\n") (fill-nobreak-predicate . 'ess-inside-string-p) (ess-execute-screen-options-command . "options(width=%d, length=99999)\n") (font-lock-defaults . '(ess-build-font-lock-keywords nil nil ((?\. . "w") (?\_ . "w"))))) "S-language common settings for all -customize-alist.") (defconst S+common-cust-alist (append '((ess-suffix . "S") (ess-help-sec-regex . ess-help-S+-sec-regex) (ess-help-sec-keys-alist . ess-help-S+sec-keys-alist) (ess-change-sp-regexp . ess-S+-change-sp-regexp) (ess-function-pattern . ess-s-function-pattern) (ess-function-template . " <- \n#\nfunction()\n{\n\n}\n") (ess-dump-filename-template . (replace-regexp-in-string "S$" ess-suffix ; in the one from custom: ess-dump-filename-template-proto)) (ess-traceback-command . "traceback()\n") (ess-mode-editing-alist . S-editing-alist) (ess-dumped-missing-re . "\\(\\(<-\\|=\\)\nDumped\n\\'\\)\\|\\(\\(<-\\|=\\)\\(\\s \\|\n\\)*\\'\\)") (ess-syntax-error-re . "\\(Syntax error: .*\\) at line \\([0-9]*\\), file \\(.*\\)$") (inferior-ess-objects-command . inferior-Splus-objects-command) (ess-describe-object-at-point-commands . 'ess-S-describe-object-at-point-commands) (ess-editor . S-editor) (ess-pager . S-pager)) S-common-cust-alist) "Common settings for all S+<*>-customize-alist." ) ;;; Changes from S to S-PLUS 3.x. (standard S3 should be in ess-s-lang!). (defconst ess-help-S+sec-keys-alist '((?a . "ARGUMENTS:") (?b . "BACKGROUND:") (?B . "BUGS:") (?d . "DESCRIPTION:") (?D . "DETAILS:") (?e . "EXAMPLES:") (?n . "NOTE:") (?O . "OPTIONAL ARGUMENTS:") (?R . "REQUIRED ARGUMENTS:") (?r . "REFERENCES:") (?s . "SEE ALSO:") (?S . "SIDE EFFECTS:") (?u . "USAGE:") (?v . "VALUE:")) "Alist of (key . string) pairs for use in section searching.") ;;; `key' indicates the keystroke to use to search for the section heading ;;; `string' in an S help file. `string' is used as part of a ;;; regexp-search, and so specials should be quoted. ;; S ver.3 (NOT S-Plus) (defconst ess-help-S3-sec-keys-alist '((?a . "ARGUMENTS:") (?b . "BACKGROUND:") (?B . "BUGS:") (?d . "DESCRIPTION:") (?D . "DETAILS:") (?e . "EXAMPLES:") (?n . "NOTE:") (?r . "REFERENCES:") (?s . "SEE ALSO:") (?S . "SIDE EFFECTS:") (?u . "USAGE:") (?v . "VALUE:")) "Help section keys for S ver.3.") ;; S ver.4 (NOT S-Plus) (defconst ess-help-S4-sec-keys-alist '((?a . "ARGUMENTS:") (?b . "BACKGROUND:") (?B . "BUGS:") (?d . "DESCRIPTION:") (?D . "DETAILS:") (?e . "EXAMPLES:") (?n . "NOTE:") (?r . "REFERENCES:") (?s . "SEE ALSO:") (?S . "SIDE EFFECTS:") (?u . "USAGE:") (?v . "VALUE:")) "Help section keys for S4.") (defconst ess-help-S+-sec-regex "^[A-Z.]+:$" "Reg(ular) Ex(pression) of section headers in help file.") ; Function Definitions (defun S-comment-indent () "Indentation for S comments." (if (or (looking-at "###") (and (looking-at "#!") (= 1 (line-number-at-pos)))) (current-column) (if (looking-at "##") (let ((tem (when ;; FIXME ess-calculate-indent is R specific (fboundp 'ess-calculate-indent) (ess-calculate-indent)))) (if (listp tem) (car tem) tem)) (skip-chars-backward " \t") (max (if (bolp) 0 (1+ (current-column))) comment-column)))) ;;*;; S/R Pretty-Editing (defun ess-fix-comments (&optional dont-query verbose) "Fix buffer so that single-line comments start with at least '##', and ensure space before subsequent text." (interactive "P") (ess-replace-regexp-dump-to-src "#\\([A-Za-z0-9]\\)" "# \\1" nil verbose) (ess-replace-regexp-dump-to-src "^\\([ \t]*#\\)\\([^#]\\)" "\\1#\\2" dont-query verbose)) (defun ess-dump-to-src (&optional dont-query verbose) "Make the change in an S - dump() file to improve human readability. Optional arguments DONT-QUERY and VERBOSE are passed to `ess-replace-regexp-dump-to-src'." (interactive "P") (ess-replace-regexp-dump-to-src "^\"\\([a-z.][a-z.0-9]*\\)\" *<-\n" "\n\\1 <- " dont-query verbose)) (defun ess-num-var-round (&optional dont-query verbose) "Round endings like 000000 and 99999. Optional argument DONT-QUERY means do not query. Optional argument VERBOSE gives more verbose output." (interactive "P") (save-excursion (goto-char (point-min)) (let ((num 0) (str "") (rgxp "000000+[1-9]?[1-9]?\\>") (to "")) (if dont-query (ess-rep-regexp rgxp to nil nil verbose) (query-replace-regexp rgxp to nil)) (while (< num 9) (setq str (concat (int-to-string num) "999999+[0-8]*")) (if (and (numberp verbose) (> verbose 1)) (message (format "\nregexp: '%s'" str))) (goto-char (point-min)) (ess-rep-regexp str (int-to-string (1+ num)) 'fixedcase 'literal verbose) (setq num (1+ num)))))) (defun ess-fix-dot (before-chars &optional dont-query verbose) "Remove trailing decimal '.' (\"dot\"), before BEFORE-CHARS. Optional argument DONT-QUERY and VERBOSE get passed to `ess-replace-regexp-dump-to-src'." ;; typically, before-chars = "]:" or more (ess-replace-regexp-dump-to-src (concat "\\([0-9]\\)\\.\\( *[" before-chars "]\\)") ;; 111 ^ "\\1\\2" dont-query verbose)) (defun ess-fix-dot-1 (&optional do-query verbose) "Remove trailing decimal '.' (\"dot\"), before ':' or ']', i.e., in cases where it's ugly and nonsense. DO-QUERY(prefix) asks before replacing." (interactive "P") (ess-fix-dot "]:" (not do-query) verbose)) (defun ess-fix-dot-more (&optional dont-query verbose) "Remove trailing decimal '.' (\"dot\", typically from S+) in more cases than `ess-fix-dot-1'." (interactive "P") (ess-fix-dot-1 nil verbose) (ess-fix-dot ",)" dont-query verbose)) (defun ess-fix-EQ-assign (&optional dont-query verbose not-all) "Replace \"=\" by \"<-\" in places where it `might make sense', e.g., for function assignments and lines not ending in \",\". Be *careful* for list()s of functions and when argument not-all is nil (as by default) !" ;;TODO: "in the few places we can be very sure.." ;;---- is hard in general: local functions: ok; but functions in ;; list(a = function(x) abs(x), b= function(y) bound(y)) *NOT* ok! (interactive "P") (ess-replace-regexp-dump-to-src "^\\( *[a-z.][_a-z.0-9]*\\) *= *\\(function *(\\)" "\\1 <- \\2" dont-query verbose) (unless not-all ;; "too" aggressive {proposing to replace function argument specs}: (ess-replace-regexp-dump-to-src ;; all those *not* ending in "," ;; including Mat[ i, ] = ..., ;; but not `names(x) = "..."' for that is "confused" with plot(x=x,..) "^\\( *[a-z.][][, \"_a-z.0-9]*\\) *= *\\([a-z.0-9({]\\(.*[^,]\\)? *$\\)" "\\1 <- \\2" nil ;; always query - often has many "false positives" verbose))) ;;; All of the above three : (defun ess-MM-fix-src (&optional dont-query verbose) "Clean up ess-source code which has been produced by dump(..), and other code typically produced by other tools. Produces more readable code, and one that is well formatted in Emacs ess-mode." (interactive "P") ;; each of the following does a save-excursion: (ess-dump-to-src dont-query) (ess-fix-comments dont-query) (ess-num-var-round dont-query verbose) (ess-fix-dot-more dont-query verbose) (ess-fix-EQ-assign dont-query verbose 'not-all)) (defun ess-fix-miscellaneous (&optional from verbose) "Fix Miscellaneous S/R `ill-formation's from current \\[point]. Particularly use \"<-\"and put spaces around operators." (interactive "d\nP"); Defaults: point and prefix (C-u) ;; activate by (setq ess-verbose t) (ess-if-verbose-write (format "ess-fix-misc begin (from = %s, verbose = %s)\n" from verbose)) (save-excursion (when (and (string= ess-dialect "R") (fboundp 'ess-r-fix-T-F)) (ess-r-fix-T-F from (not verbose))) ;; activate by (setq ess-verbose t) (ess-if-verbose-write "ess-fix-misc: after fix-T-F\n");___D___ ;; former C and matlab programmers leave trailing ";" : ;; (goto-char from) (ess-rep-regexp "; *$" "" nil 'literal verbose) ;; (ess-if-verbose-write "ess-fix-misc: after trailing ';'\n");___D___ (goto-char from) (ess-rep-regexp ";\\( *\\)#" "\\1#" nil nil verbose) (ess-if-verbose-write "ess-fix-misc: after ';' before #\n");___D___ ;;from R 1.9.x "_" is valid in names; here assume no initial / trailing '_' ;; BUG: The following changes "beta_ " or " _abc" ;; (goto-char from) (ess-rep-regexp " +_ *" " <- " nil 'literal verbose) ;; (goto-char from) (ess-rep-regexp "_ +" " <- " nil 'literal verbose) (ess-if-verbose-write "ess-fix-misc: before 'around \"<-\"' :\n");___D___ ;; ensure space around "<-" ---- but only replace if necessary: (goto-char from) (ess-rep-regexp "\\([^< \t\n]\\)\\(<" (not ">=") : (goto-char from);; --> " <", care with "->": (ess-rep-regexp "\\([^-< \t\n]\\)\\([<>]\\)" "\\1 \\2" nil nil verbose) ;; ">" -> "> " , for "<", don't split "<-" nor "<<-": (goto-char from) (ess-rep-regexp "\\(>=?\\)\\([^= \t\n]\\)" "\\1 \\2" nil nil verbose) (goto-char from) (ess-rep-regexp "\\(<=?\\)\\([^-<= \t\n]\\)" "\\1 \\2" nil nil t) (ess-if-verbose-write "ess-fix-misc: before \"=\" \"==\" .. :\n");___D___ ;; -- ensure space around "=", "==", "!=" : (goto-char from) ;; --> " =" (ess-rep-regexp "\\([^=!<> ]\\)\\([=!]?\\)=" "\\1 \\2=" nil nil verbose) (goto-char from) (ess-rep-regexp "=\\([^= ]\\)" "= \\1" nil nil verbose) (goto-char from) ;; add a space between "{" and surrounding ..char: (ess-rep-regexp "{\\([.A-Za-z()]\\)" "{ \\1" 'fix nil verbose) (ess-rep-regexp "\\([()]\\){" "\\1 {" 'fix nil verbose) (goto-char from) ;; add a space between "}" and a preceding wordchar: (ess-rep-regexp "\\([A-Za-z0-9()]\\)}" "\\1 }" 'fix nil verbose) (ess-space-around "else" from verbose) (ess-if-verbose-write "ess-fix-misc: after \"{ ... }\" :\n");___D___ (goto-char from) ;; add a space inside "){" (ess-rep-regexp "){" ") {" 'fix nil verbose) ;; add a newline and indent before a "}" ;; --- IFF there's NO "{" or "#" AND some NON-white text on the same line: ;;D (if verbose (message "\t R-fix-misc..: Hard.. '}'")) (goto-char from) (ess-rep-regexp "^\\([^#{\n]*[^#{ \t\n]+[ \t]*\\)}[ \t]*$" "\\1\n}" 'fix nil verbose) (ess-if-verbose-write "ess-fix-misc __end__\n");___D___ )) (defun ess-cycle-assign () "Cycle between assignment symbols in `ess-assign-list'. On consecutive calls, replace the assignment symbol before point with the next symbol from that list. This function sets the last keypress to repeat it, so if it is bound to \"C-c C-=\" pressing \"=\" again cycles to the next assignment." (interactive) (if (eq last-command this-command) (let ((slist ess-assign-list) str) ;; The or statements in the setq allow cycling past the end of ;; ess-assign-list. (while (and (setq str (or (car slist) (car ess-assign-list)) slist (or (cdr slist) ess-assign-list)) (not (and (re-search-backward str (- (point) (length str)) t) (not (replace-match (car slist)))))))) (delete-horizontal-space) (insert (car ess-assign-list))) (set-transient-map (let ((map (make-sparse-keymap)) (key (format "%c" (event-basic-type last-input-event)))) (define-key map (kbd key) #'ess-cycle-assign) map))) (defun ess-insert-assign (arg) "Insert the first element of `ess-assign-list' unless in string or comment. If the character before point is the first element of `ess-assign-list', replace it with the last character typed. If `ess-language' is not \"S\", call `self-insert-command' with ARG." (interactive "p") (if (string= ess-language "S") (let* ((assign (car ess-assign-list)) (event (event-basic-type last-input-event)) (char (ignore-errors (format "%c" event)))) (cond ((and char (ess-inside-string-or-comment-p)) (insert char)) ((re-search-backward assign (- (point) (length assign)) t) (if (and char (numberp event)) (replace-match char t t) (replace-match ""))) (t (delete-horizontal-space) (insert assign)))) (funcall #'self-insert-command arg))) ;; In case people had this in their config don't cause errors: (define-obsolete-function-alias 'ess-smart-S-assign #'ess-insert-assign "ESS 18.10") (define-obsolete-function-alias 'ess-disable-smart-S-assign #'ignore "ESS 18.10") (defun ess-add-MM-keys () "Define MM's user keys." (declare (obsolete "Setup your own keybindings." "ESS 19.04")) (define-key inferior-ess-mode-map "\C-cw" #'ess-execute-screen-options) (define-key ess-mode-map [?\M--] #'ess-insert-assign) (define-key inferior-ess-mode-map [?\M--] #'ess-insert-assign)) (defun ess-dump-args-and-go (Sfunc) "Dump the function name, with arguments, to a buffer for editing. Currently, this needs to: 1. set the buffer to the right mode, with the right settings 2. format the statement, 3. c/function/Sfunc/ and I need to relearn Emacs lisp (but I had to, anyway." (declare (obsolete 'ess-execute "ESS 19.04")) (interactive "sFunction ? ") (let* ((buffname "ess-complete.R")) (ess-execute (format "args(%s)" Sfunc) t buffname) (pop-to-buffer (concat "*" buffname "*")) (while (search-forward "function" nil t) (replace-match Sfunc nil t)) (when (fboundp 'ess-r-mode) (ess-r-mode)))) ;;; S imenu support ;; don't use syntax classes, bad for etags (defvar ess-imenu-S-generic-expression '(("Functions" "^\\([^ \t\n]+\\)[ \t\n]*\\(?:<-\\|=\\)[ \t\n]*function[ ]*(" 1) ("Classes" "^.*setClass(\\(.*\\)," 1) ("Coercions" "^.*setAs(\\([^,]+,[^,]*\\)," 1) ; show from and to ("Generics" "^.*setGeneric(\\([^,]*\\)," 1) ("Methods" "^.*set\\(Group\\|Replace\\)?Method(\\([^,]+,[^,]*\\)" 2) ("Package" "^.*\\(library\\|require\\)(\\([^)]*\\)" 2) ("Data" "^\\(.+\\)[ \t\n]-*\\(?:<-\\|=\\)[ \t\n]*\\(read\\|.*data\\.frame\\).*(" 1)) "Imenu generic expression for S modes. See `imenu-generic-expression'.") (defun ess-imenu-S (&optional _arg) "S Language Imenu support for ESS. ARG is ignored." (declare (obsolete "It is set automatically in major modes" "ESS 19.04")) (imenu-add-to-menubar "Imenu-S")) ;;; Speedbar stuff. (eval-after-load "speedbar" '(progn (speedbar-add-supported-extension ".R") (speedbar-add-supported-extension ".S") (speedbar-add-supported-extension ".s") (speedbar-add-supported-extension ".q"))) (cl-defmethod ess-help-get-topics (proc &context (ess-dialect "R")) "Return a list of current S help topics associated with process PROC. If `sp-for-help-changed?' process variable is non-nil or `ess-help-topics-list' is nil, (re)-populate the latter and return it. Otherwise, return `ess-help-topics-list'." (with-ess-process-buffer nil (cond ;; (Re)generate the list of topics ((or (not ess-help-topics-list) (ess-process-get 'sp-for-help-changed?)) (ess-process-put 'sp-for-help-changed? nil) (setq ess-help-topics-list (delete-dups (append (ess-get-object-list proc 'exclude-1st) (ess-get-help-files-list) (ess-get-help-aliases-list))))) (t ess-help-topics-list)))) (cl-defmethod ess-help--reset-cache-override (&context (ess-dialect "R")) (ess-command ".ess.getHelpAliases(reset = TRUE)\n" nil nil nil nil nil nil ess-help--aliases-timeout)) (define-obsolete-function-alias 'ess-toggle-S-assign-key #'ignore "ESS 18.10") (define-obsolete-function-alias 'ess-smart-underscore #'ess-insert-assign "ESS 18.10") (define-obsolete-function-alias 'ess-insert-S-assign #'ess-insert-assign "ESS 18.10") ;;;###autoload (add-to-list 'auto-mode-alist '("\\.[Ss]t\\'" . S-transcript-mode)) ;;;###autoload (add-to-list 'auto-mode-alist '("\\.Sout\\'" . S-transcript-mode)) (provide 'ess-s-lang) ;;; ess-s-lang.el ends here ESS-24.01.1/lisp/ess-sas-a.el000066400000000000000000001775261455642170100154250ustar00rootroot00000000000000;;; ess-sas-a.el --- clean-room implementation of many SAS-mode features -*- lexical-binding: t; -*- ;; Copyright (C) 1997-2022 Free Software Foundation, Inc. ;; Author: Rodney A. Sparapani ;; Maintainer: ESS-core@r-project.org ;; Created: 17 November 1999 ;; Keywords: languages ;; This file is part of GNU Emacs. ;;; License: ;; ;; 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 ;; ;;; Code: (require 'ess-mode) (require 'ess-utils) ;; Silence the byte compiler ;; FIXME: This is a lot, perhaps they can be moved? (defvar sas-indent-width) (defvar SAS-customize-alist) (defvar sas-mode-local-map) (declare-function ess-num-or-zero "ess-sas-d") ;; FIXME: What is this doing here??? (declare-function ess-add-ess-process "essd-els") (declare-function ess-listing-minor-mode "ess-sas-l") ;;; Table of Contents ;;; Section 1: Variable Definitions ;;; Section 2: Function Definitions ;;; Section 3: Key Definitions ;;; Section 1: Variable Definitions (defvar ess-sas-file-path "." "Full path-name of the sas file to perform operations on.") (defcustom ess-sas-data-view-libname " " "SAS code to define a library for `ess-sas-data-view-fsview' or `ess-sas-data-view-insight'." :group 'ess-sas :type 'string) (defcustom ess-sas-data-view-submit-options (if ess-microsoft-p "-noenhancededitor -nosysin -log NUL:" "-nodms -nosysin -log /dev/null -terminal") "The command-line options necessary for your OS with respect to `ess-sas-data-view-fsview' and `ess-sas-data-view-insight'." :group 'ess-sas :type 'string) (defcustom ess-sas-data-view-fsview-command "; proc fsview data=" "SAS code to open a SAS dataset with `ess-sas-data-view-fsview'." :group 'ess-sas :type 'string) (defcustom ess-sas-data-view-fsview-statement " " "SAS code to perform a PROC FSVIEW statement with `ess-sas-data-view-fsview'." :group 'ess-sas :type 'string) (make-variable-buffer-local 'ess-sas-data-view-fsview-statement) (defcustom ess-sas-data-view-insight-command "; proc insight data=" "SAS code to open a SAS dataset with `ess-sas-data-view-insight'." :group 'ess-sas :type 'string) (defcustom ess-sas-data-view-insight-statement " " "SAS code to perform a PROC FSVIEW statement with `ess-sas-data-view-insight'." :group 'ess-sas :type 'string) (make-variable-buffer-local 'ess-sas-data-view-insight-statement) (defcustom ess-sas-graph-view-suffix-regexp "[.]\\([eE]?[pP][sS]\\|[pP][dD][fF]\\|[gG][iI][fF]\\|[jJ][pP][eE]?[gG]\\|[tT][iI][fF][fF]?\\|[pP][nN][gG]\\)" "GSASFILE suffix regexp." :group 'ess-sas :type 'string) (defcustom ess-sas-graph-view-viewer-alist ;;creates something like ;;'(("[pP][dD][fF]" . "/usr/local/bin/acroread") ("[eE]?[pP][sS]" . "/usr/local/bin/gv"))) (let ((ess-tmp-ps nil) (ess-tmp-pdf nil)) (setq ess-tmp-ps (executable-find (if ess-microsoft-p "gsview32" "gsview"))) (if (not ess-tmp-ps) (setq ess-tmp-ps (executable-find "gv"))) (if (not ess-tmp-ps) (setq ess-tmp-ps (executable-find "ghostview"))) (setq ess-tmp-pdf (executable-find "evince")) (if (not ess-tmp-pdf) (setq ess-tmp-pdf (executable-find "xpdf"))) (if (not ess-tmp-pdf) (setq ess-tmp-pdf (if ess-microsoft-p "acrord32" "acroread")))) "Associate file name extensions with graphics image file viewers." :group 'ess-sas :type '(choice (const nil) (alist))) (defcustom ess-sas-log-max 0 "If >0 and .log file exceeds this many bytes, just \"refresh\" this many bytes." :group 'ess-sas :type 'integer) (defcustom ess-sas-rtf-font-name "Courier" ; "Bitstream Vera Sans Mono" "Name of font with which to create MS RTF." :group 'ess-sas :type 'string) (defcustom ess-sas-shell-buffer "*shell*" "Name that you want to use for the shell buffer; buffer-local." :group 'ess-sas :type 'string) (make-variable-buffer-local 'ess-sas-shell-buffer) (defcustom ess-sas-shell-buffer-remote-host nil "Remote host that you want to open a shell on." :group 'ess-sas :type '(choice (const nil) string)) (make-variable-buffer-local 'ess-sas-shell-buffer-remote-host) (defcustom ess-sas-shell-buffer-remote-init "ssh" "Command to open a shell on a remote host." :group 'ess-sas :type 'string) (make-variable-buffer-local 'ess-sas-shell-buffer-remote-init) (defcustom ess-sas-submit-mac-virtual-pc nil "Non-nil means that you want to run Windows SAS in a Virtual PC emulator on your Mac; buffer-local." :group 'ess-sas :type 'boolean) (make-variable-buffer-local 'ess-sas-submit-mac-virtual-pc) (defcustom sas-program "sas" "Command to invoke SAS, default for buffer-local `ess-sas-submit-command'." :group 'ess-sas :type 'string) (defcustom ess-sas-submit-command sas-program "Command to invoke SAS in batch; buffer-local." :group 'ess-sas :type 'string) (make-variable-buffer-local 'ess-sas-submit-command) (defcustom ess-sas-submit-command-options "-rsasuser" "Options to pass to SAS in batch; buffer-local." :group 'ess-sas :type 'string) (make-variable-buffer-local 'ess-sas-submit-command-options) (defvar-local ess-sas-submit-method (if (and (and ess-microsoft-p (fboundp 'w32-shell-dos-semantics)) (w32-shell-dos-semantics)) 'ms-dos 'sh) "Method used by `ess-sas-submit'. The default is based on the value of the emacs variable `system-type' and, on Windows, the function `w32-shell-dos-semantics'. \\='sh if *shell* runs sh, ksh, csh, tcsh or bash \\='ms-dos if *shell* follows MS-DOS semantics Unix users will get \\='sh by default. Windows users running bash in *shell* will get \\='sh by default. Windows users running MS-DOS in *shell* will get \\='ms-dos by default. Users accessing a remote machine with `telnet', `rlogin', `ssh', etc., should set this variable to \\='sh regardless of their local shell (since their remote shell is \\='sh).") (defcustom ess-sas-graph-view-viewer-default (if ess-microsoft-p "explorer" (if (equal ess-sas-submit-method 'sh) "sdtimage")) "Default graphics image file viewer." :group 'ess-sas :type 'string) (defcustom ess-sas-submit-post-command (if (equal ess-sas-submit-method 'sh) "&" (if ess-microsoft-p "-icon")) "Command-line statement to post-modify SAS invocation." :group 'ess-sas :type 'string) (defcustom ess-sas-submit-pre-command ;;"nohup" (if (equal ess-sas-submit-method 'sh) ;; nice is tricky, higher numbers give you lower priorities ;; if you are using csh/tcsh, the default priority is 4 ;; if you are using most other shells, the default priority is 10, ;; and some implementations are higher, i.e. zsh unless you ;; specify "setopt no_bg_nice" in your ~/.zshrc ;; therefore, on the same machine, you can run at a higher or ;; lower priority by changing shells, although, the command ;; line is the same! ;; the following code should give you a priority of 10 regardless ;; of which shell is in use, but it will default to the old ;; behavior if csh or variant is not recognized ;; this should avoid the necessity of each user needing to set this ;; variable correctly based on the shell that they use and provide ;; an environment where all shells are treated equally (let* ((temp-shell (getenv "SHELL")) ;; AJR: old CYGWIN versions return nil for (getenv ;; "SHELL"), so we need to deal with it 'cause I have to (temp-char (if temp-shell (string-match "/" temp-shell) nil))) (while temp-char (setq temp-shell (substring temp-shell (+ 1 temp-char))) (setq temp-char (string-match "/" temp-shell))) (cond ((or (equal temp-shell "csh") (equal temp-shell "tcsh")) "nohup nice +6") (t "nohup nice"))) (if ess-microsoft-p "start")) "Command-line statement to precede SAS invocation, e.g. start or nohup." :group 'ess-sas :type 'string) (defcustom ess-sas-suffix-1 "txt" "The first suffix to associate with SAS." :group 'ess-sas :type 'string) (defcustom ess-sas-suffix-2 "csv" "The second suffix to associate with SAS." :group 'ess-sas :type 'string) (defcustom ess-sas-suffix-regexp (concat "[.]\\([sS][aA][sS]\\|[lL][oO][gG]\\|[lL][sS][tT]" (if ess-sas-suffix-1 (concat "\\|" (downcase ess-sas-suffix-1) "\\|" (upcase ess-sas-suffix-1))) (if ess-sas-suffix-2 (concat "\\|" (downcase ess-sas-suffix-2) "\\|" (upcase ess-sas-suffix-2))) "\\)") "Regular expression for SAS suffixes." :group 'ess-sas :type 'string) (defcustom ess-sas-tab-stop-list '(4 8 12 16 20 24 28 32 36 40 44 48 52 56 60 64 68 72 76 80 84 88 92 96 100 104 108 112 116 120) "List of tab stop positions used by `tab-to-tab-stop' in ESS[SAS]." :type '(repeat integer) :group 'ess-sas) (defcustom ess-sas-temp-root "-temp" "Appended to root name of the temporary .sas file for `ess-sas-submit-region'." :group 'ess-sas :type 'string) (defvar ess-sas-versions '("sas") "List of partial strings for versions of SAS to access within ESS. Each string specifies the start of a filename. If a filename beginning with one of these strings is found on `exec-path', a M-x command for that version of SAS is made available. For example, if the file \"sas8\" is found and this variable includes the string \"sas\", a function called `M-x SAS8' will be available to run that version of SAS. If duplicate versions of the same program are found (which happens if the same path is listed on `exec-path' more than once), they are ignored by calling `delete-dups'. If you set this variable, you need to restart Emacs (and set this variable before ess-site is loaded) for it to take effect.") (defvar ess-sas-global-unix-keys nil "Non-nil if function keys use Unix-like SAS key definitions in all modes.") (defvar ess-sas-local-pc-keys nil "Non-nil if function keys use PC-like SAS key definitions in SAS-mode and related modes.") (defvar ess-sas-local-unix-keys nil "Non-nil if function keys use Unix-like SAS key definitions in SAS-mode and related modes.") ;;; Section 2: Function Definitions (defun ess-ebcdic-to-ascii-search-and-replace () "Search and replace EBCDIC text with ASCII equivalents." (interactive) (let ((ess-tmp-dd (executable-find "dd")) (ess-tmp-recode (executable-find "recode")) (ess-tmp-util nil) (ess-tmp-util-args nil)) (if ess-tmp-dd (progn (setq ess-tmp-util ess-tmp-dd) (setq ess-tmp-util-args "conv=ascii")) (setq ess-tmp-util ess-tmp-recode) (setq ess-tmp-util-args "EBCDIC..ISO-8859-1")) (if ess-tmp-util (while (search-forward-regexp "[^\f\t\n -~][^\f\t\n -?A-JQ-Yb-jp-y]*[^\f\t\n -~]?" nil t) (call-process-region (match-beginning 0) (match-end 0) ess-tmp-util t (list t nil) t ess-tmp-util-args))))) (defun ess-exit-notify-sh (string) "Detect completion or failure of submitted job and notify the user." (let* ((exit-done "\\[[0-9]+\\] *\\+* *\\(Exit\\|Done\\)[^\r\n]*") (beg (string-match exit-done string))) (if beg (message "%s" (substring string beg (match-end 0)))))) (defun ess-sas-append-log () "Append ess-temp.log to the current .log file." (interactive) (ess-sas-goto "log" 'revert) (goto-char (point-max)) (insert-file-contents (concat (ess-sas-temp-root) ".log")) (save-buffer)) (defun ess-sas-append-lst () "Append ess-temp.lst to the current .lst file." (interactive) (ess-sas-goto "lst" 'revert) (goto-char (point-max)) (insert-file-contents (concat (ess-sas-temp-root) ".lst")) (save-buffer)) (defun ess-sas-backward-delete-tab () "Moves the cursor to the previous tab-stop, deleting any characters on the way." (interactive) (let* (;; point of search ;;(ess-sas-search-point nil) ;; column of search ;;(ess-sas-search-column nil) ;; limit of search ;;(ess-sas-search-limit nil) ;; text to be inserted after a back-tab, if any ;;(ess-sas-end-text "end;") ;; current-column (ess-sas-column (current-column)) ;; remainder of current-column and sas-indent-width (ess-sas-remainder (% ess-sas-column sas-indent-width))) (if (not (= ess-sas-column 0)) (progn (if (= ess-sas-remainder 0) (setq ess-sas-remainder sas-indent-width)) (let ((backward-delete-char-untabify-method 'nil)) (backward-delete-char-untabify ess-sas-remainder t) (setq ess-sas-column (- ess-sas-column ess-sas-remainder)) (move-to-column ess-sas-column) (setq left-margin ess-sas-column)) )) )) ;; this feature was far too complicated to perfect ;; (if ess-sas-smart-back-tab (progn ;; (save-excursion ;; (setq ess-sas-search-point ;; (search-backward-regexp "end" nil t)) ;; (if (and ess-sas-search-point ;; (search-backward-regexp "%" (+ ess-sas-search-point -1) t)) ;; (setq ess-sas-search-point (+ ess-sas-search-point -1)) ;; ) ;; (if (and ess-sas-search-point ;; (not (equal ess-sas-column (current-column)))) ;; (setq ess-sas-search-point nil)) ;; ) ;; (save-excursion ;; (setq ess-sas-search-point ;; (search-backward-regexp "do\\|select" ;; ess-sas-search-point t)) ;; (setq ess-sas-search-column (current-column)) ;; (if ess-sas-search-point (progn ;; (save-excursion ;; (search-backward-regexp "^" nil t) ;; (setq ess-sas-search-limit (point)) ;; ) ;; (if (search-backward-regexp "if.*then\\|else" ess-sas-search-limit t) ;; (setq ess-sas-search-point (point))) ;; (if (search-backward-regexp "%" ess-sas-search-limit t) (progn ;; (setq ess-sas-end-text "%end;") ;; (setq ess-sas-search-point (point)) ;; )) ;; (setq ess-sas-search-column (current-column)) ;; (if (not (equal ess-sas-column ess-sas-search-column)) ;; (setq ess-sas-search-point nil)) ;; ))) ;; (if ess-sas-search-point (insert ess-sas-end-text)) ;; )) (defun ess-sas-cd () "Change directory, taking into account various issues with respect to `ess-sas-file-path'." ;(interactive) (ess-sas-file-path) (ess-sas-goto-shell t) (comint-send-input) (if (equal ess-sas-submit-method 'sh) (insert "cd \"" (car (last (split-string (file-name-directory ess-sas-file-path) "\\([a-zA-Z][a-zA-Z]:\\|]\\)"))) "\"") (if (equal ess-sas-submit-method 'ms-dos) (progn (if (string-equal ":" (substring ess-sas-file-path 1 2)) (progn (insert (substring ess-sas-file-path 0 2)) (comint-send-input))) (insert "cd \"" (convert-standard-filename (file-name-directory ess-sas-file-path)) "\"")))) (comint-send-input)) (defun ess-sas--change-alist (item value alist) "Modify ALIST to set VALUE to ITEM. If there is a pair whose car is ITEM, replace its cdr by VALUE. If there is not such pair, create new pair (ITEM . VALUE) and return new alist whose car is the new pair and cdr is ALIST. \[tomo's ELIS like function]" (let ((pair (assoc item alist))) (if pair (progn (setcdr pair value) alist) (cons (cons item value) alist)))) (defun ess-sas-create-local-variables-alist (&optional file-or-buffer) "Create an alist of local variables from file-or-buffer. Use the current buffer if nil." (declare (obsolete nil "ESS 19.04")) (if file-or-buffer (set-buffer (if (bufferp file-or-buffer) file-or-buffer (find-buffer-visiting file-or-buffer)))) (ess-sas--change-alist 'ess-kermit-remote-directory ess-kermit-remote-directory nil)) (define-obsolete-function-alias 'ess-change-alist #'ess-sas--change-alist "ESS 18.10") (defun ess-sas-data-view-fsview (&optional ess-sas-data) "Open a dataset for viewing with PROC FSVIEW." (interactive) (ess-save-and-set-local-variables) (save-excursion (let ((ess-tmp-sas-data nil) (ess-tmp-sas-data-view-fsview-statement ess-sas-data-view-fsview-statement) (ess-search-regexp "[ \t=]\\([a-zA-Z_][a-zA-Z_0-9]*[.][a-zA-Z_][a-zA-Z_0-9]*\\)\\(&.*\\)?[. ,()\t;/]") (ess-search-except "^\\([wW][oO][rR][kK]\\|[fF][iI][rR][sS][tT]\\|[lL][aA][sS][tT]\\)[.]")) (if ess-sas-data nil (save-match-data (search-backward-regexp "[ \t=]" nil t) (save-excursion (setq ess-tmp-sas-data (ess-search-except ess-search-regexp ess-search-except))) (if (not ess-tmp-sas-data) (setq ess-tmp-sas-data (ess-search-except ess-search-regexp ess-search-except t))) (setq ess-sas-data (read-string "Permanent SAS Dataset: " ess-tmp-sas-data)) ;; (ess-sas-goto-shell t) (ess-sas-cd) (insert (concat ess-sas-submit-pre-command " " ess-sas-submit-command " -initstmt \"" ess-sas-data-view-libname ess-sas-data-view-fsview-command ess-sas-data ";" ess-tmp-sas-data-view-fsview-statement "; run;\" " ess-sas-submit-command-options " " ess-sas-data-view-submit-options " " ess-sas-submit-post-command)) (comint-send-input) ))))) (defun ess-sas-data-view-insight (&optional ess-sas-data) "Open a dataset for viewing with PROC INSIGHT." (interactive) (ess-save-and-set-local-variables) (save-excursion (let ((ess-tmp-sas-data nil) (ess-tmp-sas-data-view-insight-statement ess-sas-data-view-insight-statement) (ess-search-regexp "[ \t=]\\([a-zA-Z_][a-zA-Z_0-9]*[.][a-zA-Z_][a-zA-Z_0-9]*\\)\\(&.*\\)?[. ,()\t;]") (ess-search-except "^\\([wW][oO][rR][kK]\\|[fF][iI][rR][sS][tT]\\|[lL][aA][sS][tT]\\)[.]")) (if ess-sas-data nil (save-match-data (search-backward-regexp "[ \t=]" nil t) (save-excursion (setq ess-tmp-sas-data (ess-search-except ess-search-regexp ess-search-except))) (if (not ess-tmp-sas-data) (setq ess-tmp-sas-data (ess-search-except ess-search-regexp ess-search-except t))) (setq ess-sas-data (read-string "Permanent SAS Dataset: " ess-tmp-sas-data)) ;; (ess-sas-goto-shell t) (ess-sas-cd) (insert (concat ess-sas-submit-pre-command " " ess-sas-submit-command " -initstmt \"" ess-sas-data-view-libname ess-sas-data-view-insight-command ess-sas-data ";" ess-tmp-sas-data-view-insight-statement "; run;\" " ess-sas-data-view-submit-options " " ess-sas-submit-post-command)) (comint-send-input) ))))) (defun ess-sas-graph-view () "Open a GSASFILE for viewing." (interactive) ;; (ess-sas-goto-shell t) (ess-sas-cd) (ess-sas-goto-log 'no-error-check) (save-excursion (let ( (ess-tmp-length (length ess-sas-graph-view-viewer-alist)) (ess-tmp-counter 0) (ess-tmp-graph nil) (ess-tmp-graph-alist nil) (ess-tmp-glyph nil) (ess-tmp-graph-regexp (concat "[cCub][oOty][rRpt][dDue][sSt][ ][wW][rR][iI][tT][tT][eE][nN][ ]+[tT][oO][ ]\n?[ ]*\\(.*" ;; (concat "[ ][rR][eE][cC][oO][rR][dD][sS][ ][wW][rR][iI][tT][tT][eE][nN][ ]+[tT][oO][ ]\n?[ ]*\\(.*" ess-sas-graph-view-suffix-regexp "\\)"))) ; (concat "['\"]\\(.*" ess-sas-graph-suffix-regexp "\\)['\"]"))) (save-match-data (search-backward-regexp "[ \t=]" nil t) (save-excursion (setq ess-tmp-graph (ess-search-except ess-tmp-graph-regexp))) (if (not ess-tmp-graph) (setq ess-tmp-graph (ess-search-except ess-tmp-graph-regexp nil t))) (setq ess-tmp-graph (read-string "GSASFILE: " (or ess-tmp-graph ess-sas-file-path))) ;; whether the image libraries are configured is what is important here (if (and (string-match "JPEG" system-configuration-features) (string-match "[.][jJ][pP][eE]?[gG]" ess-tmp-graph)) (find-file ess-tmp-graph) (if (and (string-match "PNG" system-configuration-features) (string-match "[.][pP][nN][gG]" ess-tmp-graph)) (find-file ess-tmp-graph) ;; ;;GNU Emacs graphics file image viewing mode loaded? ;; (if (and (bound-and-true-p auto-image-file-mode) ;; (string-match "[.][jJ][pP][eE]?[gG]" ess-tmp-graph)) ;; (find-file ess-tmp-graph) ;; ;;else XEmacs graphics file image viewing mode loaded? ;; (if (and (fboundp 'image-mode) ;; (string-match "[.]\\([jJ][pP][eE]?[gG]\\|[gG][iI][fF]\\)" ;; ess-tmp-graph)) ;; (find-file ess-tmp-graph) ;;else use the appropriate graphics file image viewer (while (< ess-tmp-counter ess-tmp-length) (setq ess-tmp-graph-alist (nth ess-tmp-counter ess-sas-graph-view-viewer-alist)) (setq ess-tmp-graph-regexp (car ess-tmp-graph-alist)) (if (string-match (concat "[.]" ess-tmp-graph-regexp) ess-tmp-graph) (progn (ess-sas-goto-shell t) (insert ess-sas-submit-pre-command " " (cdr ess-tmp-graph-alist) " " ess-tmp-graph (if (equal ess-sas-submit-method 'sh) " &")) (setq ess-tmp-glyph 'alist) (setq ess-tmp-counter ess-tmp-length)) ;;else (setq ess-tmp-counter (+ ess-tmp-counter 1)))) (if (not ess-tmp-glyph) (progn (ess-sas-goto-shell t) (insert ess-sas-submit-pre-command " " ess-sas-graph-view-viewer-default " " ess-tmp-graph (if (equal ess-sas-submit-method 'sh) " &")))) (comint-send-input))))))) (defun ess-sas-file-path (&optional force) "Define `ess-sas-file-path' to be the current buffer depending on suffix." (interactive) (save-match-data (let ((ess-sas-temp-file (expand-file-name (buffer-name)))) (if (or force (string-match ess-sas-suffix-regexp ess-sas-temp-file)) ;;(progn (setq ess-sas-file-path (nth 0 (split-string ess-sas-temp-file "[<]"))))))) (defun ess-sas-file-path-remote-host () "Return the remote host, if any, associated with `ess-sas-file-path'." (interactive) (let* ((temp-colon-pos (string-match ":" ess-sas-file-path)) (temp-list (if (or (not temp-colon-pos) (> temp-colon-pos 2)) (if (equal ess-sas-file-path ".") nil (split-string (file-name-directory ess-sas-file-path) "\\(@\\|:\\|]\\)")) (list ess-sas-file-path))) (temp-list-length (length temp-list))) (if (= temp-list-length 1) (setq temp-list nil) (if (= temp-list-length 2) (setq temp-list (car temp-list)) (setq temp-list (nth 1 temp-list)))) (if temp-list (setq temp-list (car (last (split-string temp-list "/"))))) temp-list)) (defun ess-sas-goto (suffix &optional revert no-create) "Find a file associated with a SAS file by suffix and revert if necessary." ; (interactive) ; (let ((ess-temp-regexp (concat ess-sas-suffix-regexp "[.]?[1-9]?\\'"))) ; can we identify common nonsense extensions like .log.1 or .sas.2? (let ((ess-temp-regexp (concat ess-sas-suffix-regexp "\\(@.+\\)?\\'"))) (save-match-data (if (or (string-match ess-temp-regexp (expand-file-name (buffer-name))) (string-match ess-temp-regexp ess-sas-file-path)) (progn (ess-sas-file-path) (let* ( (ess-sas-temp-file (replace-match (concat "." suffix) t t ess-sas-file-path)) (ess-sas-temp-buff (find-buffer-visiting ess-sas-temp-file)) (ess-temp-kermit-remote-directory ess-kermit-remote-directory)) (if ess-sas-temp-buff (switch-to-buffer ess-sas-temp-buff) ;; else (if no-create (setq revert nil) (if (file-exists-p ess-sas-temp-file) (find-file ess-sas-temp-file)))) ;; else ;; (let* ((ess-sas-buffer-list (buffer-list)) ;; (ess-sas-buffer-list-index 0) ;; (ess-sas-buffer-list-file nil) ;; (ess-sas-buffer-list-length (length ess-sas-buffer-list))) ;; (while (< ess-sas-buffer-list-index ess-sas-buffer-list-length) ;; (setq ess-sas-buffer-list-file ;; (buffer-file-name (nth ess-sas-buffer-list-index ess-sas-buffer-list))) ;; (if (and ess-sas-buffer-list-file ;; (string-match (concat "." suffix) ess-sas-buffer-list-file)) ;; (switch-to-buffer (nth ess-sas-buffer-list-index ess-sas-buffer-list)) ;; (setq ess-sas-buffer-list-index ess-sas-buffer-list-length) ;; ) ;; (setq ess-sas-buffer-list-index (+ 1 ess-sas-buffer-list-index)) ;; ))) (if (and (not no-create) (or (string-equal suffix "log") (string-equal suffix "lst"))) (ess-kermit-get (file-name-nondirectory ess-sas-temp-file) ess-temp-kermit-remote-directory)) (if revert (if (and (> ess-sas-log-max 0) (string-equal suffix "log") (> (ess-num-or-zero (nth 7 (file-attributes ess-sas-temp-file))) ess-sas-log-max)) (progn (insert-file-contents ess-sas-temp-file nil 0 ess-sas-log-max t) t) (ess-revert-wisely)) nil))))))) ;;(defun ess-sas-file (suffix &optional revert) ;; "Please use `ess-sas-goto' instead." ;; (let* ((tail (downcase (car (split-string ;; (car (last (split-string (buffer-name) "[.]"))) "[<]")))) ;;(if (fboundp 'file-name-extension) (file-name-extension (buffer-name)) ;; (substring (buffer-name) -3))) ;; (tail-in-tail-list (member tail (list "sas" "log" "lst" ;; ess-sas-suffix-1 ess-sas-suffix-2))) ;; (root (if tail-in-tail-list (expand-file-name (buffer-name)) ;; ess-sas-file-path)) ;; (ess-sas-arg (concat (file-name-sans-extension root) "." suffix)) ;; (ess-sas-buf (find-buffer-visiting ess-sas-arg))) ;; (if (equal tail suffix) (if revert (ess-revert-wisely)) ;; (if (not ess-sas-buf) (find-file ess-sas-arg) ;; (switch-to-buffer ess-sas-buf) ;; (if revert (ess-revert-wisely)))))) (defun ess-sas-goto-file-1 () "Switch to ess-sas-file-1 and revert from disk." (interactive) (ess-sas-goto ess-sas-suffix-1 'revert)) (defun ess-sas-goto-file-2 () "Switch to ess-sas-file-2 and revert from disk." (interactive) (ess-sas-goto ess-sas-suffix-2 'revert)) (defun ess-sas-goto-log (&optional ess-tmp-no-error-check) "Switch to the .log file, revert from disk and search for error messages." (interactive) (let ((ess-sas-error (concat "^ERROR [0-9]+-[0-9]+:\\|^ERROR:\\|_ERROR_=1 _N_=\\|_ERROR_=1[ ]?$" "\\|NOTE: MERGE statement has more than one data set with repeats" "\\|NOTE: Variable .* is uninitialized." "\\|NOTE: SAS went to a new line when INPUT statement reached past" "\\|NOTE 485-185: Informat .* was not found" "\\|NOTE: Estimated G matrix is not positive definite." "\\|NOTE: Compressing data set .* increased size by" "\\|NOTE: ERROR DETECTED IN ANNOTATE=" "\\|WARNING: Apparent symbolic reference .* not resolved." "\\|WARNING: Length of character variable has already been set." "\\|WARNING: Not all variables in the list " "\\|WARNING: RUN statement ignored due to previous errors." "\\|WARNING: Values exist outside the axis range" "\\|WARNING: Truncated record." "\\|Bus Error In Task\\|Segmentation Violation In Task")) (ess-sas-save-point nil)); (ess-sas-pop-mark nil)) (if (ess-sas-goto "log" 'revert) (progn (setq ess-sas-save-point (point)) (goto-char (point-min))) (setq ess-sas-save-point (point))) ;(if (number-char-or-marker-p ess-sas-save-point) (progn (if ess-tmp-no-error-check (goto-char ess-sas-save-point) (if (or (search-forward-regexp ess-sas-error nil t) (and (goto-char (point-min)) (search-forward-regexp ess-sas-error nil t))) t (goto-char ess-sas-save-point))))) (defun ess-sas-goto-lst () "Switch to the .lst file and revert from disk." (interactive) (ess-sas-goto "lst" 'revert)) (defun ess-sas-goto-sas (&optional revert) "Switch to the .sas file." (interactive) (ess-sas-goto "sas" revert)) (defun ess-sas-goto-shell (&optional set-buffer) "Set `ess-sas-file-path' and goto `ess-sas-shell-buffer'. If optional argument is non-nil, then set-buffer rather than switch." (interactive) (ess-sas-file-path) ; The following let* block is an attempt to deal with remote directories. (let* ((temp-shell-buffer-remote-host (or ess-sas-shell-buffer-remote-host (ess-sas-file-path-remote-host))) (temp-shell-buffer-remote-init ess-sas-shell-buffer-remote-init) (temp-shell-buffer (if temp-shell-buffer-remote-host (concat "*" temp-shell-buffer-remote-host "*") ess-sas-shell-buffer)) ) (if (get-buffer temp-shell-buffer) (if set-buffer (set-buffer temp-shell-buffer) (switch-to-buffer temp-shell-buffer)) (shell) (rename-buffer temp-shell-buffer) (ess-sleep) ; GNU Emacs needs this (if temp-shell-buffer-remote-host (progn (insert (concat temp-shell-buffer-remote-init " " temp-shell-buffer-remote-host)) (comint-send-input)) ) (if (eq ess-sas-submit-method 'sh) (add-hook 'comint-output-filter-functions #'ess-exit-notify-sh)) ;; 19.28 ;; nil t) works for newer emacsen ) ) (goto-char (point-max)) ; (insert "cd " ess-temp-directory) ; (comint-send-input)) ) (defun ess-sas-interactive () "And now for something completely different." (interactive) ;;(ess-sas-file-path) (setq ess-local-customize-alist SAS-customize-alist) ;; (let ((ess-temp-sas-file ;; (nth 0 (split-string ;; (car (last (split-string ess-sas-file-path "\\([a-zA-Z][a-zA-Z]:\\|]\\)"))) "[.]")))) (setq ess-sas-shell-buffer "*iESS[SAS]*") (ess-sas-goto-shell) (ess-add-ess-process) (ess-setq-vars-local ess-local-customize-alist) (inferior-ess-mode) (ess-eval-linewise (concat ess-sas-submit-command " " ess-sas-submit-command-options " -stdio")) ;;" -altlog " ess-temp-sas-file ".log -altprint " ;; ess-temp-sas-file ".lst -stdio")) (ess-sas-goto-sas) (setq ess-sas-submit-method 'iESS) (setq ess-eval-visibly-p nil) ) ;;(defun ess-sas-interactive () ;; (interactive) ;; (ess-sas-file-path) ;; (setq ess-sas-submit-method 'iESS) ;; ;; (let ((ess-temp-stderr " ") (ess-temp-stdout " ") (ess-temp-stdin " ")) ;; (setq ess-sas-shell-buffer "*LOG*") ;; (ess-sas-goto-shell) ;; (insert "tty") ;; (comint-send-input) ;; (sleep-for ess-sleep-for) ;; (save-excursion (setq ess-temp-stderr (ess-search-except "\\(/dev/[a-z0-9/]+\\)" nil t))) ;; (setq ess-sas-shell-buffer "*OUTPUT*") ;; (ess-sas-goto-shell) ;; (insert "tty") ;; (comint-send-input) ;; (sleep-for ess-sleep-for) ;; (save-excursion (setq ess-temp-stdout (ess-search-except "\\(/dev/[a-z0-9/]+\\)" nil t))) ;; (setq ess-sas-shell-buffer "*PROGRAM*") ;; (ess-sas-goto-shell) ;;;; (insert "tty") ;; (comint-send-input) ;; (sleep-for ess-sleep-for) ;; (insert "sh") ;; (comint-send-input) ;; (sleep-for ess-sleep-for) ;; (save-excursion (setq ess-temp-stdin (ess-search-except "\\(/dev/[a-z0-9/]+\\)" nil t))) ;; (insert (concat ess-sas-submit-command " " ess-sas-submit-command-options " -stdio <" ;; ess-temp-stdin " >1 " ess-temp-stdout " >2 " ess-temp-stderr)) ;; (comint-send-input) ;; (ess-add-ess-process) ;; (ess-sas-goto-sas) ;;)) (defun ess-sas-kill-buffers () "Kill all buffers related to a .sas file." (interactive) (ess-sas-file-path) (ess-sas-goto "log" nil t) (kill-buffer nil) (ess-sas-goto "lst" nil t) (kill-buffer nil) (ess-sas-goto ess-sas-suffix-1 nil t) (kill-buffer nil) (ess-sas-goto ess-sas-suffix-2 nil t) (kill-buffer nil) (ess-sas-goto "sas" nil t) (kill-buffer nil) ) ; else (defun ess-sas-rtf-portrait (&optional _ess-tmp-font-size) "Creates an MS RTF portrait file from the current buffer." (interactive) (ess-revert-wisely) (set-visited-file-name (concat (buffer-name) ".rtf")) (when buffer-read-only (setq buffer-read-only nil)) (ess-rtf-replace-chars) (goto-char (point-min)) (insert (concat "{\\rtf1\\ansi{\\fonttbl\\f1\\fmodern " ess-sas-rtf-font-name ";}\n" "\\margl720\\margr720\\margt720\\margb720\n" "{\\colortbl;\\red0\\green0\\blue0;\\red0\\green0\\blue255;\\red0\\green255\\blue255;\\red0\\green255\\blue0;\\red255\\green0\\blue255;\\red255\\green0\\blue0;\\red255\\green255\\blue0;\\red255\\green255\\blue255;\\red0\\green0\\blue128;\\red0\\green128\\blue128;\\red0\\green128\\blue0;\\red128\\green0\\blue128;\\red128\\green0\\blue0;\\red128\\green128\\blue0;\\red128\\green128\\blue128;\\red192\\green192\\blue192;}\n" "{\\stylesheet{\\s15\\plain\\f1\\fs16\\cf1\\cb8\\lang1024 Emacs Text;}{\\*\\cs16 \\additive\\f1\\fs16\\cf1\\cb8\\lang1024 Emacs Base Style;}}\n" "{\\plain\\s15{\\cs16\\cs16\\f1\\fs16\\cf1\\cb8\\lang1024{\\cs16\\f1\\fs16\\cf1\\cb8\\lang1024\n")) (goto-char (point-max)) (insert "}}}}\n") (save-buffer) (kill-buffer (current-buffer))) (defun ess-rtf-replace-chars () "Convert a text file to an MS RTF file." (interactive) (goto-char (point-min)) (while (re-search-forward "\n" nil t) (replace-match "\\par\n" nil t)) (goto-char (point-min)) (while (re-search-forward "\f" nil t) (replace-match "\\page\n" nil t)) (goto-char (point-min)) (while (re-search-forward "\t" nil t) (replace-match "\\tab" nil t))) (defun ess-sas-rtf-landscape (&optional _ess-tmp-font-size) "Creates an MS RTF landscape file from the current buffer." (interactive) (ess-revert-wisely) (set-visited-file-name (concat (buffer-name) ".rtf")) (when buffer-read-only (setq buffer-read-only nil)) (ess-rtf-replace-chars) (goto-char (point-min)) (insert (concat "{\\rtf1\\ansi{\\fonttbl\\f1\\fmodern " ess-sas-rtf-font-name ";}\n" "\\margl720\\margr720\\margt720\\margb720\n" "{\\*\\pgdsctbl\n" "{\\pgdsc0\\pgdscuse195\\lndscpsxn\\pgwsxn15840\\pghsxn12240\\marglsxn1800\\margrsxn1800\\margtsxn1440\\margbsxn1440\\pgdscnxt0 Default;}}\n" "\\landscape\\paperh12240\\paperw15840\\margl1800\\margr1800\\margt1440\\margb1440\\sectd\\sbknone\\lndscpsxn\\pgwsxn15840\\pghsxn12240\\marglsxn1800\\margrsxn1800\\margtsxn1440\\margbsxn1440\\ftnbj\\ftnstart1\\ftnrstcont\\ftnnar\\aenddoc\\aftnrstcont\\aftnstart1\\aftnnrlc\n" "{\\colortbl;\\red0\\green0\\blue0;\\red0\\green0\\blue255;\\red0\\green255\\blue255;\\red0\\green255\\blue0;\\red255\\green0\\blue255;\\red255\\green0\\blue0;\\red255\\green255\\blue0;\\red255\\green255\\blue255;\\red0\\green0\\blue128;\\red0\\green128\\blue128;\\red0\\green128\\blue0;\\red128\\green0\\blue128;\\red128\\green0\\blue0;\\red128\\green128\\blue0;\\red128\\green128\\blue128;\\red192\\green192\\blue192;}\n" "{\\stylesheet{\\s15\\plain\\f1\\fs16\\cf1\\cb8\\lang1024 Emacs Text;}{\\*\\cs16 \\additive\\f1\\fs16\\cf1\\cb8\\lang1024 Emacs Base Style;}}\n" "{\\plain\\s15{\\cs16\\cs16\\f1\\fs16\\cf1\\cb8\\lang1024{\\cs16\\f1\\fs16\\cf1\\cb8\\lang1024\n")) (goto-char (point-max)) (insert "}}}}\n") (save-buffer) (kill-buffer (current-buffer))) (defun ess-sas-rtf-us-landscape () "Creates an MS RTF US landscape file from the current buffer." (interactive) (ess-sas-rtf-portrait "16") (ess-sas-goto "rtf" t) (goto-char (point-min)) (forward-line 3) (insert (concat "{\\*\\pgdsctbl\n" "{\\pgdsc0\\pgdscuse195\\lndscpsxn\\pgwsxn15840\\pghsxn12240\\marglsxn1800\\margrsxn1800\\margtsxn1440\\margbsxn1440\\pgdscnxt0 Default;}}\n" "\\landscape\\paperh12240\\paperw15840\\margl1800\\margr1800\\margt1440\\margb1440\\sectd\\sbknone\\lndscpsxn\\pgwsxn15840\\pghsxn12240\\marglsxn1800\\margrsxn1800\\margtsxn1440\\margbsxn1440\\ftnbj\\ftnstart1\\ftnrstcont\\ftnnar\\aenddoc\\aftnrstcont\\aftnstart1\\aftnnrlc\n")) (save-buffer) (kill-buffer (current-buffer))) (defun ess-sas-rtf-a4-landscape () "Creates an MS RTF A4 landscape file from the current buffer." (interactive) (ess-sas-rtf-portrait "16") (ess-sas-goto "rtf" t) (goto-char (point-min)) (forward-line 3) (insert (concat "{\\*\\pgdsctbl\n" "{\\pgdsc0\\pgdscuse195\\lndscpsxn\\pgwsxn16837\\pghsxn11905\\marglsxn1800\\margrsxn1800\\margtsxn1440\\margbsxn1440\\pgdscnxt0 Default;}}\n" "\\landscape\\paperh11905\\paperw16837\\margl1800\\margr1800\\margt1440\\margb1440\\sectd\\sbknone\\lndscpsxn\\pgwsxn16837\\pghsxn11905\\marglsxn1800\\margrsxn1800\\margtsxn1440\\margbsxn1440\\ftnbj\\ftnstart1\\ftnrstcont\\ftnnar\\aenddoc\\aftnrstcont\\aftnstart1\\aftnnrlc\n")) (save-buffer) (kill-buffer (current-buffer))) (defun ess-sas-submit () "Save the .sas file and submit to shell using a function that depends on the value of `ess-sas-submit-method'" (interactive) (ess-sas-file-path) (ess-sas-goto-sas) (save-buffer) (hack-local-variables) ;(ess-save-and-set-local-variables) (cond ((eq ess-sas-submit-method 'ms-dos) (ess-sas-submit-windows ess-sas-submit-command ess-sas-submit-command-options)) ((eq ess-sas-submit-method 'iESS) (ess-sas-submit-iESS ess-sas-submit-command ess-sas-submit-command-options)) ((eq ess-sas-submit-method 'sh) (ess-sas-submit-sh ess-sas-submit-command ess-sas-submit-command-options)) (t (ess-sas-submit-sh ess-sas-submit-command ess-sas-submit-command-options))) ; (ess-sas-goto-sas) ) (defun ess-sas-submit-iESS (arg1 arg2) "iESS Submit a batch job in an inferior-ESS buffer. The buffer should (1) have telnet access and be running a shell on a remote machine or (2) be running a shell on the local machine. The user can telnet to the remote computer and then declare the *telnet-buffer* to be an inferior ESS buffer with the `ess-add-ess-process' command. When using a remote computer, the .sas file must live on the remote computer and be accessed through `ange-ftp'. When `ess-sas-submit' saves a file, it is therefore saved on the remote computer. The various functions such as `ess-sas-goto-lst' retrieve their files from the remote computer. Local copies of the .sas .lst .log and others may be made manually with `write-buffer'." ;; (ess-eval-linewise (concat "cd default-directory)) (ess-force-buffer-current "Process to load into: ") (ess-eval-linewise (concat "cd " (car (last (split-string (file-name-directory ess-sas-file-path) "\\(:\\|]\\)"))))) (ess-eval-linewise (concat arg1 " " arg2 " " (buffer-name) " &"))) (defun ess-sas-submit-region () "Write region to temporary file, and submit to SAS." (interactive) (ess-sas-file-path) (hack-local-variables t) (write-region (region-beginning) (region-end) (concat (ess-sas-temp-root) ".sas")) (let ((arg1 ess-sas-submit-command) (arg2 ess-sas-submit-command-options)) (save-excursion (ess-sas-goto-shell t) (if (and (when ;; Silence byte compiler warns about w32-fns (fboundp 'w32-shell-dos-semantics) (w32-shell-dos-semantics)) (string-equal ":" (substring ess-sas-file-path 1 2))) (progn (insert (substring ess-sas-file-path 0 2)) (comint-send-input) )) (insert "cd \"" (convert-standard-filename (file-name-directory ess-sas-file-path)) "\"") (comint-send-input) (insert (concat ess-sas-submit-pre-command " " arg1 " " arg2 " " (ess-sas-temp-root) " " ess-sas-submit-post-command)) (comint-send-input) )) ) (defun ess-sas-submit-sh (arg1 arg2) "Unix or bash in the *shell* buffer. Multiple processing is supported on this platform. SAS may not be found in your PATH. You can alter your PATH to include SAS or you can specify the PATHNAME (PATHNAME can NOT contain spaces), i.e. let arg1 be your local equivalent of \"/usr/local/sas612/sas\"." (if (string-equal (substring (file-name-nondirectory ess-sas-file-path) 0 1) ess-kermit-prefix) (progn (ess-kermit-send) (ess-sas-goto-shell t) (insert ess-sas-submit-pre-command " " arg1 " " (substring (file-name-sans-extension (file-name-nondirectory ess-sas-file-path)) 1) " " arg2 " " ess-sas-submit-post-command) (comint-send-input)) ;;else ;; (ess-sas-goto-shell t) (ess-sas-cd) ; (insert "cd " (car (last (split-string (file-name-directory ess-sas-file-path) ;"\\([a-zA-Z][a-zA-Z]:\\|]\\)")))) ; (comint-send-input) (insert ess-sas-submit-pre-command " " arg1 " " (file-name-sans-extension (file-name-nondirectory ess-sas-file-path)) " " arg2 " " ess-sas-submit-post-command)) ; (ess-sleep) (comint-send-input)) (defun ess-sas-submit-windows (arg1 arg2) "Windows using MS-DOS prompt in the *shell* buffer. Multiple processing is supported on this platform. On most Windows installations, SAS will not be found in your PATH so you should alter your PATH to include SAS, i.e. SET PATH=%PATH%;C:\\Program Files\\SAS Or you can specify the PATHNAME directly (you must escape spaces by enclosing the string in \\\"'s), i.e. let `ess-sas-submit-command' be \"\\\"C:\\Program Files\\SAS\\sas.exe\\\"\". Keep in mind that the maximum command line length in MS-DOS is 127 characters so altering your PATH is preferable." ;(ess-save-and-set-local-variables) (ess-sas-goto-shell t) (if (string-equal ":" (substring ess-sas-file-path 1 2)) (progn (insert (substring ess-sas-file-path 0 2)) (comint-send-input) ) ) (insert "cd \"" (convert-standard-filename (file-name-directory ess-sas-file-path)) "\"") (comint-send-input) (insert ess-sas-submit-pre-command " " arg1 " -sysin \"" (file-name-sans-extension (file-name-nondirectory ess-sas-file-path)) "\" " arg2 " " ess-sas-submit-post-command) (comint-send-input)) (defun ess-sas-tab-to-tab-stop () "Tab to next tab-stop and set left margin." (interactive) (tab-to-tab-stop) (setq left-margin (current-column)) ) (defun ess-sas-temp-root () "Return `ess-sas-file-path' sans extension with `ess-sas-temp-root' appended." (concat (file-name-sans-extension ess-sas-file-path) ess-sas-temp-root)) (defun ess-sas-transcript (&optional strip) "Comment .log messages to create a .sas program; use C-u to strip." (interactive "P") (save-excursion (goto-char (point-min)) (while (search-forward-regexp (concat "^\\(\\(1[ \t]+The SAS System\\| \\|NOTE\\|WARNING\\|ERROR\\|" "[ \t]+\\(\\(real\\|cpu\\) time\\|Licensed to\\|Engine:\\|" "Physical Name:\\|File Name=\\|Owner Name=\\|Group Name=\\|" "Access Permission=\\|File Size (bytes)=\\|Pipe command=\\|" "RECFM=[DFNPV],LRECL=\\|[0-9]+:[0-9]+[ /t]+[0-9]+:[0-9]+\\|" "[1-9][0-9]* at [0-9]+:[0-9]+[ /t]+[1-9][0-9]* at [0-9]+:[0-9]+\\)\\).*$" "\\|[0-9]+\\([ \t]+!\\)?\\|MPRINT([_A-Z]+):\\|" "[ \t]+\\(values at the places given by: (Line):(Column).\\|" "The m\\(in\\|ax\\)imum record length was [1-9][0-9]*.\\|" "One or more lines were truncated.\\|" "Each place is given by: (Number of times) at (Line):(Column).\\|" "[0-9][0-9]:[0-9][0-9] [MTWFS][aeioudhnrst]+day, [JFMASOND]" "[aeiouybcghlmnprstv]+ [1-9][0-9]?, 20[0-9][0-9]\\)\\)") nil t) (replace-match (if strip " " "/*\\&*/") t)) )) (defun ess-sas-toggle-sas-listing-mode (&optional _force) "Toggle SAS-listing-mode for .lst files." (interactive) (ess-sas-goto-lst) (if (equal (cdr (assoc "\\.[lL][sS][tT]\\'" auto-mode-alist)) 'SAS-listing-mode) (progn (setq auto-mode-alist (delete '("\\.[lL][sS][tT]\\'" . SAS-listing-mode) auto-mode-alist)) (setq buffer-read-only nil) (ess-listing-minor-mode 0)) (setq auto-mode-alist (append '(("\\.[lL][sS][tT]\\'" . SAS-listing-mode)) auto-mode-alist)) (setq buffer-read-only t) (ess-listing-minor-mode 1))) (defun ess-sas-toggle-sas-log-mode () "Toggle SAS-log-mode for .log files." (interactive) (ess-sas-goto-log) (kill-buffer nil) ; (if (equal (cdr (assoc "\\.[lL][oO][gG]\\'" auto-mode-alist)) 'SAS-log-mode) (progn ; (setq auto-mode-alist (delete '("\\.[lL][oO][gG]\\'" . SAS-log-mode) auto-mode-alist)) ; (setq buffer-read-only nil) ; (ess-transcript-minor-mode 0) ; (font-lock-mode 0)) ; (setq auto-mode-alist (append '(("\\.[lL][oO][gG]\\'" . SAS-log-mode)) auto-mode-alist)) ; (setq buffer-read-only t) ; (ess-transcript-minor-mode 1) ; (font-lock-mode 1) ; (font-lock-fontify-buffer)) (if (equal (cdr (assoc "\\.[lL][oO][gG]\\'" auto-mode-alist)) 'SAS-log-mode) (setq auto-mode-alist (delete '("\\.[lL][oO][gG]\\'" . SAS-log-mode) auto-mode-alist)) (setq auto-mode-alist (append '(("\\.[lL][oO][gG]\\'" . SAS-log-mode)) auto-mode-alist))) (ess-sas-goto-log)) (define-obsolete-variable-alias 'ess-sas-versions-created 'ess-sas-created-runners "ESS 18.10") (defvar ess-sas-created-runners) (defun ess-sas-define-runners () "Generate the `M-x SASV' functions for starting other versions of SAS. See `ess-sas-versions' for strings that determine which functions are created. The local variable `ess-sas-created-runners' is used to return list of the new SAS defuns, if any, that were created. The defuns will normally be placed on the menubar upon ESS initialization." ;; This works by creating a temp buffer where the template function is ;; edited so that V is replaced by the version number (let ((versions ;; Find which versions of SAS we want. Remove the pathname, ;; leaving just the name of the executable. (delete-dups (mapcar #'file-name-nondirectory (apply #'nconc (mapcar #'ess-find-exec-completions ess-sas-versions)))))) ;; Iterate over each string in VERSIONS, creating a new defun each time. (setq ess-sas-created-runners (mapc (lambda (v) (ess-define-runner v "SAS")) versions)))) (define-obsolete-function-alias 'ess-sas-create-versions #'ess-sas-define-runners "ESS 18.10") ;;; Section 3: Key Definitions (defun ess-sas-edit-keys-set (&optional arg) "Set TAB/RET key in `SAS-mode'. If arg is nil TAB is `sas-indent-line' and RET is `newline-and-indent'. Else TAB is `ess-sas-tab-to-tab-stop', C-TAB is `ess-sas-backward-delete-tab' and RET is `newline'." (interactive) (when arg ;; TODO: Why is this set up this way? (define-key sas-mode-local-map [(control tab)] #'ess-sas-backward-delete-tab) (define-key sas-mode-local-map [return] #'newline) (define-key sas-mode-local-map "\t" #'ess-sas-tab-to-tab-stop))) (defvar ess-sas-edit-keys-toggle nil "Toggle TAB/RET key in `SAS-mode'. nil binds TAB to `sas-indent-line' and RET to `newline-and-indent'. Non-nil binds TAB to `ess-sas-tab-to-tab-stop', C-TAB to `ess-sas-backward-delete-tab', and RET to `newline'.") (defun ess-sas-edit-keys-toggle (&optional _arg) "Toggle `ess-sas-edit-keys-toggle'. Optional arg is still accepted for backward compatibility, however, arg is ignored." (interactive) (setq ess-sas-edit-keys-toggle (not ess-sas-edit-keys-toggle)) (ess-sas-edit-keys-set ess-sas-edit-keys-toggle) ) (defvar ess-sas-global-pc-keys nil "Non-nil if function keys use PC-like SAS key definitions in all modes.") (defun ess-sas-global-pc-keys () "PC-like SAS key definitions" (interactive) (global-set-key [(control f1)] #'ess-sas-rtf-portrait) (global-set-key [(control f2)] #'ess-sas-rtf-landscape) (global-set-key (quote [f2]) #'ess-revert-wisely) (global-set-key (quote [f3]) #'ess-sas-goto-shell) (global-set-key (quote [f4]) #'ess-sas-goto-file-1) (global-set-key (quote [f5]) #'ess-sas-goto-sas) (global-set-key (quote [f6]) #'ess-sas-goto-log) (global-set-key [(control f6)] #'ess-sas-append-log) (global-set-key (quote [f7]) #'ess-sas-goto-lst) (global-set-key [(control f7)] #'ess-sas-append-lst) (global-set-key (quote [f8]) #'ess-sas-submit) (global-set-key [(control f8)] #'ess-sas-submit-region) (global-set-key (quote [f9]) #'ess-sas-data-view-fsview) (global-set-key [(control f9)] #'ess-sas-data-view-insight) ;; (global-set-key (quote [f10]) #'ess-sas-toggle-sas-log-mode) ;; (global-set-key [(control f10)] #'ess-sas-toggle-sas-listing-mode) ;; (global-set-key (quote [f11]) #'ess-sas-goto-file-2) ;; (global-set-key [(control f11)] #'ess-ebcdic-to-ascii-search-and-replace) (global-set-key (quote [f12]) #'ess-sas-graph-view) (global-set-key [(control tab)] #'ess-sas-backward-delete-tab) ;; (define-key sas-mode-local-map "\C-c\C-p" #'ess-sas-file-path) (setq ess-sas-global-pc-keys t) (setq ess-sas-global-unix-keys nil) (setq ess-sas-local-pc-keys nil) (setq ess-sas-local-unix-keys nil) ) (defun ess-sas-global-unix-keys () "Unix/Mainframe-like SAS key definitions" (interactive) (global-set-key [(control f1)] #'ess-sas-rtf-portrait) (global-set-key [(control f2)] #'ess-sas-rtf-landscape) (global-set-key (quote [f2]) #'ess-revert-wisely) (global-set-key (quote [f3]) #'ess-sas-submit) (global-set-key [(control f3)] #'ess-sas-submit-region) (global-set-key (quote [f4]) #'ess-sas-goto-sas) (global-set-key (quote [f5]) #'ess-sas-goto-log) (global-set-key [(control f5)] #'ess-sas-append-log) (global-set-key (quote [f6]) #'ess-sas-goto-lst) (global-set-key [(control f6)] #'ess-sas-append-lst) (global-set-key (quote [f7]) #'ess-sas-goto-file-1) (global-set-key (quote [f8]) #'ess-sas-goto-shell) (global-set-key (quote [f9]) #'ess-sas-data-view-fsview) (global-set-key [(control f9)] #'ess-sas-data-view-insight) ;; (global-set-key (quote [f10]) #'ess-sas-toggle-sas-log-mode) ;; (global-set-key [(control f10)] #'ess-sas-toggle-sas-listing-mode) ;; (global-set-key (quote [f11]) #'ess-sas-goto-file-2) ;; (global-set-key [(control f11)] #'ess-ebcdic-to-ascii-search-and-replace) (global-set-key (quote [f12]) #'ess-sas-graph-view) (global-set-key [(control tab)] #'ess-sas-backward-delete-tab) ;;(define-key sas-mode-local-map "\C-c\C-p" #'ess-sas-file-path) (setq ess-sas-global-pc-keys nil) (setq ess-sas-global-unix-keys t) (setq ess-sas-local-pc-keys nil) (setq ess-sas-local-unix-keys nil) ) (defun ess-sas-local-pc-keys () "PC-like SAS key definitions." (interactive) (define-key sas-mode-local-map [(control f1)] #'ess-sas-rtf-portrait) (define-key sas-mode-local-map [(control f2)] #'ess-sas-rtf-landscape) (define-key sas-mode-local-map (quote [f2]) #'ess-revert-wisely) (define-key sas-mode-local-map (quote [f3]) #'ess-sas-goto-shell) (define-key sas-mode-local-map (quote [f4]) #'ess-sas-goto-file-1) (define-key sas-mode-local-map (quote [f5]) #'ess-sas-goto-sas) (define-key sas-mode-local-map (quote [f6]) #'ess-sas-goto-log) (define-key sas-mode-local-map [(control f6)] #'ess-sas-append-log) (define-key sas-mode-local-map (quote [f7]) #'ess-sas-goto-lst) (define-key sas-mode-local-map [(control f7)] #'ess-sas-append-lst) (define-key sas-mode-local-map (quote [f8]) #'ess-sas-submit) (define-key sas-mode-local-map [(control f8)] #'ess-sas-submit-region) (define-key sas-mode-local-map (quote [f9]) #'ess-sas-data-view-fsview) (define-key sas-mode-local-map [(control f9)] #'ess-sas-data-view-insight) (define-key sas-mode-local-map (quote [f10]) #'ess-sas-toggle-sas-log-mode) (define-key sas-mode-local-map [(control f10)] #'ess-sas-toggle-sas-listing-mode) (define-key sas-mode-local-map (quote [f11]) #'ess-sas-goto-file-2) (define-key sas-mode-local-map [(control f11)] #'ess-ebcdic-to-ascii-search-and-replace) (define-key sas-mode-local-map (quote [f12]) #'ess-sas-graph-view) ;(define-key sas-mode-local-map "\C-c\C-p" #'ess-sas-file-path) (setq ess-sas-global-pc-keys nil) (setq ess-sas-global-unix-keys nil) (setq ess-sas-local-pc-keys t) (setq ess-sas-local-unix-keys nil) ) (defun ess-sas-local-unix-keys () "Unix/Mainframe-like SAS key definitions" (interactive) (define-key sas-mode-local-map [(control f1)] #'ess-sas-rtf-portrait) (define-key sas-mode-local-map [(control f2)] #'ess-sas-rtf-landscape) (define-key sas-mode-local-map (quote [f2]) #'ess-revert-wisely) (define-key sas-mode-local-map (quote [f3]) #'ess-sas-submit) (define-key sas-mode-local-map [(control f3)] #'ess-sas-submit-region) (define-key sas-mode-local-map (quote [f4]) #'ess-sas-goto-sas) (define-key sas-mode-local-map (quote [f5]) #'ess-sas-goto-log) (define-key sas-mode-local-map [(control f5)] #'ess-sas-append-log) (define-key sas-mode-local-map (quote [f6]) #'ess-sas-goto-lst) (define-key sas-mode-local-map [(control f6)] #'ess-sas-append-lst) (define-key sas-mode-local-map (quote [f7]) #'ess-sas-goto-file-1) (define-key sas-mode-local-map (quote [f8]) #'ess-sas-goto-shell) (define-key sas-mode-local-map (quote [f9]) #'ess-sas-data-view-fsview) (define-key sas-mode-local-map [(control f9)] #'ess-sas-data-view-insight) (define-key sas-mode-local-map (quote [f10]) #'ess-sas-toggle-sas-log-mode) (define-key sas-mode-local-map [(control f10)] #'ess-sas-toggle-sas-listing-mode) (define-key sas-mode-local-map (quote [f11]) #'ess-sas-goto-file-2) (define-key sas-mode-local-map [(control f11)] #'ess-ebcdic-to-ascii-search-and-replace) (define-key sas-mode-local-map (quote [f12]) #'ess-sas-graph-view) ;;(define-key sas-mode-local-map "\C-c\C-p" #'ess-sas-file-path) (setq ess-sas-global-pc-keys nil) (setq ess-sas-global-unix-keys nil) (setq ess-sas-local-pc-keys nil) (setq ess-sas-local-unix-keys t) ) (defun ess-kermit-get (&optional ess-file-arg ess-dir-arg) "Get a file with Kermit. WARNING: Experimental! From your *shell* buffer, start kermit and then log in to the remote machine. Open a file that starts with `ess-kermit-prefix'. From that buffer, execute this command. It will retrieve a file from the remote directory that you specify with the same name, but without the `ess-kermit-prefix'." (interactive) ;; (save-match-data (let ((ess-temp-file (if ess-file-arg ess-file-arg (buffer-name))) (ess-temp-file-remote-directory ess-dir-arg)) (if (string-equal ess-kermit-prefix (substring ess-temp-file 0 1)) (progn ;; I think there is a bug in the buffer-local variable handling in GNU Emacs 21.3 ;; Setting ess-kermit-remote-directory every time is somehow resetting it to the ;; default on the second pass. So, here's a temporary work-around. It will fail ;; if you change the default, so maybe this variable should not be customizable. ;; In any case, there is also trouble with local variables in XEmacs 21.4.9 and ;; 21.4.10. XEmacs 21.4.8 is fine. (if ess-temp-file-remote-directory (setq ess-kermit-remote-directory ess-temp-file-remote-directory) (if (string-equal "." ess-kermit-remote-directory) (setq ess-kermit-remote-directory (read-string "Remote directory to transfer file from: " ess-kermit-remote-directory)))) (setq ess-temp-file-remote-directory ess-kermit-remote-directory) ;; (setq ess-temp-file (substring ess-temp-file (match-end 0))) (ess-sas-goto-shell) (insert "cd " ess-temp-file-remote-directory "; " ess-kermit-command " -s " (substring ess-temp-file 1) " -a " ess-temp-file) (comint-send-input) ;; (insert (read-string "Press Return to connect to Kermit: " nil nil "\C-\\c")) ;; (comint-send-input) ;; (insert (read-string "Press Return when Kermit is ready to receive: " nil nil ;; (concat "receive ]" ess-sas-temp-file))) ;; (comint-send-input) ;; (insert (read-string "Press Return when transfer is complete: " nil nil "c")) ;; (comint-send-input) (insert (read-string "Press Return when shell is ready: ")) (comint-send-input) (switch-to-buffer (find-buffer-visiting ess-temp-file)) (ess-revert-wisely) )))) (defun ess-kermit-send () "Send a file with Kermit. WARNING: Experimental! From a file that starts with `ess-kermit-prefix', execute this command. It will transfer this file to the remote directory with the same name, but without the `ess-kermit-prefix'." (interactive) ;; (save-match-data (let ((ess-temp-file (expand-file-name (buffer-name))) (ess-temp-file-remote-directory nil)) (if (string-equal ess-kermit-prefix (substring (file-name-nondirectory ess-temp-file) 0 1)) (progn ;; I think there is a bug in the buffer-local variable handling in GNU Emacs 21.3 ;; Setting ess-kermit-remote-directory every time is somehow resetting it to the ;; default on the second pass. Here's a temporary work-around. It will fail ;; if you change the default, so maybe this variable should not be customizable. ;; In any case, there is also trouble with local variables in XEmacs 21.4.9 and ;; 21.4.10. XEmacs 21.4.8 is fine. (if (string-equal "." ess-kermit-remote-directory) (setq ess-kermit-remote-directory (read-string "Remote directory to transfer file to: " ess-kermit-remote-directory))) (setq ess-temp-file-remote-directory ess-kermit-remote-directory) ;; (setq ess-temp-file (substring ess-temp-file (match-end 0))) (ess-sas-goto-shell) (insert "cd " ess-temp-file-remote-directory "; " ess-kermit-command " -a " (substring (file-name-nondirectory ess-temp-file) 1) " -g " ess-temp-file) (comint-send-input) ;; (insert (read-string "Press Return to connect to Kermit: " nil nil "\C-\\c")) ;; (comint-send-input) ;; (insert (read-string "Press Return when Kermit is ready to receive: " nil nil ;; (concat "receive ]" ess-sas-temp-file))) ;; (comint-send-input) ;; (insert (read-string "Press Return when transfer is complete: " nil nil "c")) ;; (comint-send-input) (insert (read-string "Press Return when shell is ready: ")) (comint-send-input) (switch-to-buffer (find-buffer-visiting ess-temp-file)) (ess-revert-wisely) )))) (provide 'ess-sas-a) ;;; ess-sas-a.el ends here ESS-24.01.1/lisp/ess-sas-d.el000066400000000000000000000303671455642170100154170ustar00rootroot00000000000000;;; ess-sas-d.el --- SAS customization -*- lexical-binding: t; -*- ;; Copyright (C) 1997-2022 Free Software Foundation, Inc. ;; Author: Richard M. Heiberger ;; Created: 20 Aug 1997 ;; Maintainer: ESS-core ;; This file is part of GNU Emacs. ;;; License: ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see ;; ;;; Commentary: ;; This file defines all the SAS customizations for ESS behaviors. See ;; ess-sas-l and ess-sas-a for the underlying general modifications. ;;; Code: (require 'shell) (require 'ess-sas-l) (defcustom SAS-mode-hook nil "Hook to run when entering SAS mode." :type 'hook :group 'ess-sas) (defvar inferior-SAS-args "-stdio -linesize 80 -noovp -nosyntaxcheck" "Arguments to use for starting SAS.") (defvar inferior-SAS-args-temp nil "Hack variable, needed for args preprocessing. Better logic needed! (see 2 uses, in this file).") (defvar SAS-mode-syntax-table (let ((tab (make-syntax-table))) (modify-syntax-entry ?\\ "." tab) ;; backslash is punctuation (modify-syntax-entry ?+ "." tab) (modify-syntax-entry ?- "." tab) (modify-syntax-entry ?= "." tab) (modify-syntax-entry ?% "w" tab) (modify-syntax-entry ?< "." tab) (modify-syntax-entry ?> "." tab) (modify-syntax-entry ?& "w" tab) (modify-syntax-entry ?| "." tab) (modify-syntax-entry ?\' "\"" tab) (modify-syntax-entry ?* ". 23" tab) ; comment character (modify-syntax-entry ?\; "." tab) (modify-syntax-entry ?_ "w" tab) (modify-syntax-entry ?< "." tab) (modify-syntax-entry ?> "." tab) (modify-syntax-entry ?/ ". 14" tab) ; comment character (modify-syntax-entry ?. "w" tab) tab) "Syntax table for `SAS-mode'.") (defun ess-SAS-pre-run-hook (temp-ess-dialect) "Set up log and list files for interactive SAS." (let* ((ess-shell-buffer-name-flag (get-buffer "*shell*")) ess-shell-buffer-name ;; isn't pretty yet. ;; ess-local-process-name is defined after this function. ;; it needs to be defined prior to this function. (tmp-procname (let ((ntry 0) (done nil)) ;; find a non-existent process (while (not done) (setq ntry (1+ ntry) done (not (get-process (ess-proc-name ntry temp-ess-dialect))))) (ess-proc-name ntry temp-ess-dialect))) ;; Following was tmp-local-process-name. Stolen from inferior-ess (ess-sas-lst-bufname (concat "*" tmp-procname ".lst*")) (ess-sas-log-bufname (concat "*" tmp-procname ".log*")) (explicit-shell-file-name "/bin/sh") inferior-SAS-redirect-args ess-sas-lst ess-sas-log) (ess-write-to-dribble-buffer (format "(ess-SAS-pre-run-hook 1): ess-lang=%s, ess-dialect=%s, temp-dialect=%s, buf=%s \n" ess-language ess-dialect temp-ess-dialect (current-buffer))) ;; If someone is running a *shell* buffer, rename it to avoid ;; inadvertent nuking. (if ess-shell-buffer-name-flag (with-current-buffer "*shell*" (setq ess-shell-buffer-name (rename-buffer "*ess-shell-regular*" t)))) ;; Construct the LST buffer for output (if (get-buffer ess-sas-lst-bufname) nil (with-current-buffer (shell) (accept-process-output (get-buffer-process (current-buffer)) 0.2) (sleep-for 2) ; need to wait, else working too fast! (setq ess-sas-lst (ess-insert-accept "tty")) (SAS-listing-mode) (shell-mode) (ess-listing-minor-mode t) (rename-buffer ess-sas-lst-bufname t))) ;; Construct the LOG buffer for output (if (get-buffer ess-sas-log-bufname) nil (with-current-buffer (shell) (accept-process-output (get-buffer-process (current-buffer)) 0.2) (sleep-for 2) ; need to wait, else working too fast! (setq ess-sas-log (ess-insert-accept "tty")) ;(SAS-log-mode) (shell-mode) (ess-transcript-minor-mode t) (rename-buffer ess-sas-log-bufname t))) (setq inferior-SAS-redirect-args (concat " " ess-sas-lst " " ess-sas-log " ") inferior-SAS-args-temp (concat inferior-SAS-redirect-args inferior-SAS-args)) ;; Restore the *shell* buffer (if ess-shell-buffer-name-flag (with-current-buffer ess-shell-buffer-name (rename-buffer "*shell*"))) (delete-other-windows) (split-window-vertically) (split-window-vertically) (switch-to-buffer (nth 2 (buffer-list))) (other-window 2) (switch-to-buffer ess-sas-log-bufname) (split-window-vertically) (other-window 1) (switch-to-buffer ess-sas-lst-bufname) (other-window 2) ;;workaround (setq inferior-SAS-program (concat (file-name-as-directory ess-etc-directory) "ess-sas-sh-command")) (setq inferior-ess-program inferior-SAS-program))) (defun ess-insert-accept (command) "Submit command to process, get next line." (interactive) (goto-char (point-max)) (insert command) (comint-send-input) (accept-process-output (get-buffer-process (current-buffer)) 0.2) (forward-line -1) (let* ((beg (point)) (ess-tty-name (progn (end-of-line) (buffer-substring beg (point))))) (goto-char (point-max)) ess-tty-name)) (defvar SAS-customize-alist '((ess-local-customize-alist . SAS-customize-alist) (ess-language . "SAS") (ess-dialect . "SAS") (inferior-ess-program . inferior-SAS-program) (ess-help-sec-regex . "^[A-Z. ---]+:$") (ess-help-sec-keys-alist . " ") (ess-object-name-db-file . "ess-sas-namedb.el") (inferior-ess-objects-command . "objects(%d)");;FIXME (inferior-ess-help-command . "help(\"%s\",pager=\"cat\",window=F)\n");;FIXME (inferior-ess-exit-command . "endsas;\n") (ess-loop-timeout . 500000 ) (inferior-ess-primary-prompt . "^") (inferior-ess-secondary-prompt . "^") (comint-use-prompt-regexp . t) (inferior-ess-start-args . inferior-SAS-args-temp) ;; (ess-pre-run-hook . 'ess-SAS-pre-run-hook) ;; (ess-local-process-name . nil) ) "Variables to customize for SAS") ;;; The functions of interest (mode, inferior mode) ;;;###autoload (define-derived-mode SAS-mode ess-mode "[SAS]" "Major mode for editing SAS source. See `ess-mode' for more help." :group 'ess-sas (ess-setq-vars-local SAS-customize-alist) (setq ess-local-customize-alist SAS-customize-alist) (setq-local sentence-end ";[\t\n */]*") (setq-local paragraph-start "^[ \t]*$") (setq-local paragraph-separate "^[ \t]*$") (setq-local paragraph-ignore-fill-prefix t) (setq-local adaptive-fill-mode nil) (setq-local indent-line-function #'sas-indent-line) (setq-local comment-start "/*") (setq-local comment-start-skip "/[*]") (setq-local comment-end "*/") (setq-local comment-end-skip "[*]/") (setq-local comment-column 40) (setq-local ess-local-process-name nil) (setq-local tab-stop-list ess-sas-tab-stop-list) (setq-local font-lock-keywords-case-fold-search t) ;; Local map settings, AFTER initialization (only if not yet defined) (unless sas-mode-local-map (setq sas-mode-local-map (copy-keymap (current-local-map))) (ess-sas-edit-keys-set ess-sas-edit-keys-toggle) (if ess-sas-local-unix-keys (ess-sas-local-unix-keys)) (if ess-sas-local-pc-keys (ess-sas-local-pc-keys)) (if ess-sas-global-unix-keys (ess-sas-global-unix-keys)) (if ess-sas-global-pc-keys (ess-sas-global-pc-keys))) (define-key sas-mode-local-map ";" #'ess-electric-run-semicolon) (define-key sas-mode-local-map (kbd "\C-c\C-w") #'ess-multi-frame-SAS) ;; this is a mess ;; interactive and batch commands share sas-mode-local-map, ;; but the associated commands are very different ;; what would be better is two maps like ;; sas-batch-mode-local-map and sas-interactive-mode-local-map ;; or smart function definitions that would do the appropriate ;; thing for either batch or interactive sessions ;; however, neither of these solutions are planned ;; therefore, no key definitions can be shared between ;; batch and interactive at this time, hence the lines that ;; are commented below: uncomment at your own risk ;; (define-key sas-mode-local-map "\C-c\C-p" 'ess-sas-file-path) ;; (define-key sas-mode-local-map "\C-c\C-b" 'ess-sas-submit) ;; (define-key sas-mode-local-map "\C-c\C-r" 'ess-sas-submit-region) ;; (define-key sas-mode-local-map "\C-c\C-x" 'ess-sas-goto-log) ;; (define-key sas-mode-local-map "\C-c\C-y" 'ess-sas-goto-lst) (use-local-map sas-mode-local-map) (setq font-lock-defaults ;; KEYWORDS KEYWORDS-ONLY CASE-FOLD ..... '(SAS-mode-font-lock-defaults nil t))) ;;;###autoload (add-to-list 'auto-mode-alist '("\\.[Ss][Aa][Ss]\\'" . SAS-mode)) ;; rmh Jul 10 2003 (defun ess-electric-run-semicolon (arg) "Insert character. If the line contains \"run;\" or \"quit;\" and nothing else then indent line." (interactive "P") (if ess-sas-edit-keys-toggle (insert ";") (if (and (not arg) (eolp) (save-excursion (skip-chars-backward " \t") (backward-word 1) (and (looking-at "run\\|quit") (progn (skip-chars-backward " \t") (bolp))))) (progn (insert last-command-event) (funcall indent-line-function) (save-excursion (delete-char -1)))) (self-insert-command (prefix-numeric-value arg)))) (defun SAS-menu () "Start SAS from the menu." (interactive) (if ess-microsoft-p ;; replace with other choices for starting SAS? (error "SAS cannot be started this way in ESS on Windows.") (SAS))) (defun SAS () "Call 'SAS', from SAS Institute." (interactive) (let* ((temp-dialect "SAS")) ;(cdr (rassoc ess-dialect SAS-customize-alist)))) (ess-write-to-dribble-buffer (format "(SAS): ess-dial=%s, temp-dial=%s\n" ess-dialect temp-dialect)) (ess-SAS-pre-run-hook temp-dialect) (setq ess-eval-visibly-p nil) ;; FIXME: `inferior-SAS-args' is defined from ;; `inferior-SAS-args-temp' in `ess-SAS-pre-run-hook' (let ((inf-buf (inferior-ess nil SAS-customize-alist))) (with-current-buffer inf-buf (use-local-map sas-mode-local-map)) inf-buf))) (defun ess-multi-frame-SAS () "Put running SAS buffers into separate frames. Load this function M-x load-file essx-sas.el RET. Then find-file myfile.sas. If myfile.sas is already in a buffer, kill-buffer it and then find-file it again. Place the cursor in a myfile.sas buffer. Run SAS with M-x SAS, Return the cursor to the myfile.sas buffer, then enter C-c C-w to put *SAS* *SAS.log* *SAS.lst* buffers into their own frames." (interactive) (delete-other-windows) (with-current-buffer "*SAS*" (make-frame)) (with-current-buffer "*SAS.log*" (make-frame)) (with-current-buffer "*SAS.lst*" (make-frame))) (defun ess-num-or-zero (arg) "If a number, then return that number, otherwise return 0." (or (and (numberp arg) arg) 0)) ; Provide package (provide 'ess-sas-d) ;;; ess-sas-d.el ends here ESS-24.01.1/lisp/ess-sas-l.el000066400000000000000000002253061455642170100154260ustar00rootroot00000000000000;;; ess-sas-l.el --- SAS customization -*- lexical-binding: t; -*- ;; Copyright (C) 1997-2022 Free Software Foundation, Inc. ;; Authors: Richard M. Heiberger ;; A.J. Rossini ;; Rodney Sparapani ;; Created: 20 Aug 1997 ;; Maintainer: ESS-core ;; This file is part of GNU Emacs. ;;; License: ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see ;; ;;; Commentary: ;; This is based upon Version 1.4 of SAS mode: ;;; sas-mode: indent, run etc, SAS programs. ;;; Author: Tom Cook ;;; Dept. of Biostatistics ;;; University of Wisconsin - Madison ;;; Madison, WI 53706 ;;; cook@biostat.wisc.edu ;;; ;;; Acknowledgements: ;;; Menu code for XEmacs/Lucid emacs and startup mods ;;; contributed by arossini@biostats.hmc.psu.edu ;;; ;;; Last change: 2/1/95 ;;; Last change: 01/15/02 ;;; Code: (require 'ess-mode) (require 'ess-sas-a) (declare-function SAS-mode "ess-sas-d") (put 'ess-transcript-minor-mode 'permanent-local t) (or (assq 'ess-transcript-minor-mode minor-mode-alist) (setq minor-mode-alist (append minor-mode-alist (list '(ess-transcript-minor-mode " ESStr"))))) (put 'ess-listing-minor-mode 'permanent-local t) (or (assq 'ess-listing-minor-mode minor-mode-alist) (setq minor-mode-alist (append minor-mode-alist (list '(ess-listing-minor-mode " ESSlst"))))) (defun ess-transcript-minor-mode (&optional arg) "Toggle Ess-Transcript minor mode. With arg, turn Ess-Transcript minor mode on if arg is positive, off otherwise. See the command `ess-transcript-mode' for more information on this mode." (interactive "P") (setq ess-transcript-minor-mode (if (null arg) (not ess-transcript-minor-mode) (> (prefix-numeric-value arg) 0))) (force-mode-line-update) (setq mode-line-process '(" [" ess-local-process-name "]"))) (defun ess-listing-minor-mode (&optional arg) "Toggle Ess-Listing minor mode. With arg, turn Ess-Listing minor mode on if arg is positive, off otherwise. Ess-Listing mode is used solely to place an indicator on the mode line." (interactive "P") (setq ess-listing-minor-mode (if (null arg) (not ess-listing-minor-mode) (> (prefix-numeric-value arg) 0))) (force-mode-line-update) (setq mode-line-process '(" [" ess-local-process-name "]"))) (defcustom ess-automatic-sas-log-or-lst-mode t "Automatically turn on `SAS-log-mode' and `SAS-listing-mode' when enabled." :type 'boolean :group 'ess-sas) (defun ess-SAS-log-mode-p () "Return t when when a SAS log file is detected. A SAS log is defined as having: 1. The first line matches \"^1[ \t]*The SAS System\" 2. The file name ends in .log. " (and ess-automatic-sas-log-or-lst-mode (save-excursion (goto-char (point-min)) (looking-at "1[ \t]*The SAS System")) (if (buffer-file-name) (string-match ".log$" (buffer-file-name)) t))) (defun ess-SAS-listing-mode-p () "Return t when SAS listing file is detected. A .lst file is a SAS listing file when: 1. The file name ends in .lst 2. The corresponding log file exists and is a SAS log file. " (when ess-automatic-sas-log-or-lst-mode (let* ((bfn (buffer-file-name)) (log (and bfn (string-match-p "\\.lst$" bfn) (replace-regexp-in-string "\\.lst$" ".log" bfn)))) (and log (file-exists-p log) (with-temp-buffer (insert-file-contents log nil 0 200) (goto-char (point-min)) (looking-at "1[ \t]*The SAS System")))))) (add-to-list 'magic-mode-alist '(ess-SAS-log-mode-p . SAS-log-mode)) (add-to-list 'magic-mode-alist '(ess-SAS-listing-mode-p . SAS-listing-mode)) (define-derived-mode SAS-log-mode SAS-mode "ESS[LOG]" "`ess-transcript-mode' for SAS." :group 'ess-sas (ess-transcript-minor-mode 1) (setq buffer-read-only t) ;; to protect the buffer. (buffer-disable-undo)) (defvar sas-mode-local-map nil "contains modified local keymap for SAS") (define-derived-mode SAS-listing-mode special-mode "ESS[LST]" "Fundamental mode with `ess-listing-minor-mode' and read-only." :keymap sas-mode-local-map :group 'ess-sas (ess-listing-minor-mode 1) (buffer-disable-undo)) (defalias 'sas-log-mode #'SAS-log-mode) (defalias 'SAS-transcript-mode #'SAS-log-mode) (defalias 'sas-transcript-mode #'SAS-log-mode) (defalias 'sas-mode #'SAS-mode) (defalias 'sas-listing-mode #'SAS-listing-mode) (defcustom sas-indent-width 4 "Amount to indent sas statements." :group 'ess-sas :type 'integer) (defcustom sas-indent-ignore-comment "\\*" "Comments that start with this regular expression are ignored in indentation." :group 'ess-sas :type 'string) (defcustom sas-require-confirmation t "Require confirmation when revisiting a modified sas-output file." :group 'ess-sas :type 'boolean) (defcustom sas-pre-run-hook nil "Hook to execute prior to running SAS via `submit-sas'." :group 'ess-sas :type 'hook) (defcustom sas-notify t "Beep and display message when job is done." :group 'ess-sas :type 'boolean) (defcustom sas-error-notify t "If `sas-notify' t, indicate errors in log file upon completion." :group 'ess-sas :type 'boolean) (defcustom sas-get-options nil "Options to be passed to SAS in sas-get-dataset." :group 'ess-sas :type '(choice (const nil) string)) (defcustom sas-get-options-history nil "History list of Options passed to SAS in sas-get-dataset." :type '(choice (const nil) (string)) :group 'ess-sas) (defcustom sas-page-number-max-line 3 "Number of lines from the page break, to search for the page number." :group 'ess-sas :type 'integer) (defcustom sas-notify-popup nil "If this and `sas-notify' are t), popup a window when SAS job ends." :group 'ess-sas :type 'boolean) (defcustom sas-tmp-libname "_tmp_" "Libname to use for sas-get-dataset." :group 'ess-sas :type 'string) (defcustom sas-file-name nil "The name of the current sas file." :group 'ess-sas :type '(choice (const nil) file)) ;; The next two are ``the inside of [...] in a regexp'' to be used in ;; (skip-chars-(for|back)ward SAS-..-chars) (defcustom sas-white-chars " \t\n\f" "This does NOT escape blanks (RMH, 2000/03/20)." :group 'ess-sas :type 'string) (defcustom sas-comment-chars (concat sas-white-chars ";") "Doc?" :group 'ess-sas :type 'string) (defcustom ess-sas-run-regexp-opt t "If you do not want to run regexp-opt, then set to nil." :group 'ess-sas :type 'boolean) (defvar sas-buffer-name nil) (defvar sas-file-root nil) (defvar sas-submitable nil) (defvar sas-dataset nil) (defvar SAS-mode-font-lock-defaults (if ess-sas-run-regexp-opt (list ;; .log NOTE: messages (cons "^NOTE [0-9]+-[0-9]+: Line generated by the invoked macro" font-lock-comment-face) (cons "^NOTE: .*$" font-lock-comment-face) (cons "^ [^ @].*[.]$" font-lock-comment-face) (cons "^ [a-z].*[a-z][ ]?$" font-lock-comment-face) (cons "^ Engine:[ ]+V.+$" font-lock-comment-face) (cons "^ Physical Name:[ ]+.+$" font-lock-comment-face) (cons "^ \\(cpu\\|real\\) time[ ]+[0-9].*$" font-lock-comment-face) (cons "^ decimal may be shifted by the" font-lock-comment-face) (cons "^NOTE: The infile " font-lock-comment-face) (cons "^NOTE: 1 record was read from the infile " font-lock-comment-face) (cons "^NOTE: [1-9][0-9]* records were read from the infile " font-lock-comment-face) (cons "^ Filename=.*,$" font-lock-comment-face) (cons "^ File Name=.*,$" font-lock-comment-face) (cons "^ File $" font-lock-comment-face) (cons "^ Name=.*,$" font-lock-comment-face) (cons "^ File List=(" font-lock-comment-face) (cons "^ List=(" font-lock-comment-face) (cons "^ Owner Name=.*,$" font-lock-comment-face) (cons "^ Access Permission=.*,$" font-lock-comment-face) (cons "^ Last Modified=.*,?$" font-lock-comment-face) (cons "^ File Size (bytes)=[0-9]+$" font-lock-comment-face) (cons "^ Pipe command=" font-lock-comment-face) (cons "^NOTE: The file " font-lock-comment-face) (cons "^NOTE: 1 record was written to the file " font-lock-comment-face) (cons "^NOTE: [1-9][0-9]* records were written to the file " font-lock-comment-face) (cons "^NOTE: PROC LOGISTIC is modeling the probability that" font-lock-comment-face) (cons "^NOTE: PROC GENMOD is modeling the probability that" font-lock-comment-face) (cons "^1[ ]+The SAS System.*$" font-lock-comment-face) (cons "^\014.*$" font-lock-comment-face) (cons "[*][*][*] ANNOTATE macros are now available [*][*][*]" font-lock-comment-face) (cons "For further information on ANNOTATE macros, enter," font-lock-comment-face) ;; (cons "^SAS/STAT 9.3_M1, SAS/ETS 9.3_M1, SAS/OR 9.3_M1" ;; font-lock-comment-face) (cons "\\(or \\)?%HELPANO.*$" font-lock-comment-face) (cons "^Local Variables:$" font-lock-comment-face) (cons "^End:$" font-lock-comment-face) (cons "^MPRINT([_A-Z0-9]+)" font-lock-comment-face) ;; .log ERROR: messages ; (cons "^ERROR\\( [0-9]+-[1-9][0-9][0-9]\\)?: .*$" (cons "^ERROR\\( [0-9]+-[0-9]+\\)?: .*$" font-lock-keyword-face) ; ERROR: (cons "^ [^ @].*\\([.][ ]?[ ]?\\|[,a-z][ ]\\)$" font-lock-keyword-face) ; ERROR #-###: (cons "^ [^ @].*\\([.][ ]?[ ]?\\|[,a-z][ ]\\)$" font-lock-keyword-face) ; ERROR ##-###: (cons "^ [^ @].*\\([.][ ]?[ ]?\\|[,a-z][ ]\\)$" font-lock-keyword-face) ; ERROR ###-###: (cons "^ [^ @].*\\([.][ ]?[ ]?\\|[,a-z][ ]\\)$" font-lock-keyword-face) (cons "^ a format name." font-lock-keyword-face) (cons "^ where a numeric operand is required. The condition was: " font-lock-keyword-face) (cons "[ ][_]+$" font-lock-keyword-face) ;; .log WARNING: messages ;(cons "^WARNING\\( [0-9]+-[1-9][0-9][0-9]\\)?: .*$" (cons "^WARNING\\( [0-9]+-[0-9]+\\)?: .*$" font-lock-function-name-face) ; WARNING: (cons "^ [^ @].*\\([.][ ]?[ ]?\\|[,a-z][ ]\\)$" font-lock-function-name-face) ; WARNING #-###: (cons "^ [^ @].*\\([.][ ]?[ ]?\\|[,a-z][ ]\\)$" font-lock-function-name-face) ; WARNING ##-###: (cons "^ [^ @].*\\([.][ ]?[ ]?\\|[,a-z][ ]\\)$" font-lock-function-name-face) ; WARNING ###-###: (cons "^ [^ @].*\\([.][ ]?[ ]?\\|[,a-z][ ]\\)$" font-lock-function-name-face) ;; SAS comments ;; /* */ style handled by grammar above (cons "\\(^[0-9]*\\|[:;!]\\)[ \t]*%?\\*[^;/][^;]*;" font-lock-comment-face) ; these over-rides need to come before the more general declarations (cons "\\") ; font-lock-keyword-face) ; ;; SAS base and SAS/Graph statements (cons (concat ;"\\<" (regexp-opt '( "do" "to" "by" "goto" ; "go" "abort" "and" "array" "assess" "attrib" "baseline" "bayes" "between" "bivar" "block" "bubble" "bubble2" "change" "choro" "class" "contains" "contrast" "delete" "display" "dm" "donut" "drop" "else" "error" "exchange" "exclude" "fcs" "file" "filename" "format" "freq" "footnote" "footnote1" "footnote2" "footnote3" "footnote4" "footnote5" "footnote6" "footnote7" "footnote8" "footnote9" "footnote10" "goptions" "grid" ; "ge" "gt" "hazardratio" "hbar" "hbar3d" "id" "if" "index" "infile" "informat" "input" ; "is" rarely used, but common false pos. "keep" "label" "length" "libname" "like" "link" "lsmeans" ; "le" "lt" "manova" "means" "merge" "missing" "model" "modify" "not" "null" ; "ne" "note" "ods" "options" "output" "otherwise" ; "or" "pageby" "parms" "pie" "pie3d" "plot" "plot2" "prism" "put" "random" "rename" "repeated" "retain" "same" "save" "scatter" "select" "set" "skip" "star" "strata" "sum" "sumby" "surface" "table" "tables" "test" "then" "time" "title" "title1" "title2" "title3" "title4" "title5" "title6" "title7" "title8" "title9" "title10" "univar" "update" "value" "var" "vbar" "vbar3d" "weight" "where" "window" "with" ; "x" ) 'words)) ;"\\>") font-lock-keyword-face) ;; SAS/GRAPH statements not handled above (cons (concat "\\<" (regexp-opt '("axis" "legend" "pattern" "symbol")) "\\([1-9][0-9]?\\)?" "\\>") font-lock-keyword-face) ;; SAS functions and SAS macro functions (cons "%[a-z_][a-z_0-9]*[(;]" font-lock-function-name-face) ;(cons "\\" "("); "[ \t]*(") font-lock-function-name-face) ) (list ;; .log NOTE: messages (cons "^NOTE: .*$" font-lock-constant-face) ;; .log ERROR: messages (cons "^ERROR: .*$" font-lock-keyword-face) ;; .log WARNING: messages (cons "^WARNING: .*$" font-lock-function-name-face) ;; SAS comments ;; /* */ handled by grammar above ;; (list "/\\*.*\\*/" 0 font-lock-comment-face t) (cons "\\(^[0-9]*\\|;\\)[ \t]*\\(%?\\*\\|comment\\).*\\(;\\|$\\)" font-lock-comment-face) ;; SAS execution blocks, DATA/RUN, PROC/RUN, SAS Macro Statements (cons "\\<%do[ \t]*\\(%until\\|%while\\)?\\>" font-lock-constant-face) ;;(cons (concat "\\(^[0-9]*\\|;\\)[ \t]*" ;;"%\\(end\\|global\\|local\\|m\\(acro\\|end\\)\\)" ;;"\\>") font-lock-constant-face) (cons "\\<%\\(end\\|global\\|local\\|m\\(acro\\|end\\)\\)\\>" font-lock-constant-face) (cons (concat "\\(^[0-9]*\\|;\\|):\\|%then\\|%else\\)[ \t]*" "\\(data\\|endsas\\|finish\\|quit\\|run\\|start\\)[ \t\n;]") font-lock-constant-face) (cons (concat "\\(^[0-9]*\\|;\\|):\\|%then\\|%else\\)[ \t]*" ;;"proc[ \t]+[a-z][a-z_0-9]+") font-lock-constant-face) "proc[ \t]+" ;;SAS/Base, SAS/Graph, SAS/FSP and common add-ons "\\(append" "\\|b\\(genmod\\|lifereg\\|phreg\\)" "\\|c\\(a\\(lendar\\|talog\\)\\|port\\|o\\(mpare\\|ntents\\|py\\|rr\\)\\)" "\\|d\\(atasets\\|bcstab\\|isplay\\)\\|ex\\(plode\\|port\\)" "\\|f\\(orm\\(at\\|s\\)\\|req\\|s\\(browse\\|edit\\|l\\(etter\\|ist\\)\\|view\\)\\)" "\\|g?\\(chart\\|p\\(lot\\|rint\\)\\)" "\\|g\\(anno\\|contour\\|device\\|font\\|\\(key\\)?map\\|options\\|project" "\\|re\\(duce\\|move\\|play\\)\\|slide\\|testit\\|3\\(d\\|grid\\)\\)" "\\|\\(map\\|[cg]\\)?import\\|i\\(ml\\|nsight\\)" "\\|means\\|options\\|p\\(menu\\|rintto\\)" "\\|r\\(ank\\|e\\(gistry\\|port\\)\\)" "\\|s\\(ort\\|ql\\|tandard\\|ummary\\)" "\\|t\\(abulate\\|emplate\\|imeplot\\|ran\\(spose\\|tab\\)\\)\\|univariate" ;;SAS/Stat and SAS/ETS "\\|a\\(ceclus\\|nova\\|rima\\|utoreg\\)\\|boxplot" "\\|c\\(a\\(lis\\|n\\(corr\\|disc\\)\\|tmod\\)\\|itibase\\|luster\\|o\\(mputab\\|rresp\\)\\)" "\\|discrim\\|expand\\|f\\(a\\(ctor\\|stclus\\)\\|orecast\\|req\\)" "\\|g\\(enmod\\|l\\(immix\\|m\\(mod\\|power\\|select\\)?\\)\\)\\|inbreed\\|k\\(de\\|rige2d\\)" "\\|l\\(attice\\|ife\\(reg\\|test\\)\\|o\\(ess\\|gistic\\)\\)" "\\|m\\(ds\\|ixed\\|o\\(de\\(clus\\|l\\)\\|rtgage\\)\\|ulttest\\)" "\\|n\\(ested\\|l\\(in\\|mixed\\)\\|par1way\\)\\|orthoreg" "\\|p\\(dlreg\\|hreg\\|l\\(an\\|s\\)\\|ower\\|r\\(in\\(comp\\|qual\\)\\|obit\\)\\)\\|r\\(sr\\)?eg" "\\|s\\(core\\|im\\(2d\\|lin\\)\\|pectra\\|t\\(atespace\\|dize\\|epdisc\\)\\|urvey\\(means\\|reg\\|select\\)\\|yslin\\)" "\\|t\\(phreg\\|pspline\\|r\\(ansreg\\|ee\\)\\|test\\)" "\\|var\\(clus\\|comp\\|iogram\\)\\|x11" "\\)") font-lock-constant-face) ;;(cons (concat "\\(^[0-9]*\\|;\\|%then\\|%else\\)[ \t]*" ;;"\\(%\\(go[ \t]*to\\|i\\(f\\|n\\(clude\\|put\\)\\)\\|let\\|put\\|sysexec\\)\\)" ;;"\\>") font-lock-constant-face) (cons "\\<%\\(go[ \t]*to\\|i\\(f\\|n\\(clude\\|put\\)\\)\\|let\\|put\\|sysexec\\)\\>" font-lock-constant-face) (cons "\\<%\\(by\\|else\\|t\\(o\\|hen\\)\\)\\>" font-lock-constant-face) ;; SAS dataset options/PROC statements followed by an equal sign/left parentheses (cons (concat "[ \t(,]" "\\(attrib\\|by\\|compress\\|d\\(ata\\|rop\\)\\|f\\(irstobs\\|ormat\\)" "\\|i\\(d\\|f\\|n\\)\\|ke\\(ep\\|y\\)\\|l\\(abel\\|ength\\)" "\\|o\\(bs\\|rder\\|ut\\)\\|rename\\|s\\(ortedby\\|plit\\)" "\\|var\\|where\\)" "[ \t]*=") font-lock-keyword-face) (cons "\\<\\(in\\(:\\|dex[ \t]*=\\)?\\|until\\|wh\\(en\\|ile\\)\\)[ \t]*(" font-lock-keyword-face) ;; SAS statements (cons (concat "\\(^[0-9]*\\|):\\|[;,]\\|then\\|else\\)[ \t]*" "\\(a\\(bort\\|rray\\|ttrib\\)\\|b\\(ayes\\|y\\)" "\\|c\\(hange\\|lass\\|ontrast\\)" "\\|d\\(elete\\|isplay\\|m\\|o\\([ \t]+\\(data\\|over\\)\\)?\\|rop\\)" "\\|e\\(rror\\|stimate\\|xc\\(hange\\|lude\\)\\)" "\\|f\\(ile\\(name\\)?\\|o\\(otnote\\(10?\\|[2-9]\\)?\\|rmat\\)\\|req\\)" "\\|go\\([ \t]*to\\|ptions\\)" "\\|hazardratio\\|[hv]bar\\(3d\\)?" "\\|i\\(d\\|f\\|n\\(dex\\|f\\(ile\\|ormat\\)\\|put\\|value\\)\\)" "\\|keep\\|l\\(abel\\|ength\\|i\\(bname\\|nk\\|st\\)\\|smeans\\)" "\\|m\\(anova\\|e\\(ans\\|rge\\)\\|issing\\|od\\(el\\|ify\\)\\)\\|note" "\\|o\\(ds\\|ptions\\|therwise\\|utput\\)\\|p\\(arms\\|lot2?\\|ut\\)" "\\|r\\(andom\\|e\\(name\\|peated\\|tain\\)\\)" "\\|s\\(ave\\|e\\(lect\\|t\\)\\|kip\\|trata\\|um\\(by\\)?\\)" "\\|t\\(ables?\\|i\\(me\\|tle\\(10?\\|[2-9]\\)?\\)\\)\\|update" "\\|va\\(lue\\|r\\)\\|w\\(eight\\|here\\|i\\(ndow\\|th\\)\\)" ;; IML statements that are not also SAS statements "\\|append\\|c\\(lose\\(file\\)?\\|reate\\)\\|edit\\|f\\(ind\\|orce\\|ree\\)" "\\|insert\\|load\\|mattrib\\|p\\(a[ru]se\\|rint\\|urge\\)" "\\|re\\(move\\|peat\\|place\\|set\\|sume\\)" "\\|s\\(et\\(in\\|out\\)\\|how\\|ort\\|tore\\|ummary\\)\\|use\\)?" "\\>") font-lock-keyword-face) ;; (cons "\\<\\(\\(then\\|else\\)[ \t]*\\)?\\(do\\([ \t]*over\\)?\\|else\\)\\>" ;; font-lock-keyword-face) ;; SAS statements that must be followed by a semi-colon (cons (concat "\\(^[0-9]*\\|):\\|[;,]\\|then\\|else\\)[ \t]*" "\\(cards4?\\|datalines\\|end\\|l\\(ostcard\\)\\|page\\|stop\\)?" "[ \t]*;") font-lock-keyword-face) ;; SAS/GRAPH statements not handled above (cons (concat "\\(^[0-9]*\\|):\\|[;,]\\)[ \t]*" "\\(axis\\|legend\\|pattern\\|symbol\\)" "\\([1-9][0-9]?\\)?\\>") font-lock-keyword-face) ;; SAS Datastep functions and SAS macro functions ;(cons "%[a-z_][a-z_0-9]*[ \t]*[(;]" ;; SAS macro functions occasionally defined with no arguments ;; which means they can be followed by any character that can ;; separate tokens, however, they are most likely to be followed ;; by operat-ions/ors (cons "%[a-z_][a-z_0-9]*[- \t();,+*/=<>]" font-lock-function-name-face) (cons "\\ (- (point-max) pos) (point)) (goto-char (- (point-max) pos))))) ;;(defun sas-indent-region (start end) ;; "Indent a region of SAS code." ;; (interactive "r") ;; (save-excursion ;; (let ((endmark (copy-marker end))) ;; (goto-char start) ;; (and (bolp) (not (eolp)) ;; (sas-indent-line)) ;; (indent-sexp endmark) ;; (set-marker endmark nil)))) (defun indent-sas-statement (arg) "Indent all continuation lines sas-indent-width spaces from first line of statement." (interactive "p") (let (end) (save-excursion (if (> arg 0) (while (and (> arg 0) (search-forward ";" (point-max) 1 1)) (setq end (point)) (if (bobp) nil (backward-char 1)) (beginning-of-sas-statement 1) (forward-char 1) (indent-region (point) end (+ (current-column) (1- sas-indent-width))) (search-forward ";" (point-max) 1 1) (setq arg (1- arg))))))) ;; added 9/31/94 (defun sas-next-statement-indentation () "Returns the correct indentation of the next sas statement. The current version assumes that point is at the end of the statement. This will (hopefully) be fixed in later versions." (if (bobp) 0 (save-excursion (let ((prev-end (point))) (beginning-of-sas-statement 1) (while (and (not (bobp)) (not (looking-at "\\*/")) (looking-at sas-indent-ignore-comment)) (skip-chars-backward sas-white-chars) (if (bobp) nil (backward-char 1)) (setq prev-end (point)) (beginning-of-sas-statement 1 t)) (if (or (looking-at (concat "data[ \n\t;]\\|" (regexp-opt '("cards;" "cards4;" "datalines;" "datalines4;" "lines;" "lines4;")) "\\|proc[ \n\t]\\|%?do[ \n\t;]\\|%macro[ \n\t]\\|/\\*")) (save-excursion (re-search-forward "\\b%?then\\>[ \n\t]*\\b%?do\\>\\|\\b%?else\\>[ \n\t]*\\b%?do\\>" prev-end 1 1))) ; fixed 1/30/95 to avoid being fooled by ; variable names starting with "do" (+ (current-indentation) sas-indent-width) (if (looking-at "%?end[ ;\n]\\|%mend[ ;\n]\\|\\*/") (max (- (current-indentation) sas-indent-width) 0) (current-indentation))))))) ;; added 2/1/95 (defun sas-comment-start-col () "If the current line is inside a /* */ comment, returns column in which the opening /* appears. returns 0 otherwise." (let ((pos (point))) (save-excursion (if (and (search-backward "*/" (point-min) 1 1) (search-forward "/*" pos 1 1)) (current-indentation) 0)))) ;; Created 6/27/94 to verify that RUN; statements match PROC and DATA ;; statements. Useful since indentation my be goofy w/o "RUN;" (defun sas-check-run-statements () "Check to see that \"run\" statements are matched with proc, data statements." (interactive) (let (pos (ok t) (eob-ok t)) (save-excursion (beginning-of-line) (while ok (if (re-search-forward "\\(^[ \t]*run[ ;]\\)\\|\\(^[ \t]*proc \\|^[ \t]*data[ ;]\\)" nil 1) (if (match-beginning 2) (if (re-search-forward "\\(^[ \t]*run[ ;]\\)\\|\\(^[ \t]*proc \\|^[ \t]*data[ ;]\\)" nil t) (progn (setq pos (point)) (setq ok (match-beginning 1))) (setq eob-ok nil pos (point-max)))) (setq ok nil))) (setq ok (eobp))) (if (and ok eob-ok) (message "Run statements match") (goto-char pos) (beep) (message "Missing Run Statement.")))) (defun sas-fix-life-tables () "Remove censored and duplicate observations from life tables generated by Proc Lifetest. Operates on current region. A major space saver if there is heavy censoring." (interactive) (if buffer-read-only (setq buffer-read-only nil)) (goto-char (point-min)) (while (re-search-forward "^.*[ ]+[.][ ]+[.][ ]+[.][ ]+.*$" nil t) (replace-match "" nil nil))) ; (save-excursion ; (shell-command-on-region ; start end ; "sed '/[ ][.][ ]/d'" t))) ;;"sed \"\\? *\\. *\\. *\\. ?d\"" t))) ;;(vip-goto-line 1) ;;(setq ex-g-flag nil ;;ex-g-variant nil) ;;(vip-ex "1,$g/ \\. \\. \\. /d"))) (defun sas-fix-page-numbers (offset &optional page-num) "Fix number of current page in sas output files after editing. Add OFFSET to actual page number." (interactive "P") (if (not offset) (setq offset 0)) (if (not page-num) (setq page-num (sas-page-number))) (save-excursion (if (/= (preceding-char) ?\C-l) (backward-page 1)) (let (end len mstart mend) (save-excursion (forward-line sas-page-number-max-line) (setq end (point))) (if (re-search-forward "\\(^[0-9]+[ ]\\)\\|\\([ ][0-9]+$\\)" end t) (progn (setq len (- (match-end 0) (match-beginning 0)) mstart (match-beginning 0) mend (match-end 0)) (delete-region mstart mend) (if (eolp) (insert (format (concat "%" len "d") (+ page-num offset))) (insert (substring (concat (+ (sas-page-number) offset) " ") 0 len)))))))) (defun sas-page-fix (start) "Fix page numbers in sas output from point to end of file. If START is given this will be the number for the current page." (interactive "P") (let (offset (pnum (sas-page-number))) (if (not start) (setq offset 0) (setq offset (- start pnum))) (while (not (eobp)) (sas-fix-page-numbers offset pnum) (setq pnum (1+ pnum)) (forward-page 1)))) (defun fix-page-breaks () "Fix page breaks in SAS 6 print files." (interactive) (save-excursion (goto-char (point-min)) (if (looking-at "\f") (delete-char 1)) ;(replace-regexp "^\\(.+\\)\f" "\\1\n\f\n") (while (re-search-forward "^\\(.+\\)\f" nil t) (replace-match "\\1\n\f\n" nil nil)) (goto-char (point-min)) ;(replace-regexp "^\f\\(.+\\)" "\f\n\\1") (while (re-search-forward "^\f\\(.+\\)" nil t) (replace-match "\f\n\\1" nil nil)) ; (goto-char (point-min)) ;(replace-regexp " $" "") ;(while (re-search-forward "$" nil t) ; (replace-match "" nil nil)) (goto-char (point-min)) ;(replace-regexp " \\([^\\$]+\\)" "\n\\1") (while (re-search-forward " \\([^\\$]+\\)" nil t) (replace-match "\n\\1" nil nil)) (goto-char (point-max)) (if (not (bobp)) (progn (backward-char 1) (if (not (looking-at "\n")) (progn (forward-char 1) (open-line 1))))))) (defun sas-page-number () ;; like what-page except it returns an integer page number "Return page number of point in current buffer." (let ((opoint (point))) (save-excursion (goto-char (point-min)) (1+ (sas-how-many page-delimiter opoint))))) (defun sas-how-many (regexp &optional end) ;; a copy of `how-many' which returns an integer ;; rather than a message "Return number of matches for REGEXP following point." (let ((count 0) opoint) (save-excursion (while (and (not (eobp)) (progn (setq opoint (point)) (re-search-forward regexp end t))) (if (= opoint (point)) (forward-char 1) (setq count (1+ count)))) count))) (defun beginning-of-sas-proc () "Move point to beginning of sas proc, macro or data step." (interactive) (let ((case-fold-search t)) (forward-char -1) (while (not (or (looking-at "data\\|proc\\|%macro") (bobp))) (re-search-backward "proc\\|data\\|%macro" (point-min) 1) (beginning-of-sas-statement 1)))) (defun next-sas-proc (arg) "Move point to beginning of next sas proc." (interactive "P") (let ((case-fold-search t)) (forward-char 1) (if (re-search-forward "^[ \t]*\\(data[ ;]\\|proc[ ;]\\|endsas[ ;]\\|g?options[ ;]\\|%macro[ ;]\\)" nil t arg) (beginning-of-sas-statement 1) (forward-char -1)))) (defun set-sas-file-name () "Stores the name of the current sas file." (let ((name (buffer-file-name))) (cond ((not name)) ((string-match (substring name -4 nil) "\\.sas\\|\\.lst\\|\\.log") (setq sas-file-name (substring name 0 (- (length name) 4))) (setq sas-buffer-name (buffer-name)) (setq sas-file-root (substring sas-buffer-name 0 (- (length sas-buffer-name) 4)))) (t (message "This file does not have a standard suffix"))))) ;; created 6/27/94 (defun sas-set-alternate-file-name (name) "Stores the NAME of an alternate sas file. When this file is submitted with `submit-sas', the alternate file will be submitted instead. `sas-submitable' is automatically sets to t." (interactive "f") (cond ((string-match (substring name -4 nil) "\\.sas\\|\\.lst\\|\\.log") (setq sas-file-name (substring name 0 (- (length name) 4))) (setq sas-submitable t)) (t (message "This file does not have a standard suffix")))) (defun switch-to-sas-source () "Switches to sas source file associated with the current file." (interactive) (switch-to-sas-file "sas")) (defun switch-to-sas-lst () "Switches to sas source file associated with the current file." (interactive) (switch-to-sas-file "lst")) (defun switch-to-sas-log () "Switches to sas source file associated with the current file." (interactive) (switch-to-sas-file "log")) (defun switch-to-sas-source-other-window () "Switches to sas source file associated with the current file." (interactive) (switch-to-sas-file-other-window "sas")) (defun switch-to-sas-lst-other-window () "Switches to sas source file associated with the current file." (interactive) (switch-to-sas-file-other-window "lst")) (defun switch-to-sas-log-other-window () "Switches to sas source file associated with the current file." (interactive) (switch-to-sas-file-other-window "log")) ;;(defun switch-to-sas-file (suff &optional revert silent) ;; "Switches to sas \"SUFF\" file associated with the current file" ;; (let* ((sfile sas-file-name) ;; (buf (get-file-buffer (concat sfile "." suff))) ;; (sas-require-confirmation ;; (and sas-require-confirmation (not revert)))) ;; (if (or sas-require-confirmation (string-equal suff "sas") (not buf)) ;; (find-file (concat sfile "." suff)) ;; (progn (switch-to-buffer buf) ;; (if (not (verify-visited-file-modtime (current-buffer))) ;; (progn (revert-buffer t t) ;; (if (not silent) ;; (message "File has changed on disk. Buffer automatically updated.")))))) ;; (setq sas-file-name sfile)) ;; (if (string-equal suff "sas") ;; (if (not (string-equal major-mode "sas-mode")) ;; (sas-mode)) ;; (if (not (string-equal major-mode "sasl-mode")) ;; (sasl-mode)))) ;; ;;(defun switch-to-sas-file-other-window (suff) ;; "Switches to sas \"SUFF\" file associated with the current file" ;; (let* ((sfile sas-file-name) ;; (buf (get-file-buffer (concat sfile "." suff)))) ;; (if (or sas-require-confirmation (string-equal suff "sas") (not buf)) ;; (find-file-other-window (concat sfile "." suff)) ;; (progn (switch-to-buffer-other-window buf) ;; (if (not (verify-visited-file-modtime (current-buffer))) ;; (progn (revert-buffer t t) ;; (message "File has changed on disk. Buffer automatically updated."))))) ;; (setq sas-file-name sfile)) ;; (if (string-equal suff "sas") ;; (if (not (string-equal major-mode "sas-mode")) ;; ;;(sas-mode) ;; ) ;; (if (not (string-equal major-mode "sasl-mode")) ;; ;;(sasl-mode) ;; ))) (defun switch-to-sas-file (suff) "Switches to sas \"SUFF\" file associated with the current file." (switch-to-buffer (set-sas-file-buffer suff))) (defun switch-to-sas-file-other-window (suff) "Switches to sas \"SUFF\" file associated with the current file." (switch-to-buffer-other-window (set-sas-file-buffer suff))) ;; The following was created 6/7/94 to handle buffers without messing up ;; windows. (defun set-sas-file-buffer (suff &optional revert silent) "Sets current buffer to sas \"SUFF\" file associated with the current file." (let* ((sfile sas-file-name) (buf (get-file-buffer (concat sfile "." suff))) (sas-require-confirmation (and sas-require-confirmation (not revert)))) (if (or sas-require-confirmation (string-equal suff "sas") (not buf)) (set-buffer (find-file-noselect (concat sfile "." suff))) (progn (set-buffer buf) (if (not (verify-visited-file-modtime (current-buffer))) (progn (revert-buffer t t) (if (not silent) (message "File has changed on disk. Buffer automatically updated.")))))) (setq sas-file-name sfile)) ;;(if (string-equal suff "sas") ;; (if (not (string-equal major-mode "sas-mode")) (sas-mode)) ;; (if (not (string-equal major-mode "sasl-mode"))(sasl-mode)) (current-buffer)) (defun switch-to-sas-process-buffer () "Switch to sas-process-buffer." (interactive) (let (buf proc-name) (setq proc-name (concat "SAS" sas-file-name) buf (concat "*" proc-name "*")) (switch-to-buffer-other-window buf))) (defun submit-sas () ;; 6/17/94 added sas-submitable local variable. "Submit SAS file as shell command." (interactive) (if ;; can file be run, or is it only for inclusion? (or sas-submitable (progn (beep) (y-or-n-p (format "Submission is disabled for this file. Submit it anyway? ")))) (progn ;; if buffer name has changed, tell user (if (or (string-equal sas-buffer-name (buffer-name)) (not (y-or-n-p (format "The name of this buffer has changed. Submit the new file? ")))) (setq sas-buffer-name (buffer-name)) (set-sas-file-name)) (let ((sas-file sas-file-name) (sas-root sas-file-root) ;;(sas-buf sas-buffer-name) proc-name buf) ;; Save buffer to SAS the right file :-). (if (buffer-modified-p) (if (y-or-n-p (format "Buffer %s is modified. Save it? " (buffer-name))) (save-buffer))) (setq proc-name (concat "SAS" sas-file) buf (concat "*" proc-name "*")) (if (get-buffer buf) (save-window-excursion (switch-to-buffer buf) (erase-buffer) (setq default-directory (file-name-directory sas-file)))) (run-hooks 'sas-pre-run-hook) ;; added 8/24/94 (message "---- Submitting SAS job ----") ;; (switch-to-buffer buf) (make-comint proc-name sas-program ;added sas-program 4/29/94 nil sas-root) (save-window-excursion (switch-to-buffer buf) (setq sas-file-name sas-file) (bury-buffer buf)) (message "---- SAS job submitted ---- ") (if sas-notify;; added 4/7/94 (set-process-sentinel (get-process proc-name) #'sas-sentinel) (display-buffer buf t)))) (message "---- File not submitted ----"))) ;; 5/2/94 Modified sas-sentinel to check for errors in log file upon ;; completion. (defun sas-sentinel (proc arg);; created 4/7/94 "Notify user that SAS run is done." (beep) ;;(if (string-equal arg "finished\n") (save-excursion (let (msg buf win (sbuf (concat "*" (process-name proc) "*"))) (setq msg (format "SAS %s %s" (substring arg 0 -1) (if sas-error-notify ;;(save-window-excursion (progn (set-buffer sbuf) (setq buf (set-sas-file-buffer "log" t t)) (goto-char (point-min)) (setq win (get-buffer-window buf)) (save-window-excursion (if win (progn (select-window win) (if (re-search-forward "^ERROR" nil t) " (See .log file for errors)" "")) (switch-to-buffer buf) (if (re-search-forward "^ERROR" nil t) " (See .log file for errors)" "")))) ""))) (set-buffer sbuf) (goto-char (point-max)) (insert msg) (bury-buffer (get-buffer sbuf)) ;;(if (and sas-notify-popup window-system) ;; (x-popup-dialog t ;; (list "SAS Menu" (cons msg nil) ))) ;;(if (not (minibuffer-window-active-p)) (princ msg)) (princ msg)))) ;; 5/2/94 Modified run-sas-on-region to separate log and output buffers. ;; ;;(defun run-sas-on-region (start end append &optional buffer) ;; "Submit region to SAS" ;; (interactive "r\nP") ;; (message "---- Running SAS ----") ;; (let ((sfile sas-file-name) ;; (shell-file-name "/bin/sh") ;; serror buff) ;; (setq buffer (or buffer "*SAS output*")) ;; (save-excursion ;; (shell-command-on-region ;; start end;; added sas-program ;; (concat sas-program " -nonews -stdio 2> /tmp/_temp_.log" nil)) ;; (get-buffer-create "*SAS Log*") ;; (save-window-excursion ;; (switch-to-buffer "*SAS Log*") ;; (erase-buffer) ;; (insert-file-contents "/tmp/_temp_.log") ;; (delete-file "/tmp/_temp_.log") ;; (setq serror (re-search-forward "^ERROR" nil t)) ;; (if serror () (bury-buffer))) ;; (setq buff (get-buffer-create buffer)) ;; (save-window-excursion ;; (switch-to-buffer buff) ;; (setq sas-file-name sfile) ;; (if append ;; (progn ;; (end-of-buffer) ;; (insert "\f\n")) ;; (erase-buffer)) ;; (if (get-buffer "*Shell Command Output*") ;; (progn (insert-buffer "*Shell Command Output*") ;; (kill-buffer "*Shell Command Output*")) ;; (insert "SAS completed with no output.")) ;; (if append () (sasl-mode)) ;; (message "---- SAS Complete ----"))) ;; (if (not serror) ;; (switch-to-buffer-other-window buff) ;; (switch-to-buffer-other-window "*SAS Log*") ;; (goto-char serror) ;; (beep) ;; (message "Error found in log file.") ;; ))) (defun switch-to-dataset-log-buffer () "Switch to log buffer for run-sas-on-region." (interactive) (switch-to-buffer-other-window "*SAS Log*")) (defun switch-to-dataset-source-buffer () "Switch to source buffer for run-sas-on-region." (interactive) (switch-to-buffer-other-window (format " *sas-tmp-%s*" sas-dataset))) ;;(defun sas-get-dataset (filename &optional arg opts-p append buffer vars) ;; "Run proc contents and proc print on SAS dataset. Automatically prompts ;;for SAS options to use. Default options are defined by the variable ;;`sas-get-options'. Output may be updated from within output buffer with ;;C-cr if dataset changes. Also, the source code which generates the output ;;may be edited with C-cs. Typing C-cr within the output buffer reexecutes ;;the (modified) source code." ;; (interactive "fName of SAS dataset (file name):") ;; (let ((file (file-name-nondirectory filename)) ;; (dir (file-name-directory filename)) ;; (opts sas-get-options) ;; (minibuffer-history sas-get-options-history) ;; buf); fsize) ;; (setq buffer (or buffer (concat "*" file "*"))) ;; (setq opts (if opts-p opts (read-string "SAS options: " opts))) ;; (setq sas-get-options-history minibuffer-history) ;; (cond ((string-match (substring file -6 nil) "\\.ssd01") ;; (setq file (substring file 0 (- (length file) 6)))) ;; (t (error "This file is not a SAS dataset."))) ;; (setq buf (format " *sas-tmp-%s*" file)) ;; (get-buffer-create buf) ;; (save-window-excursion ;; (switch-to-buffer buf) ;; (erase-buffer) ;; (setq default-directory dir) ;; (if opts ;; (insert (format "options %s ;\n" opts))) ;; (insert (format "title \"Contents of SAS dataset `%s'\" ;\n" file)) ;; (insert (format "libname %s '%s' ;\n" sas-tmp-libname dir)) ;; (if (not (equal arg 1)) ;; (insert (format "proc contents data = %s.%s ;\n" sas-tmp-libname file))) ;; (if (equal arg 2) () ;; (insert (format "proc print data = %s.%s ;\n" sas-tmp-libname file)) ;; (if vars (insert (format " var %s ;\n" vars)))) ;; (run-sas-on-region (point-min) (point-max) append ;; buffer) ;; (get-buffer buffer) ;; (if append () (sasd-mode)) ;; added 5/5/94 ;; (setq sas-dataset file)) ;; (if (get-buffer-window buffer t) ;; (raise-frame (window-frame (get-buffer-window buffer t))) ;; (display-buffer buffer (not append))) ;; )) ;;(defun revert-sas-dataset () ;; "Revert current sas dataset from disk version" ;; (interactive) ;; (let* ((file sas-dataset) ;; (buf (format " *sas-tmp-%s*" file)) ;; (pos (point))) ;; (save-window-excursion ;; (switch-to-buffer buf) ;; (run-sas-on-region (point-min) (point-max) nil ;; (concat "*" file ".ssd01*")) ;; ) ;; (goto-char pos) ;; added 6/9/94 ;; (sasd-mode) ;; added 5/5/94 ;; (setq sas-dataset file))) (defun sas-insert-local-variables () ;; created 6/17/94 "Add local variables code to end of sas source file." (interactive) (save-excursion (if (re-search-forward "\\* *Local Variables: *;" nil t) () (goto-char (point-max)) (insert " ** Local Variables: ; ** End: ; page ; ")))) ;; variables section (defvar sas-dir-mode-map nil) (defvar-local sas-directory-name nil "Name of directory associated with this buffer.") (defvar-local sas-dir-buf-end nil) (defvar-local sas-sorted-by-num nil) ;; user variables ;; keymaps etc... (if sas-dir-mode-map () (setq sas-dir-mode-map (make-sparse-keymap)) (define-key sas-dir-mode-map "m" #'sas-mark-item) (define-key sas-dir-mode-map "u" #'sas-unmark-item) (define-key sas-dir-mode-map " " #'sas-next-line) (define-key sas-dir-mode-map "\C-n" #'sas-next-line) (define-key sas-dir-mode-map "\C-p" #'sas-prev-line) (define-key sas-dir-mode-map "\177" #'sas-prev-line-undo) (define-key sas-dir-mode-map "\C-b" #'sas-backward-page-narrow) (define-key sas-dir-mode-map "\C-v" #'sas-forward-page-narrow) (define-key sas-dir-mode-map "\C-m" #'sas-goto-dataset) (define-key sas-dir-mode-map "t" #'sas-dir-goto-page) (define-key sas-dir-mode-map "q" #'bury-buffer) (define-key sas-dir-mode-map "1" #'digit-argument) (define-key sas-dir-mode-map "2" #'digit-argument) (define-key sas-dir-mode-map "3" #'digit-argument) (define-key sas-dir-mode-map "4" #'digit-argument) (define-key sas-dir-mode-map "5" #'digit-argument) (define-key sas-dir-mode-map "6" #'digit-argument) (define-key sas-dir-mode-map "7" #'digit-argument) (define-key sas-dir-mode-map "8" #'digit-argument) (define-key sas-dir-mode-map "9" #'digit-argument) (define-key sas-dir-mode-map [menu-bar sas run] '("Submit File " . submit-sas)) ) (define-derived-mode sas-dir-mode special-mode "SAS" "Major mode for managing sas files." :group 'ess-sas (setq sas-directory-name (expand-file-name default-directory))) ;;(defun sas-make-library (directory &optional update) ;; "Create a buffer with the names of all sas datasets from DIRECTORY." ;; (interactive "DDirectory Name: ") ;; (let ((dir (expand-file-name directory)) buf out cont pos) ;; (setq buf (format " *sas-tmp-%s*" dir)) ;; (setq out (concat "*SAS-dir-" dir)) ;; (setq cont (concat "*SAS-cont-" dir)) ;; (get-buffer-create buf) ;; (if (get-buffer out) ;; (if update ;; (progn ;; (set-buffer out) ;; (setq buffer-read-only nil))) ;; (setq update t)) ;; (pop-to-buffer out) ;; (setq default-directory dir) ;; (setq pos (point)) ;; (if update ;; (progn ;; (save-window-excursion ;; (set-buffer buf) ;; (erase-buffer) ;; (setq default-directory dir) ;; (insert "options linesize=70 pagesize=1000 ;\n") ;; (insert (format "title \"Contents of SAS directory `%s'\" ;\n" ;; dir)) ;; (insert (format "libname %s '%s' ;\n" sas-tmp-libname dir)) ;; (insert (format "proc contents data = %s._all_ directory details memtype=data ;\n" sas-tmp-libname)) ;; (run-sas-on-region (point-min) (point-max) nil ;; out) ;; (set-buffer out) ;; (goto-char (point-min)) ;; (if (= (sas-how-many page-delimiter (point-max)) 0) ;; (let ((buffer-read-only nil)) ;; (erase-buffer) ;; (insert "There are no SAS datasets in this directory") ;; (pop-to-buffer out)) ;; (save-excursion ;; (set-buffer (get-buffer-create cont)) ;; (setq buffer-read-only t) ;; (let ((buffer-read-only nil)) ;; (erase-buffer) ;; (insert-buffer out) ;; (delete-region (point-min) ;; (or (re-search-forward page-delimiter nil t) ;; (point-min))) ;; (sas-page-fix 1) ;; (goto-char (point-min)) ;; (sas-dir-mode) ;; (sas-narrow-to-page))) ;; (if (re-search-forward page-delimiter nil t) ;; (delete-region (progn (beginning-of-line) (point)) ;; (point-max))) ;; (sas-insert-set-properties (point-min) (point-max)) ;; ) ;; (switch-to-buffer out t) ;; (goto-char (point-min)) ;; (sas-dir-mode) ;; (setq sas-dir-buf-end (point-max))) ;; (goto-char pos) ;; (sas-move-to-filename (point-max)))))) (defun sas-move-to-filename (&optional eol) (or eol (setq eol (progn (end-of-line) (point)))) (beginning-of-line) (if (re-search-forward "\\(^ *[0-9]+ *<*\\)[^:0-9\n]" eol t) (goto-char (match-end 1)))) (defun sas-next-line (arg) "Move down one line." (interactive "p") (forward-line arg) (sas-move-to-filename (point-max))) ;;(and (< (point) sas-dir-buf-end) ;;(forward-line arg) ;;(sas-move-to-filename sas-dir-buf-end))) (defun sas-prev-line (&optional _arg) "Move up one line." (interactive) (beginning-of-line) (re-search-backward "^ *[0-9]+ *<*[^:0-9\n]" (point-min) t) (sas-move-to-filename sas-dir-buf-end)) (defun sas-insert-set-properties (beg end) (save-excursion (goto-char beg) (while (< (point) end) (if (sas-move-to-filename) (put-text-property (point) (+ 8 (point)) 'mouse-face 'highlight)) (forward-line 1)))) (defun sas-get-filename () "Return name of dataset on current line." (interactive) (save-excursion (if (string-equal "*SAS-dir" (substring (buffer-name) 0 8)) (sas-move-to-filename) (goto-char (point-min)) (re-search-forward "Data Set Name: [^.]*\\.")) (expand-file-name (downcase (concat sas-directory-name (buffer-substring (point) (save-excursion (skip-chars-forward "A-Z0-9_") (point))) ".ssd01"))))) (defun sas-get-file-number () "Return name of dataset on current line." (interactive) (if (sas-move-to-filename) (progn (forward-word -1) (re-search-forward "[0-9]*") (string-to-number (buffer-substring (match-beginning 0) (match-end 0)))))) (defun sas-goto-page (arg) "Goto top of page ARG. If no ARG, then goto top of file." (interactive "P") (goto-char 1) (if arg (if (> arg 1) (progn (re-search-forward page-delimiter (point-max) 1 (1- arg))))) (skip-chars-forward sas-white-chars); was " \f\n" till 5.1.13 (recenter 1)) (defun forward-page-top-of-window (arg) "Move forward to page boundary and leave first line at top of window. With arg, repeat, or go back if negative. A page boundary is any line whose beginning matches the regexp `page-delimiter'." (interactive "p") (forward-page arg) (recenter 0)) (defun backward-page-top-of-window (arg) "Move backward to page boundary and leave first line at top of window. With arg, repeat, or go back if negative. A page boundary is any line whose beginning matches the regexp `page-delimiter'." (interactive "p") (forward-page (- arg)) (recenter 0)) (defun sas-narrow-to-page () (save-excursion (let* ((min (point-min)) (max (point-max))) ;;(omin (point-min)) ;;(omax (point-max))) (if (or (bolp) (beginning-of-line) (looking-at page-delimiter)) (forward-char 1) (forward-page -1)) (setq min (point)) (forward-page 1) (beginning-of-line) (setq max (point)) (narrow-to-region min max)))) (defun sas-forward-page-narrow (arg) "Move forward to page boundary and narrow to page. With arg, repeat, or go back if negative. A page boundary is any line whose beginning matches the regexp `page-delimiter'." (interactive "p") (widen) (forward-page arg) (sas-narrow-to-page) (goto-char (point-min))) (defun sas-backward-page-narrow (arg) "Move backward to page boundary and narrow to page. With arg, repeat, or go back if negative. A page boundary is any line whose beginning matches the regexp `page-delimiter'." (interactive "p") (goto-char (point-min)) (widen) (forward-page (- arg)) (sas-narrow-to-page)) (defun sas-goto-dataset (&optional page) (interactive) (and sas-directory-name (let ((page (or page (sas-get-file-number)))) ;;(dir sas-directory-name)) (if page (progn (switch-to-buffer-other-window (concat "*SAS-cont-" sas-directory-name)) (widen) (sas-goto-page page) (sas-narrow-to-page) (goto-char (point-min))))))) (defun sas-dir-goto-page (page) (interactive "p") (widen) (sas-goto-page page) (sas-narrow-to-page)) (defun sas-mark-item (&optional next) (interactive) (sas-move-to-filename) (beginning-of-line) (let ((buffer-read-only nil)) (if (re-search-forward "^\\( *[0-9]+ *\\) \\([A-Z][A-Z_0-9]*\\) " (save-excursion (end-of-line) (point)) t) (replace-match "\\1<\\2>"))) (or next (sas-next-line 1))) (defun sas-unmark-item () (interactive) (save-excursion (beginning-of-line) (let ((buffer-read-only nil)) (if (re-search-forward "^\\( *[0-9]+ *\\)<\\([A-Z][A-Z_0-9]*\\)>" (save-excursion (end-of-line) (point)) t) (replace-match "\\1 \\2 "))))) (defun sas-prev-line-undo (arg) (interactive "p") (sas-prev-line arg) (sas-unmark-item) (sas-move-to-filename)) (defun sas-create-var-string () (and (string-equal "*SAS-cont" (substring (buffer-name) 0 9)) (let (str) (goto-char (point-min)) (while (re-search-forward "^\\( *[0-9]+ *\\)<\\([A-Z][A-Z_0-9]*\\)>" nil t) (setq str (concat str " " (buffer-substring (match-beginning 2) (match-end 2))))) str))) (defun ess-imenu-SAS (&optional _arg) "SAS language Imenu support for ESS." (interactive) (setq imenu-generic-expression '( (nil "[ \t\n=]\\([[:alpha:]_][[:alnum:]_]*[.][[:alpha:]_][[:alnum:]_]*\\)[ ,()\t\n;]" 1))) (imenu-add-to-menubar "SAS Datasets")) (provide 'ess-sas-l) ;;; ess-sas-l.el ends here ESS-24.01.1/lisp/ess-site.el000066400000000000000000000045231455642170100153470ustar00rootroot00000000000000;;; ess-site.el --- user customization of ESS -*- lexical-binding: t; -*- ;; Copyright (C) 1993-2020 Free Software Foundation, Inc. ;; Author: David Smith ;; Created: 12 Nov 1993 ;; Maintainer: ESS-core ;; This file is part of GNU Emacs. ;;; License: ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see ;; ;;; Commentary: ;; Load path, autoloads, and major modes ;; ======================================== ;; ;; This file defines all the site-specific customizations for ESS. It should be ;; edited on a per-site basis. users who wish to use ESS should add the path to ;; ess-site to their `load-path' and require it: ;; ;; (add-to-list 'load-path "/path/to/ess/lisp-directory");; ;; (require 'ess-site) ;; ;; For most users the variable ess-lisp-directory will automatically be set ;; correctly. If you are working with an old Emacs, one in which file-truename ;; is not defined, then you might need to change the value of ess-lisp-directory ;; to the directory which is to contain the file ess-site.elc. This is probably ;; the current directory, or the value of LISPDIR if it was set in the Makefile. ;; ;; Debug startup: (setq ess-show-load-messages t) ;;; Code: (when load-file-name ;; Modify this if ess-site.el is not in the ./lisp/ directory (defvar ess-lisp-directory (file-name-directory load-file-name) "Directory containing ess-site.el(c) and other ESS Lisp files.") (add-to-list 'load-path (directory-file-name ess-lisp-directory))) ;;; Loading popular dialects (they should become optional in the future) (require 'ess-r-mode) (require 'essd-els) ;; ess-remote (require 'ess-sas-d) (require 'ess-bugs-d) (require 'ess-jags-d) (require 'ess-toolbar) (provide 'ess-site) ;;; ess-site.el ends here ESS-24.01.1/lisp/ess-sp6-d.el000066400000000000000000000162401455642170100153330ustar00rootroot00000000000000;;; ess-sp6-d.el --- S-Plus 6 & 7 & 8 customization -*- lexical-binding: t; -*- ;; Copyright (C) 2001-2022 Free Software Foundation, Inc. ;; Author: A.J. Rossini ;; Created: 2001/02/06 ;; Maintainer: ESS Core Team ;; This file is part of GNU Emacs. ;;; License: ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see ;; ;;; Commentary: ;; AJR copied S+5 to be S+6. ;; AJR copied S4 to be S+5. ;; DB contributed the changes from ess-sp3-d.el to ;; ess-s4-d.el. (removed the old ugly approach). ;; This file defines Sp5 customizations for ess-mode. Lots of thanks ;; to RMH and JMC for code and suggestions ;; Thanks to MM for making this sensible. ;;; Code: (require 'ess-mode) (require 'ess-inf) (require 'ess-s-lang) (require 'ess-trns) ;; You now need to make sure you've defined if you are running 5.0 or 5.1. ;; Lots of things are broken between them, GRR... (defun S+-directory-p (directory) "Splus 5++ directories have a .Data directory and a __Meta directory within." (and directory (file-directory-p (concat directory ".Data")) (file-directory-p (concat directory ".Data/__Meta")))) (defvar S+-directory-function #'inferior-ess-default-directory) (defvaralias 'S+6-setup-directory-function 'S+-setup-directory-function) (defvar S+-setup-directory-function (lambda (startdir) (when (and startdir (S+-directory-p startdir)) (setenv "S_WORK" (if (getenv "S_WORK") (concat startdir ":" (getenv "S_WORK")) ;;(message "adding %s to S_WORK" startdir) startdir))))) (defvaralias 'S+6-customize-alist 'S+-customize-alist) (defvar S+-customize-alist (append '((ess-local-customize-alist . S+-customize-alist) (ess-dialect . S+-dialect-name) (ess-function-pattern . ess-r-function-pattern) (ess-object-name-db-file . "ess-sp6-namedb.el") (inferior-ess-program . inferior-S+-program) (inferior-ess-help-command . "help(\"%s\", pager=\"slynx -dump\", window=FALSE)\n") (inferior-ess-search-list-command . "searchPaths()\n") (ess-startup-directory-function . S+-directory-function) (ess-STERM . "iESS")) S+common-cust-alist) "Variables to customize for S+.") (defvar ess-S+-post-run-hook nil "Functions run in process buffer after the initialization of S+ process.") (defvar ess-S+--injected-code ".ess_funargs <- function(funname){ ## funname <- deparse(substitute(object)) fun <- try(eval(parse(text=funname)), silent = TRUE) if(is.function(fun)) { special <- grepl('[:$@[]', funname) args <- args(fun) fmls <- formals(args) fmls.names <- names(fmls) fmls <- gsub('\\\"', '\\\\\\\"', as.character(fmls), fixed = TRUE) args.alist <- sprintf(\"'(%s)\", paste(\"(\\\"\", fmls.names, \"\\\" . \\\"\", fmls, \"\\\")\", sep = '', collapse = ' ')) ## envname <- environmentName(environment(fun)) envname <- if (special) '' else 'S+' cat(sprintf('(list \\\"%s\\\" %s )\\n', envname, args.alist)) } } ") (defalias 'S+6 #'S+) (defun S+ (&optional _proc-name) "Call `Splus6', based on S version 4, from Bell Labs. New way to do it." (interactive) (ess-write-to-dribble-buffer (format "\n(S+): ess-dialect=%s, buf=%s\n" ess-dialect (current-buffer))) (let ((inf-buf (inferior-ess nil S+-customize-alist))) (ess-command ess-S+--injected-code) (when inferior-ess-language-start (ess-eval-linewise inferior-ess-language-start)) (with-current-buffer inf-buf (run-mode-hooks 'ess-S+-post-run-hook)) inf-buf)) (defalias 'S+6-mode #'S+-mode) ;;;###autoload (defun S+-mode (&optional _proc-name) "Major mode for editing S+ source. See `ess-mode' for more help." (interactive) (setq-local ess-local-customize-alist S+-customize-alist) (ess-mode) (if (fboundp 'ess-add-toolbar) (ess-add-toolbar)) (setq imenu-generic-expression ess-imenu-S-generic-expression) (when ess-imenu-use-S (imenu-add-to-menubar "Imenu-S"))) (defalias 'S+6-transcript-mode #'S+-transcript-mode) (define-derived-mode S+-transcript-mode ess-transcript-mode "ESS S Transcript" "S-PLUS 6 transcript mode." :syntax-table S-syntax-table :group 'ess-S) (defvar ess-s-versions '("Splus") "List of partial strings for versions of S to access within ESS. Each string specifies the start of a filename. If a filename beginning with one of these strings is found on `exec-path', a M-x command for that version of S is made available. For example, if the file \"Splus7\" is found and this variable includes the string \"Splus\", a function called `M-x Splus7' will be available to run that version of S. If duplicate versions of the same program are found (which happens if the same path is listed on `exec-path' more than once), they are ignored by calling `delete-dups'. Set this variable to nil to disable searching for other versions of S using this method. If you set this variable, you need to restart Emacs (and set this variable before ess-site is loaded) for it to take effect.") (define-obsolete-variable-alias 'ess-s-versions-created 'ess-s-created-runners "ESS 18.10") (defvar ess-s-created-runners) (defun ess-s-define-runners () "Generate functions for starting other versions of S. See `ess-s-versions' for strings that determine which functions are created. It assumes these versions of S can be run as a substitute for Splus6. This function returns the list of functions, if any, that were created. The functions will normally be placed on the menubar upon ESS initialization." (when ess-s-versions (let ((versions (delete-dups (mapcar #'file-name-nondirectory (apply #'nconc (mapcar #'ess-find-exec-completions ess-s-versions)))))) ;; Iterate over each string in VERSIONS, creating a new defun ;; each time. (setq ess-s-created-runners (mapc (lambda (v) (ess-define-runner v "S")) versions)) ;; Add to menu (when ess-s-created-runners ;; new-menu will be a list of 3-vectors, of the form: ;; ["R-1.8.1" R-1.8.1 t] (let ((new-menu (mapcar (lambda (x) (vector x (intern x) t)) ess-s-created-runners))) (easy-menu-add-item ess-mode-menu '("Start Process") (cons "Other" new-menu))))))) ;; Define the runners (ess-s-define-runners) (define-obsolete-function-alias 'ess-s-versions-create #'ess-s-define-runners "ESS 18.10") ; Provide package (provide 'ess-sp6-d) ;;; ess-sp6-d.el ends here ESS-24.01.1/lisp/ess-toolbar.el000066400000000000000000000151751455642170100160520ustar00rootroot00000000000000;;; ess-toolbar.el --- Support for a toolbar in ESS. -*- lexical-binding: t; -*- ;; Copyright (C) 1997-2020 Free Software Foundation, Inc. ;; Author: Stephen Eglen ;; Created: 2004-05-06 ;; Maintainer: ESS-core ;; This file is part of GNU Emacs. ;;; License: ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see ;; ;;; Commentary: ;; This code adds a toolbar to ESS modes for editing R and S code. ;; Support can be added for other modes (e.g. STATA), just ask! ;; ;; This code is experimental. It has been tested only on Linux ;; machines. All feedback appreciated. ;; ;; If your Emacs can support images, the ESS toolbar should be loaded. ;; ;; If you see a toolbar, but no icons, check out the value of ;; ess-icon-directory. ;; ;; The toolbar can be customized in several ways. To see options, do: ;; M-x customize-group RET ess-toolbar RET ;; If you change any of the variables, you _may_ need to restart Emacs ;; to see any effect. See also the documentation for ess-toolbar-items ;; if you wish to change its value. ;;; Technical issues. ;; 2009-03-16: toolbar code in Emacs 23 has changed slightly to 22, ;; and presumably once Emacs 22 is no longer supported, this code can ;; be cleaned up a bit (i.e. no need to set load-path.) ;;; Code: (require 'ess-mode) (defgroup ess-toolbar nil "ESS: toolbar support." :group 'ess :link '(emacs-commentary-link :tag "Commentary" "ess-toolbar.el") :prefix "ess-") (defcustom ess-use-toolbar (and (fboundp 'display-images-p) (display-images-p)) "Non-nil means ESS should support the toolbar." :type 'boolean) (defcustom ess-toolbar-own-icons nil "Non-nil means that we only put our toolbar entries in ESS. Otherwise we get standard toolbar as well as ESS entries. The standard toolbar items are copied from the default toolbar." :type 'boolean) (defcustom ess-toolbar-global nil "*Non-nil means that the ESS toolbar is available in all Emacs buffers. Otherwise, the ESS toolbar is present only in R/S mode buffers. For beginners, this is probably better set to a non-nil value." :type 'boolean) (defcustom ess-toolbar-items '( (R "startr") ;;(S "spluslogo" "Start S process") (S "splus_letter_small") (ess-eval-line-and-step "rline") (ess-eval-region "rregion") (ess-eval-function-or-paragraph-and-step "rregion") (ess-load-file "rbuffer") (ess-eval-function "rfunction") (ess-switch-to-ESS "switch_ess")) "Items to be added to the ESS toolbar. Each list element has two items: 1. the name of the function to run 2. the icon to be used (without .xpm extension) General toolbar items are also added to the ESS toolbar iff `ess-toolbar-own-icons' is nil. Setting this variable with setq doesn't take effect once you have loaded ess-site, unless you follow it by a call to `ess-make-toolbar' afterwards. Instead, change its value using Custom, and then on all new ESS buffers you should see the toolbar has changed." :set (lambda (symbol value) (set-default symbol value) (if (fboundp 'ess-make-toolbar) (ess-make-toolbar))) :type '(repeat (list (function :tag "Function to run") (string :tag "Icon")))) (defvar ess-icon-directory (expand-file-name "icons" ess-etc-directory) "*Location for ESS icons. This variable should be set automatically by the ESS install process. Icons should be found in ESS/etc/icons/ directory. If `ess-icon-directory' is invalid, please report a bug.") (unless (file-directory-p ess-icon-directory) (ess-write-to-dribble-buffer "`ess-icon-directory' does not exist; using `ess-etc-directory'.\n") (setq ess-icon-directory ess-etc-directory)) (defvar ess-toolbar nil "Toolbar items to be added to ESS editing buffers.") (defun ess-make-toolbar () "Make the ESS toolbar." ;; Under Emacs, only worth building the toolbar if tool-bar-map is ;; available. e.g. when running Emacs within a terminal, tool-bar-map ;; is not available, so no need to make the tool-bar. (when (boundp 'tool-bar-map) (setq ess-toolbar (if (or ess-toolbar-own-icons (null tool-bar-map)) (make-sparse-keymap) (copy-keymap tool-bar-map))) (let ((tool-bar-map ess-toolbar) (load-path (list ess-icon-directory))) ;; in Emacs 22, icons are found by examining load-path, bound here ;; whereas Emacs 23 seems to want them in image-load-path, set at the ;; bottom of this file. (mapc #'ess-add-icon ess-toolbar-items)))) (defun ess-add-icon (x) "Add an ESS item to the Emacs toolbar. X should be a list, see `ess-toolbar-items' for the format." ;; By using tool-bar-add-item-from-menu instead of tool-bar-add-item ;; we get the tooltips "for free" from ess-mode-map. (tool-bar-add-item-from-menu (car x) (cadr x) ess-mode-map)) (defun ess-add-toolbar () "Add the ESS toolbar to a particular mode. The toolbar is added iff `ess-toolbar-global' is nil, else the toolbar is added globally when ess-toolbar.el is loaded." (when (and ess-toolbar (not ess-toolbar-global)) (setq-local tool-bar-map ess-toolbar))) ;; Make the toolbars. Each toolbar is hopefully made only when this file ;; is loaded; we don't need it to be remade every time. (if ess-use-toolbar (progn (ess-make-toolbar) ;; After making the toolbar, if ESS toolbar is needed globally, ;; add it here. (if ess-toolbar-global (setq tool-bar-map ess-toolbar) (ess-write-to-dribble-buffer "Creating global Emacs toolbar")) ;; Check for toolbar support - needed iff ess-use-toolbar is non-nil. (or ;; Emacs support for images: (and (fboundp 'display-images-p) (display-images-p)) ;; if above tests failed, give a warning. (progn (message "Toolbar support for ESS not available in this Emacs.") ;; Not sure if we want to delay startup of ESS. ;;(sit-for 2) )) )) ;; Following needed for Emacs 23, not Emacs 22 (when (boundp 'image-load-path) (add-to-list 'image-load-path ess-icon-directory)) (provide 'ess-toolbar) ;;; ess-toolbar.el ends here ESS-24.01.1/lisp/ess-tracebug.el000066400000000000000000003536571455642170100162160ustar00rootroot00000000000000;; ess-tracebug.el --- Tracing and debugging facilities for ESS. -*- lexical-binding: t; -*- ;; Copyright (C) 2011-2022 Free Software Foundation, Inc. ;; Author: Vitalie Spinu ;; Maintainer: Vitalie Spinu ;; Created: Oct 14 14:15:22 2010 ;; This file is part of GNU Emacs. ;;; License: ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see ;; ;;; Commentary: ;; Ess-tracebug is a package for interactive debugging of R code from ;; ESS and provides such features as: ;; - visual debugging ;; - browser, recover and conditional breakpoints ;; - watch window and loggers ;; - on the fly debug/undebug of R functions and methods ;; - highlighting of error source references and easy error navigation ;; - interactive traceback. ;; ;; For a complete description please see the documentation in the ESS ;; manual. ;;; Code: (eval-and-compile (when (< emacs-major-version 26) (require 'cl)) (require 'cl-lib) (require 'tramp) (require 'subr-x) (require 'ess-utils)) (require 'comint) (require 'compile) (require 'ring) (defvar text-scale-mode-amount) (autoload 'text-scale-mode "face-remap" "[autoload]" nil) ;; Silence the byte compiler. This is OK here because this file is ;; only loaded from ess-inf and has no autoloads. ;; TODO: This is a LOT. Can we move some of this around? (defvar ess--dbg-del-empty-p) (defvar inferior-ess-mode-map) (defvar ess-mode-map) (defvar ess--inhibit-presend-hooks) (declare-function ess--accumulation-buffer "ess-inf") (declare-function ess--if-verbose-write-process-state "ess-inf") (declare-function ess--run-presend-hooks "ess-inf") (declare-function ess-boolean-command "ess-inf") (declare-function ess-build-eval-command "ess-inf") (declare-function ess-build-load-command "ess-inf") (declare-function ess-command "ess-inf") (declare-function ess-dirs "ess-inf") (declare-function ess-eval-region--normalise-region "ess-inf" ) (declare-function ess-force-buffer-current "ess-inf") (declare-function ess-get-process "ess-inf") (declare-function ess-get-process-variable "ess-inf") (declare-function ess-get-words-from-vector "ess-inf") (declare-function ess-get-words-from-vector--foreground "ess-inf") (declare-function ess-process-get "ess-inf") (declare-function ess-process-live-p "ess-inf") (declare-function ess-process-put "ess-inf") (declare-function ess-send-string "ess-inf") (declare-function ess-switch-process "ess-inf" ()) (declare-function ess-switch-to-ESS "ess-inf") (declare-function ess-switch-to-end-of-ESS "ess-inf" ()) (declare-function ess-wait-for-process "ess-inf") (declare-function inferior-ess--set-status "ess-inf") (declare-function inferior-ess-output-filter "ess-inf") (declare-function inferior-ess-run-callback "ess-inf") (declare-function ess-helpobjs-at-point--read-obj "ess-help") (declare-function ess-r-get-evaluation-env "ess-r-mode") (declare-function ess-roxy--region-p "ess-roxy") (declare-function ess-r-package--all-source-dirs "ess-r-package") (declare-function ess-r-package-name "ess-r-package") (declare-function ess-r-package-source-dirs "ess-r-package") ;; Do not require tramp at runtime. It is expensive to load. Instead, ;; guard calls with (require 'tramp) and silence the byte compiler ;; here. (declare-function tramp-dissect-file-name "tramp") (declare-function tramp-get-remote-tmpdir "tramp") ;; The following declares can be removed once we drop Emacs 25 (declare-function tramp-file-name-hop "tramp") (declare-function tramp-file-name-host "tramp") (declare-function tramp-file-name-localname "tramp") (declare-function tramp-file-name-method "tramp") (declare-function tramp-file-name-user "tramp") (defgroup ess-tracebug nil "Error navigation and debugging for ESS. Currently only R is supported." :link '(emacs-library-link :tag "Source Lisp File" "ess-tracebug.el") :group 'ess) (defvar ess-tracebug-indicator " TB" "String to be displayed in mode-line alongside the process name. Indicates that ess-tracebug-mode is turned on.") (defvar ess-watch-mode-map (let ((map (make-sparse-keymap))) (define-key map "k" #'ess-watch-kill) ;; (define-key ess-watch-mode-map "u" #'ess-watch-undelete) ;; editing requires a little more work. (define-key map "a" #'ess-watch-add) (define-key map "i" #'ess-watch-insert) (define-key map "e" #'ess-watch-edit-expression) (define-key map "r" #'ess-watch-rename) (define-key map "q" #'ess-watch-quit) (define-key map "u" #'ess-watch-move-up) (define-key map "U" #'ess-watch-move-down) (define-key map "d" #'ess-watch-move-down) (define-key map "n" #'ess-watch-next-block) (define-key map "p" #'ess-watch-previous-block) ;; R mode keybindings. (define-key map "\C-c\C-s" #'ess-switch-process) (define-key map "\C-c\C-y" #'ess-switch-to-ESS) (define-key map "\C-c\C-z" #'ess-switch-to-end-of-ESS) map) "Keymap for `ess-watch-mode'.") (defcustom ess-tracebug-prefix nil "Key to be used as prefix for all `ess-tracebug' commands. Set this to a key combination you don't use often, like: (setq ess-tracebug-prefix \"\\M-t\") The postfix keys are defined in `ess-tracebug-map': \\{ess-tracebug-map}" :type '(choice (const nil) (string)) :group 'ess-tracebug) (defcustom ess-tracebug-search-path nil "List of directories to search for source files. Elements should be directory names, not file names of directories." :type '(choice (const :tag "Unset" nil) (repeat :tag "Directory list" (string :tag "Directory"))) :group 'ess-debug) (defvar ess-watch-buffer "*R watch*" "Name of the watch buffer.") (defcustom ess-watch-height-threshold nil "Minimum height for splitting *R* window sensibly to make space for watch window. See `split-height-threshold' for a detailed description. If nil, the value of `split-height-threshold' is used." :group 'ess-debug :type '(choice (const nil) (integer))) (defcustom ess-watch-width-threshold nil "Minimum width for splitting *R* window sensibly to make space for watch window. See `split-width-threshold' for a detailed description. If nil, the value of `split-width-threshold' is used." :group 'ess-debug :type '(choice (const nil) (integer))) (defcustom ess-watch-scale-amount -1 "The number of steps to scale the watch font down (up). Each step scales the height of the default face in the watch window by the variable `text-scale-mode-step' (a negative number of steps decreases the height by the same amount)" :group 'ess-debug :type 'integer) (defvar-local ess-watch-current-block-overlay nil "The overlay for currently selected block in the R watch buffer .") (defcustom ess-inject-source 'function-and-buffer "Control the source injection into evaluated code. If t, always inject source reference. If function, inject only for functions, If function-and-buffer, inject for functions and whole buffer (the default), If nil, never inject. When tracebug is active (the default), ESS instructs the subprocess to keep the source code references. If this variable is t, you won't be able to execute blocks which don't form a valid R expression. That is, if your expression spreads multiple paragraphs, and you call \\[ess-eval-region-or-function-or-paragraph-and-step] on first paragraph, R will report an error." :group 'ess-tracebug :type '(choice (const nil) (const function) (const function-and-buffer) (const t))) (defcustom ess-tracebug-enter-hook nil "List of functions to call on entry to `ess-tracebug' mode. Use `add-hook' to insert append your functions to this list." :group 'ess-tracebug :type 'hook) (defcustom ess-tracebug-exit-hook nil "List of functions to call on exit of `ess-tracebug' mode. Use `add-hook' to insert append your functions to this list." :group 'ess-tracebug :type 'hook) (defvaralias 'ess-tracebug-map 'ess-dev-map) (defvar ess--tracebug-eval-index 0 "This is used by to track source references in evaluation with source. For example, each time `ess-eval-function' is called the evaluated region is marked. When debugger enters the code it displays this reference number. Ess-debug finds this number in the referenced buffer.") ;; these vars are org variables that store the src block locations (defvar org-edit-src-beg-marker nil) (defvar org-babel-current-src-block-location nil "Marker pointing to the src block currently being executed. This may also point to a call line or an inline code block. If multiple blocks are being executed (e.g., in chained execution through use of the :var header argument) this marker points to the outer-most code block.") ;; hash to store source references of the form: tmpname -> (filename . src_start) (defvar ess--srcrefs (make-hash-table :test 'equal :size 100)) (defvar ess-tracebug-original-buffer-marker nil "Marker pointing to the beginning of original source code. If non-nil, tracebug will insert the source references based on this location instead of the current buffer. This is useful for applications, like org-babel, that call ess evaluation functions from temporary buffers.") (defun ess-tracebug-p () "Return non-nil if tracebug is running." (ess-process-get 'tracebug)) (defun ess-make-source-refd-command (beg end visibly process) "Saves a region to a temporary file in order to add source references. BEG and END delimit the region. Returns a string containing an inferior process command for loading the temporary file. This command conforms to VISIBLY." (let* ((filename buffer-file-name) (proc-dir (ess-get-process-variable 'default-directory)) (remote (when (file-remote-p proc-dir) (require 'tramp) ;; should this be done in process buffer? (tramp-dissect-file-name proc-dir))) (orig-marker (or ess-tracebug-original-buffer-marker org-edit-src-beg-marker org-babel-current-src-block-location)) orig-beg) (setq ess--tracebug-eval-index (1+ ess--tracebug-eval-index)) (goto-char beg) (skip-chars-forward " \t\n") (setq beg (point)) (goto-char end) (skip-chars-backward " \t\n") (setq end (point) orig-beg beg) ;; Delete all old temp files (when (and (not (ess-process-get 'busy)) (< 1 (float-time (time-subtract (current-time) (ess-process-get 'last-eval))))) (dolist (f (ess-process-get 'temp-source-files)) (and (file-exists-p f) (delete-file f))) (ess-process-put 'temp-source-files nil)) (when (markerp orig-marker) (setq filename (buffer-file-name (marker-buffer orig-marker))) (setq orig-beg (+ beg (marker-position orig-marker)))) (let ((tmpfile (expand-file-name (make-temp-name (concat (file-name-nondirectory (or filename "unknown")) "!")) (if remote (tramp-get-remote-tmpdir remote) temporary-file-directory)))) (ess-process-put 'temp-source-files (cons tmpfile (ess-process-get 'temp-source-files))) (when remote ;; Get local name (should this be done in process buffer?) (setq tmpfile (with-parsed-tramp-file-name tmpfile nil localname))) (if (not filename) (puthash tmpfile (list nil ess--tracebug-eval-index nil) ess--srcrefs) (puthash tmpfile (list filename ess--tracebug-eval-index orig-beg) ess--srcrefs) (puthash (file-name-nondirectory tmpfile) ; R sometimes strips dirs (list filename ess--tracebug-eval-index orig-beg) ess--srcrefs) (with-silent-modifications (put-text-property beg end 'tb-index ess--tracebug-eval-index))) (let ((string (ess-process-buffer-substring process beg end))) (or ;; Sending string to subprocess is considerably faster than tramp file ;; transfer. So, give priority to `ess-eval-command' if available (ess-build-eval-command string visibly t tmpfile) ;; When no `ess-eval-command' available, use `ess-load-command' (progn (write-region beg end tmpfile nil 'silent) (ess-build-load-command tmpfile visibly t))))))) (defun ess-process-buffer-substring (process start end) (ess--run-presend-hooks process (buffer-substring-no-properties start end))) ;; Declare globally so that the bytecode compiler let-binds it ;; properly (defvar-local ess-r-evaluation-env nil) (defun ess-tracebug-send-region (process start end &optional visibly message type) "Send region to process adding source references as specified by `ess-inject-source' variable." ;; Disable evaluation env if we're sending a roxy region. This is ;; not the ideal place to do this. (let* ((se (ess-eval-region--normalise-region start end)) (start (car se)) (end (cdr se)) (ess-r-evaluation-env (unless (ess-roxy--region-p start end) (ess-r-get-evaluation-env))) (inject-p (cond ((eq type 'function) ess-inject-source) ((eq type 'buffer) (or (eq ess-inject-source t) (eq ess-inject-source 'function-and-buffer))) ((eq ess-inject-source t)) ;; We need to always inject with namespaced ;; evaluation (FIXME: not right place for ;; this). (ess-r-evaluation-env))) (ess--dbg-del-empty-p (unless inject-p ess--dbg-del-empty-p)) (string (if inject-p (ess-make-source-refd-command start end visibly process) (ess-process-buffer-substring process start end))) (message (if (fboundp ess-build-eval-message-function) (funcall ess-build-eval-message-function message) message))) ;; Don't run the presend hooks twice. (let ((ess--inhibit-presend-hooks t)) (process-put process :eval-visibly visibly) ;; Visible evaluation is not nice when sourcing temporary files. You get ;; .ess.eval(*code*) instead of *code*. (setq visibly (unless inject-p visibly)) (ess-send-string process string visibly message)))) (defun ess-tracebug-send-function (proc start end &optional visibly message) "Like `ess-tracebug-send-region' but with tweaks for functions." (ess-tracebug-send-region proc start end visibly message 'function)) ;; * Input Ring: ;; i . Goto input event marker forwards . `ess-debug-goto-input-event-marker' ;; I . Goto input event marker backwards . `ess-debug-goto-input-event-marker' (defun ess-tracebug-show-help () "Show help for `ess-tracebug'." (interactive) (if (fboundp 'describe-keymap) (describe-keymap 'ess-tracebug-map) (info "(ess) ESS tracebug"))) (defun ess-tracebug--propertize (dummy bitmap face &optional string ) "If `window-system' propertize DUMMY with fringe BITMAP and FACE. Otherwise, propertize line-prefix and margin with STRING and FACE" (unless string (setq string dummy)) (if window-system (propertize dummy 'display (list 'left-fringe bitmap face)) (propertize dummy 'display (list '(margin left-margin) (propertize string 'font-lock-face face 'face face))))) (defun ess-tracebug (&optional arg) "Toggle `ess-tracebug' mode. With ARG, turn `ess-tracebug' mode on if and only if ARG is positive. This mode adds to ESS the interactive debugging, breakpoint and error navigation functionality. Strictly speaking `ess-tracebug' is not a minor mode. It integrates globally into ESS and iESS. Note: Currently, `ess-tracebug' does not detect some of R's debug related messages in non-English locales. To set your R messages to English add the following line to your .Rprofile init file: Sys.setlocale(\"LC_MESSAGES\", \"C\") See `ess-tracebug-help' for the overview of ess-tracebug functionality." ;; Note: The functionality in ess-tracebug is divided on conceptual ;; grounds in tracing and debugging and could be ;; activated/deactivate separately with `ess--tb-start' and ;; `ess-debug-start' respectively. (interactive "P") (ess-force-buffer-current "R process to activate tracebug in: ") (with-current-buffer (process-buffer (get-process ess-local-process-name)) (when (equal ess-dialect "R") (setq arg (if arg (prefix-numeric-value arg) (if (ess-process-get 'tracebug) -1 1))) (if (> arg 0) (unless (ess-process-get 'tracebug) ;; only if not already active (ess--tb-start) (ess-debug-start) ;; (dolist (bf (buffer-list)) ;; (with-current-buffer bf ;; (when (and (eq major-mode 'ess-mode) ;; (equal ess-dialect "R")) ;; (ess-bp-recreate-all)))) ;; watch functionality (if ess-tracebug-prefix (let ((comm (key-binding ess-tracebug-prefix))) ;; (message "ess-tracebug-prefix will be removed in future versions. Electric debug keys are now on [C-c] and [C-c C-t] maps.") ;; (sit-for 1) (when (commandp comm) (define-key ess-tracebug-map ess-tracebug-prefix comm)) (define-key ess-mode-map ess-tracebug-prefix ess-tracebug-map) (define-key inferior-ess-mode-map ess-tracebug-prefix ess-tracebug-map) (define-key ess-watch-mode-map ess-tracebug-prefix ess-tracebug-map))) (run-hooks 'ess-tracebug-enter-hook) (ess-process-put 'tracebug t) (message "ess-tracebug mode enabled")) (when (ess-process-get 'tracebug) ;;only when active (ess-process-put 'tracebug nil) ;; unset the map (when ess-tracebug-prefix (define-key ess-mode-map ess-tracebug-prefix nil) (define-key inferior-ess-mode-map ess-tracebug-prefix nil)) (ess--tb-stop) (ess-debug-stop) (run-hooks 'ess-tracebug-exit-hook) (message "ess-tracebug mode disabled")))))) (defalias 'ess-toggle-tracebug #'ess-tracebug) ;;;_* TRACEBACK ;; (defface ess--tb-last-input-face ;; '((((class grayscale) ;; (background light)) (:background "DimGray")) ;; (((class grayscale) ;; (background dark)) (:background "LightGray")) ;; (((class color) (background light) (min-colors 88)) ;; (:overline "medium blue" )) ;; (((class color) (background dark) (min-colors 88)) ;; (:overline "deep sky blue" )) ;; (((background light)) (:weight bold)) ;; (((background dark)) (:weight bold)) ;; ) ;; "Face to highlight currently debugged line." ;; :group 'ess-tracebug ) (defface ess-tracebug-last-input-fringe-face '((((background light) (min-colors 88)) (:foreground "medium blue" :overline "medium blue")) (((background dark) (min-colors 88)) (:foreground "deep sky blue" :overline "deep sky blue")) (((background light) (min-colors 8)) (:foreground "blue")) (((background dark) (min-colors 8)) (:foreground "cyan"))) "Face for fringe bitmap for last-input position." :group 'ess-tracebug) (if (fboundp 'define-fringe-bitmap) (define-fringe-bitmap 'last-input-arrow [#b00011111 #b00010000 #b00010000 #b00010000 #b00010000 #b00010000 #b00010000 #b00010000 #b00010000 #b00010000 #b11010111 #b01111100 #b00111000 #b00010000] nil nil 'top)) (defvar ess--tb-last-input (make-marker) "Marker pointing to the last user input position in iESS buffer. This is the place where `ess--tb-last-input-overlay' is moved. Local in iESS buffers with `ess-tracebug' mode enabled.") (defvar ess--tb-last-input-overlay nil "Overlay to highlight the position of last input in iESS buffer. Local in iESS buffers.") (defvar-local ess--busy-count 0 "Used to compute the busy indicator.") ;; (unless (boundp 'ess--busy-slash) ;; (defvar ess--busy-slash '(32 ?\u2014 92 47)) ;; (setq ess--busy-slash (mapcar (lambda (el) (format " %c " el)) ;; ess--busy-slash)) ;; ) (defvar ess--busy-slash '(" " " - " " \\ " " / ")) (defvar ess--busy-B '(" " " B " " ")) (defvar ess--busy-stars '(" " " " " * " " ** " " *** " " **** ")) (defvar ess--busy-vbars '(" " " " " | " " || " " ||| " " |||| ")) (defcustom ess-busy-strings ess--busy-slash "List of strings to replace in turn for busy indication. The first element of the list is used as an indicator of the process being ready (i.e. not busy). Implemented lists that you can use `ess--busy-slash', `ess--busy-B',`ess--busy-stars', `ess--busy-vbars'" :group 'ess :type '(repeat string)) (defvar ess--busy-timer nil "Timer used for busy process indication.") (defcustom inferior-ess-fix-misaligned-output nil "If non-nil, try to correct misaligned process output." :group 'ess-tracebug :type 'boolean) (defcustom inferior-ess-replace-long+ t "Determines if ESS replaces long + sequences in output. If \\='strip, remove all such instances. Otherwise, if non-nil, `+ + + + ' containing 3 or more + is replaced by `ess-long+replacement'. This variable can be process-local but not buffer-local." :group 'ess-tracebug :type '(choice (const nil :tag "No replacement") (const strip :tag "Replace all") (const t :tag "Replace 3 or more +"))) (defvar ess-long+replacement ". + " "Replacement used for long + prompt. Please don't customize this or other prompt related variables. ESS internal code assumes default R prompts.") (defmacro ess-copy-key (from-map to-map fun) `(define-key ,to-map (car (where-is-internal ,fun ,from-map)) ,fun)) ;;;_ + traceback functions (defun ess--tb-make-last-input-overlay (beg end) "Create an overlay to indicate the last input position." (let ((ove (make-overlay beg end))) (overlay-put ove 'before-string (ess-tracebug--propertize "!" 'last-input-arrow 'ess-tracebug-last-input-fringe-face)) ;; (overlay-put ove 'face 'ess--tb-last-input-face) (overlay-put ove 'evaporate t) ove)) (defun ess--tb-start () "Start traceback session." (with-current-buffer (process-buffer (get-process ess-local-process-name)) (unless ess-error-regexp-alist (error "Can not activate the traceback for %s dialect" ess-dialect)) (setq-local compilation-error-regexp-alist ess-error-regexp-alist) (let (compilation-mode-font-lock-keywords) (compilation-setup t)) (setq next-error-function 'ess-tracebug-next-error-function) ;; new locals (make-local-variable 'ess--tb-last-input) (make-local-variable 'ess--tb-last-input-overlay) (make-local-variable 'compilation-search-path) (setq compilation-search-path ess-tracebug-search-path) ;; TODO: make this dialect specific (ess-tracebug--set-left-margin) (save-excursion (goto-char comint-last-input-start) (setq ess--tb-last-input (point)) (setq ess--tb-last-input-overlay (ess--tb-make-last-input-overlay (line-beginning-position) (line-end-position)))) ;; busy timer (setq mode-line-buffer-identification (list (car (propertized-buffer-identification "%3b")) `(:eval (nth ess--busy-count ess-busy-strings)))) ;; 'face 'mode-line-buffer-id)))) (make-local-variable 'ess--busy-timer) (setq ess--busy-timer (run-with-timer 2 .5 (ess--make-busy-timer-function (get-buffer-process (current-buffer))))) (add-hook 'kill-buffer-hook (lambda () (when ess--busy-timer (cancel-timer ess--busy-timer)))) (add-hook 'comint-input-filter-functions #'ess-tracebug-set-last-input nil 'local) ;; redefine ;; TODO: all this part should go (partially gone now) (advice-add 'ess-parse-errors :override #'next-error))) (defun ess--tb-stop () "Stop ess traceback session in the current ess process." (with-current-buffer (process-buffer (get-process ess-current-process-name)) ;; restore original definitions (when (equal ess-dialect "R") (advice-remove 'ess-parse-errors #'next-error)) (if (local-variable-p 'ess--tb-last-input-overlay) (delete-overlay ess--tb-last-input-overlay)) (kill-local-variable 'ess--tb-last-input-overlay) (kill-local-variable 'ess--tb-last-input) (font-lock-remove-keywords nil (compilation-mode-font-lock-keywords)) (font-lock-ensure) (kill-local-variable 'compilation-error-regexp-alist) (kill-local-variable 'compilation-search-path) (cancel-timer ess--busy-timer) (remove-hook 'comint-input-filter-functions #'ess-tracebug-set-last-input 'local) (setq mode-line-buffer-identification (propertized-buffer-identification "%12b")))) (defvar ess--dbg-forward-ring (make-ring 10) "Ring of markers to the positions of user inputs when the debugger or traceback events are initiated. It is used in `ess--dbg-goto-input-point'.") (defvar ess--dbg-backward-ring (make-ring 10) "Ring of markers for the positions from `ess--dbg-goto-input-point'. Marks the position from which it was called. See also `ess--dbg-goto-debug-point'") ;; (setq ess-R--tb-regexp-alist '(R R2 R3 R-recover)) ;;(pop compilation-error-regexp-alist-alist) (defun ess-show-traceback () "Display R traceback and last error message. Pop up a compilation/grep/occur like buffer. Usual global key bindings are available (\\[next-error] and \\[previous-error]) for `next-error' and `previous-error' respectively. You can bind `no-select' versions of this commands: \(define-key compilation-minor-mode-map [(?n)] #\\='next-error-no-select) \(define-key compilation-minor-mode-map [(?p)] #\\='previous-error-no-select)" (interactive) (cl-assert ess-traceback-command nil "Not implemented for dialect %s" ess-dialect) (ring-insert ess--dbg-forward-ring (point-marker)) (ess-force-buffer-current "R process to use: ") (let ((trbuf (get-buffer-create "*ess-traceback*")) (lproc-name ess-local-process-name) (alist ess-mode-editing-alist) (cmd ess-traceback-command) (inhibit-read-only t)) (setq next-error-last-buffer trbuf) (with-current-buffer trbuf (setq ess-local-process-name lproc-name) (ess-command cmd trbuf) (goto-char (point-min)) ;; fixme: this is R specific check (cl-assert (not (re-search-forward "No traceback available" nil t)) nil "No traceback available") (ess-dirs) (when (boundp 'ess-r-error-regexp-alist) (setq-local compilation-error-regexp-alist ess-r-error-regexp-alist)) (setq-local compilation-search-path ess-tracebug-search-path) (ess-setq-vars-local alist) (font-lock-refresh-defaults) (compilation-minor-mode 1) (setq next-error-function #'ess-tracebug-next-error-function) (setq buffer-read-only t) (pop-to-buffer trbuf)))) (defvar ess-call-stack-command nil) (defun ess-show-call-stack () "Display current call stack. Also see `ess-show-traceback'" (interactive) (let ((ess-traceback-command ess-call-stack-command)) (ess-show-traceback))) (defalias 'ess-show-R-traceback #'ess-show-traceback) (defun ess--tb-next-error-goto-process-marker () ;; assumes current buffer is the process buffer with compilation enabled ;; used in ess-tracebug-next-error-function ; (with-current-buffer (process-buffer (get-process ess-local-process-name)) ; already in comint buffer .. no need (comint-goto-process-mark) (set-window-point (get-buffer-window) (point)) ;moves the cursor ;; FIXME: Should jump to current-debug-position, but messes the things if in recover ;; (when (ess-debug-is-active) ;; (ess-debug-goto-current-debug-position) ;; ) ) (defun ess-tracebug-next-error-function (n &optional reset) "Advance to the next error message and visits the file. This is the value of `next-error-function' in iESS buffers." ;; Modified version of `compilation-next-error-function'. (interactive "p") (if reset (goto-char (point-max))) (let* (;; (columns compilation-error-screen-columns) ; buffer's local value ;; (proc (or (get-buffer-process (current-buffer)) ;; (error "Current buffer has no process"))) (pbuff-p (get-buffer-process (current-buffer))) (n (or n 1)) (beg-pos ; from where the search for next error starts (if (and pbuff-p (>= n 0) (comint-after-pmark-p)) ess--tb-last-input (point))) (at-error t) (msg (condition-case nil (compilation-next-error n nil beg-pos) (error (when pbuff-p (ess--tb-next-error-goto-process-marker)) (if (< n 0) (message "Before first reference") (message "Beyond last reference"));(error-message-string err)) (setq at-error nil)))) (msg (if (or (not pbuff-p) (eq n 0) (> (point) ess--tb-last-input)) msg (ess--tb-next-error-goto-process-marker) (message "Beyond last-input marker") (setq at-error nil))) (marker (point-marker)) loc) (when at-error (setq compilation-current-error (point-marker) overlay-arrow-position (if (bolp) compilation-current-error (copy-marker (line-beginning-position))) loc (if (fboundp 'compilation--message->loc) (compilation--message->loc msg) (car msg))) (let* ((file (caar (nth 2 loc))) (col (car loc)) (line (cadr loc)) (mkrs (ess--dbg-create-ref-marker file line col))) (if mkrs ;; is this really needed? Shall we go directly to the location? (compilation-goto-locus marker (car mkrs) (cadr mkrs)) (message "Reference to '%s' not found" file)))))) (defun inferior-ess-move-last-input-overlay () "Move the overlay to the point." (let ((pbol (line-beginning-position))) (move-overlay ess--tb-last-input-overlay pbol (max (- (point) 2) (+ pbol 2))))) ;;;_* DEBUGGER (defgroup ess-debug nil "Debugging for ESS" :link '(emacs-library-link :tag "Source Lisp File" "ess-tracebug.el") :group 'ess-tracebug :prefix "ess-debug-") (defcustom ess-debug-error-action-alist '(( "" "NONE" "NULL" ) ( " r" "RECOVER" "utils::recover") ( " t" "TRACEBACK" "base::traceback")) "Alist of `on-error' actions. Toggled with `ess-debug-toggle-error-action'. Each element must have the form (DISP SYMB ACTION) where DISP is the string to be displayed in the mode line when the action is in place. SYMB is the symbolic name of an action. ACTION is the string giving the actual expression to be assigned to `error' user option. See R's help ?options for more details." :type '(alist :key-type string :value-type (group string string)) :group 'ess-debug) (defvar ess--dbg-output-buf-prefix " *ess.dbg" "The prefix of the buffer name the R debug output is directed to." ) (defvar-local ess--dbg-current-ref (make-marker) "Current debug reference in *ess.dbg* buffers (a marker).") (defvar-local ess--dbg-last-ref-marker (make-marker) "Last debug reference in *ess.dbg* buffer (a marker).") (defvar-local ess--dbg-buf-p nil "This is t in ess.dbg buffers.") ;; (defcustom ess--dbg-auto-single-key-p t ;; "If t entering the debug state triggers single-key mode. ;; Set it to nil if you want to trigger single-key mode manually ;; with the `ess-tracebug-prefix' key. ;; ") (defvar ess--dbg-current-debug-position (make-marker) "Marker to the current debugged line. It always point to the beginning of the currently debugged line and is used by overlay-arrow. In no-windowed Emacs an `overlay-arrow' is displayed at this position.") (unless window-system (add-to-list 'overlay-arrow-variable-list 'ess--dbg-current-debug-position)) (defface ess-debug-current-debug-line-face '((default (:inherit highlight))) "Face used to highlight currently debugged line." :group 'ess-debug) (defvar ess--dbg-current-debug-overlay (let ((overlay (make-overlay (point) (point)))) (overlay-put overlay 'face 'ess-debug-current-debug-line-face) (overlay-put overlay 'evaporate t) overlay) ;; should be global variable!! "The overlay for currently debugged line.") (defcustom ess-debug-blink-interval .2 "Time in seconds to blink the background of the debug line. Currently two events are defined `ref-not-found' and `same-ref'. Blinking colors for these events can be customized by corresponding faces." :group 'ess-debug :type 'float) (defface ess-debug-blink-ref-not-found-face '((((class grayscale) (background light)) (:background "DimGray")) (((class grayscale) (background dark)) (:background "LightGray")) (((class color) (background light) (min-colors 88)) (:background "IndianRed4")) (((class color) (background dark) (min-colors 88)) (:background "dark red")) (((background light) (min-colors 8)) (:foreground "red")) (((background dark) (min-colors 8)) (:foreground "red"))) "Face used to blink currently debugged line's background when the reference file is not found. See also `ess-debug-ask-for-file'" :group 'ess-debug ) (defface ess-debug-blink-same-ref-face '((((class grayscale) (background light)) (:background "DimGray")) (((class grayscale) (background dark)) (:background "LightGray")) (((class color) (background light) (min-colors 88)) (:background "steel blue")) (((class color) (background dark) (min-colors 88)) (:background "midnight blue")) (((background light) (min-colors 8)) (:foreground "blue")) (((background dark) (min-colors 8)) (:foreground "cyan"))) "Face used to highlight currently debugged line when new debug reference is the same as the preceding one. It is highlighted for `ess-debug-blink-interval' seconds." :group 'ess-debug ) (defcustom ess-debug-ask-for-file nil "If non nil, ask for file if the current debug reference is not found. If nil, the currently debugged line is highlighted for `ess-debug-blink-interval' seconds." :group 'ess-debug :type 'boolean) (defcustom ess-debug-skip-first-call t "If non-nil, skip first debugger call. In R first call doesn't contain source references and is skipped by default." :group 'ess-debug :type 'boolean) (defvar ess-electric-selection-map (let (ess-electric-selection-map) (define-prefix-command 'ess-electric-selection-map) ;; command-c and command-Q are not always working reliably (define-key ess-electric-selection-map "\M-N" #'ess-debug-command-continue) (define-key ess-electric-selection-map "\M-C" #'ess-debug-command-continue) (define-key ess-electric-selection-map "\M-Q" #'ess-debug-command-quit) (define-key ess-electric-selection-map "0" #'ess-debug-command-digit) (define-key ess-electric-selection-map "1" #'ess-debug-command-digit) (define-key ess-electric-selection-map "2" #'ess-debug-command-digit) (define-key ess-electric-selection-map "3" #'ess-debug-command-digit) (define-key ess-electric-selection-map "4" #'ess-debug-command-digit) (define-key ess-electric-selection-map "5" #'ess-debug-command-digit) (define-key ess-electric-selection-map "6" #'ess-debug-command-digit) (define-key ess-electric-selection-map "7" #'ess-debug-command-digit) (define-key ess-electric-selection-map "8" #'ess-debug-command-digit) (define-key ess-electric-selection-map "9" #'ess-debug-command-digit) (define-key ess-electric-selection-map "?" #'ess-tracebug-show-help) ess-electric-selection-map) "Keymap used to define commands for single key input mode. This commands are triggered by `ess-electric-selection' . \\{ess-electric-selection-map}") ;;;_ + debug functions (defun ess-debug-set-error-action (spec) "Set the on-error action. The SPEC should be one of the components of `ess-debug-error-action-alist'." (let ((proc (get-process ess-local-process-name))) (if spec (with-current-buffer (process-buffer proc) (process-put proc 'on-error-action (car spec)) (ess-command (format "options(error= %s )\n" (nth 2 spec)))) (error "Unknown action")))) (defun ess-debug-toggle-error-action () "Toggle the `on-error' action. The action list is in `ess-debug-error-action-alist'." (interactive) (ess-force-buffer-current) (let* ((ev last-command-event) (com-char (event-basic-type ev)) (cur-action (or (ess-process-get 'on-error-action) "")) actions act) (setq actions (cdr (member (assoc cur-action ess-debug-error-action-alist) ess-debug-error-action-alist))) (unless actions (setq actions ess-debug-error-action-alist)) (setq act (pop actions)) (ess-debug-set-error-action act) (message "On-error action set to: %s" (propertize (cadr act) 'face 'font-lock-function-name-face)) (while (eq (event-basic-type (setq ev (read-event))) com-char) (unless actions (setq actions ess-debug-error-action-alist)) (setq act (pop actions)) (ess-debug-set-error-action act) (force-mode-line-update) (message "On-error action set to: %s" (propertize (cadr act) 'face 'font-lock-function-name-face))) (push ev unread-command-events))) (defun ess--dbg-activate-overlays () "Initialize active debug line overlays." (move-overlay ess--dbg-current-debug-overlay (line-beginning-position) (1+ (line-end-position))) ;; used by overlay-arrow functionality on no-X, should be bol (move-marker ess--dbg-current-debug-position (line-beginning-position))) (defun ess--dbg-deactivate-overlays () "Delete debugger markers and overlays. Overlay arrow remains to indicate the last debug position." (delete-overlay ess--dbg-current-debug-overlay) (set-marker ess--dbg-current-debug-position nil)) ;;;_ + Work Flow (defun ess-debug-goto-input-event-marker () "Jump to the point where the last debugger/traceback etc event occurred. Mainly useful during/after debugging, to jump to the place from where the code was initially executed. This is an electric-command, which means that after the command is triggered a single key event is enough to navigate through the input-event-S-ring. If the key-event which triggered the command is Shift modified the input-event-S-ring is traversed backwards. The input-event-S-ring is a virtual object which consists of two rings `ess--dbg-forward-ring' and `ess--dbg-backward-ring' which are joint at their tops. See the more info at https://code.google.com/p/ess-tracebug/#Work-Flow" (interactive) (let* ((ev last-command-event) (com-char (event-basic-type ev)) (ring-el 0) input-point) (if (memq 'shift (event-modifiers ev)) (setq input-point (ring-ref ess--dbg-backward-ring 0)) (ring-insert ess--dbg-backward-ring (point-marker)) ;; insert in backward ring ;;TODO: check if the marker to this (close by?) position is already in the ring (setq input-point (ring-ref ess--dbg-forward-ring 0))) (when (marker-buffer input-point) ;; TODO: give a message here if buff is not found (pop-to-buffer-same-window (marker-buffer input-point)) (when (marker-position input-point) (goto-char (marker-position input-point)))) (while (eq (event-basic-type (event-basic-type (setq ev (read-event)))) com-char) (if (memq 'shift (event-modifiers ev)) (setq ring-el (1- ring-el)) (setq ring-el (1+ ring-el))) (if (< ring-el 0) (setq input-point (ring-ref ess--dbg-backward-ring (- ring-el))) ;; get it from backward-ring ;; get it from forward-ring (setq input-point (ring-ref ess--dbg-forward-ring ring-el)) ) (when (marker-buffer input-point) (pop-to-buffer-same-window (marker-buffer input-point)) (when (marker-position input-point) (goto-char (marker-position input-point))))) (push ev unread-command-events))) (defun ess-debug-goto-debug-point () "Return to the debugging position. Jump to markers stored in `ess--dbg-backward-ring'. If debug session is active, first jump to current debug line. This is an electric-command. Shift triggers the opposite traverse of the ring." (interactive) (let* ((debug-point (ring-ref ess--dbg-backward-ring 0)) (ev last-command-event) (com-char (event-basic-type ev)) (ring-el 0)) (if (ess--dbg-is-active-p) (progn (pop-to-buffer-same-window (marker-buffer ess--dbg-current-debug-position)) (goto-char (marker-position ess--dbg-current-debug-position )) (back-to-indentation)) (pop-to-buffer-same-window (marker-buffer debug-point)) (goto-char (marker-position debug-point))) (while (eq (event-basic-type (setq ev (read-event))) com-char) (if (memq 'shift (event-modifiers ev)) (setq ring-el (1- ring-el)) (setq ring-el (1+ ring-el))) (setq debug-point (ring-ref ess--dbg-backward-ring ring-el)) (when (marker-buffer debug-point) (pop-to-buffer-same-window (marker-buffer debug-point)) (when (marker-position debug-point) (goto-char (marker-position debug-point))))) (push ev unread-command-events))) (defun ess-debug-insert-in-forward-ring () "Insert `point-marker' into the forward-ring." (interactive) (ring-insert ess--dbg-forward-ring (point-marker)) (message "Point inserted into the forward-ring")) (defvar ess-debug-indicator " DB" "String to be displayed in mode-line alongside the process name. Indicates that ess-debug-mode is turned on. When the debugger is in active state this string is shown in upper case and highlighted.") (defvar-local ess--dbg-mode-line-debug '(:eval (let ((proc (get-process ess-local-process-name))) (if (and proc (process-get proc 'dbg-active)) (let ((str ess-debug-indicator)) (ess-debug-minor-mode 1) ; activate the keymap (put-text-property 1 (length str) 'face '(:foreground "white" :background "red") str) str) (ess-debug-minor-mode -1) "")))) (put 'ess--dbg-mode-line-debug 'risky-local-variable t) (defvar-local ess--dbg-mode-line-error-action '(:eval (or (and (ess-process-live-p) (ess-process-get 'on-error-action)) ""))) (put 'ess--dbg-mode-line-error-action 'risky-local-variable t) (defun ess--dbg-remove-empty-lines (string) "Remove empty lines from STRING (which interfere with evals) during debug. This function is placed in `ess-presend-filter-functions'." (if (and ess--dbg-del-empty-p (ess-process-get 'dbg-active)) (replace-regexp-in-string "\n\\s *$" "" string) string)) (defun ess-debug-start () "Start the debug session. Add to ESS the interactive debugging functionality, breakpoints, watch and loggers. Integrates into ESS and iESS modes by binding `ess-tracebug-map' to `ess-tracebug-prefix' in `ess-mode-map' and `inferior-ess-mode-map' respectively." (interactive) (let ((dbuff (get-buffer-create (concat ess--dbg-output-buf-prefix "." ess-current-process-name "*"))) ;TODO: make dbuff a string! (proc (ess-get-process ess-local-process-name)) (lpn ess-local-process-name)) (process-put proc 'dbg-buffer dbuff); buffer were the look up takes place (process-put proc 'dbg-active nil) ; t if the process is in active debug state. ; Active debug states are usually those, in which prompt start with Browser[d]> (set-process-filter proc #'inferior-ess-tracebug-output-filter) (with-current-buffer (process-buffer proc) (unless (equal ess-dialect "R") (error "Can not activate the debugger for %s dialect" ess-dialect)) (add-to-list 'ess--mode-line-process-indicator 'ess--dbg-mode-line-debug t) (add-to-list 'ess--mode-line-process-indicator 'ess--dbg-mode-line-error-action t) (add-hook 'ess-presend-filter-functions #'ess--dbg-remove-empty-lines nil 'local)) (with-current-buffer dbuff (setq ess-local-process-name lpn) (buffer-disable-undo) ;; (setq buffer-read-only nil) (make-local-variable 'overlay-arrow-position) ;; indicator for next-error functionality in the *ess.dbg*, useful?? (goto-char (point-max)) (setq ess--dbg-buf-p t ;; true if in *ess.dbg* buffer ess--dbg-current-ref (point-marker) ;; used by goto-error functionality ess--dbg-last-ref-marker (point-marker) ;; gives marker to reference of the last debugged line ) ;; (beginning-of-line) ;; (setq buffer-read-only t) ))) (defun ess-debug-stop () "End the debug session. Kill the *ess.dbg.[R_name]* buffer." ;;; process plist is not removed, TODO?low priority (interactive) (let ((proc (get-process ess-current-process-name))) ;;local? (with-current-buffer (process-buffer proc) (if (member ess-dialect '("XLS" "SAS" "STA")) (error "Can not deactivate the debugger for %s dialect" ess-dialect)) (delq 'ess--dbg-mode-line-debug ess--mode-line-process-indicator) (delq 'ess--dbg-mode-line-error-action ess--mode-line-process-indicator) (remove-hook 'ess-presend-filter-functions #'ess--dbg-remove-empty-lines 'local)) (set-process-filter proc #'inferior-ess-output-filter) (kill-buffer (process-get proc 'dbg-buffer)) (process-put proc 'dbg-buffer nil) (process-put proc 'dbg-active nil) ;; (when (buffer-live-p ess--dbg-buffer) ;; ;; (with-current-buffer ess--dbg-buffer ;; ;; (set-buffer-modified-p nil) ;; ;; ) ;; (kill-buffer ess--dbg-buffer) ;; ) )) (defun ess--make-busy-timer-function (process) "Display the spinner of prompt if PROCESS is busy." `(lambda () (let ((pb ,process)) (when (eq (process-status pb) 'run) ;; only when the process is alive (with-current-buffer (process-buffer pb) (if (not (process-get pb 'busy)) ;; if ready (when (> ess--busy-count 0) (setq ess--busy-count 0) (force-mode-line-update) (redisplay)) (setq ess--busy-count (1+ (mod ess--busy-count (1- (length ess-busy-strings))))) (force-mode-line-update) (redisplay))))))) ;; (ess--make-busy-prompt-function (get-process "R")) (defun ess--dbg-is-active-p () "Return t if the current R process is in active debugging state." (and (ess-process-live-p) (ess-process-get 'dbg-active))) (defun ess--dbg-is-recover-p () "Return t if the current R process is in active debugging state." (and (ess-process-live-p) (ess-process-get 'is-recover))) (defun ess-debug-active-p (&optional proc) (and (ess-process-live-p proc) (or (ess-process-get 'dbg-active proc) (ess-process-get 'is-recover proc)))) (defvar ess--dbg-regexp-reference "debug \\w+ +\\(.+\\)#\\([0-9]+\\):") (defvar ess--dbg-regexp-jump "debug \\w+ ") ;; debug at ,debug bei ,etc (defvar ess--dbg-regexp-skip ;; don't anchor to bol; secondary prompt can occur before (anything else?) ;; "\\(\\(?:Called from: \\)\\|\\(?:debugging in: \\)\\|\\(?:#[0-9]*: +recover()\\)\\)") "\\(\\(?:Called from: \\)\\|\\(?:#[0-9]*: +recover()\\)\\)") (defvar ess--dbg-regexp-no-skip ;; exceptions for first skip (magrittr) "debug_pipe") (defvar ess--dbg-regexp-debug "\\(\\(?:Browse[][0-9]+\\)\\|\\(?:debug: \\)\\)") (defvar ess--dbg-regexp-selection "\\(Selection: \\'\\)") (defvar ess--dbg-regexp-input (concat ess--dbg-regexp-debug "\\|" ess--dbg-regexp-selection)) (defvar ess--suppress-next-output? nil) ;;; MPI ;; http://jkorpela.fi/chars/c0.html ;; https://en.wikipedia.org/wiki/ANSI_escape_code#Escape_sequences (defvar ess-mpi-message-start-delimiter "_") (defvar ess-mpi-message-field-separator "") (defvar ess-mpi-message-end-delimiter "\\") (define-obsolete-variable-alias 'ess-mpi-alist 'ess-mpi-handlers "ESS 19.04") (defvar ess-mpi-handlers '(("message" . ess-mpi:message) ("error" . ess-mpi:error) ("eval" . ess-mpi:eval) ("y-or-n" . ess-mpi:y-or-n)) "Alist of the MPI handlers. Each element is of the form (TYPE . HANDLER), where TYPE is the message type and HANDLER is a function (symbol) to be called on the payload list of each message.") (defun ess-mpi:message (msg) (message "%s" msg)) (defun ess-mpi:error (msg) (error "MPI error: %s" msg)) (defun ess-mpi:eval (str &optional callback) "Read STR and evaluate as Emacs expression. If present, the CALLBACK string is passed through `format' with returned value from EXPR and then sent to the subprocess." (let ((result (eval (read str) t))) (when callback (ess-send-string (ess-get-process) (format callback result))))) (defun ess-mpi:y-or-n (prompt callback) "Ask `y-or-n-p' with PROMPT. The CALLBACK string is passed through `format' with returned value from EXPR and then sent to the subprocess." (let ((result (y-or-n-p prompt))) (when callback (let ((result (if result "TRUE" "FALSE"))) (ess-send-string (ess-get-process) (format callback result)))))) (defun ess-mpi-convert (el) (cond ((string= el "nil") nil) ((string= el "t") t) (t el))) (defun ess-mpi-handle-messages (buf) "Handle all mpi messages in BUF and delete them. The MPI message has the form TYPEFIELD... where TYPE is the type of the messages on which handlers in `ess-mpi-handlers' are dispatched. And FIELDs are strings. Return :incomplete if BUF ends with an incomplete message." (let ((obuf (current-buffer)) (out nil)) (with-current-buffer buf (goto-char (point-min)) ;; This should be smarter because Emacs might cut it in the middle of the ;; message. In practice this almost never happen because we are ;; accumulating output into the cache buffer. (while (search-forward ess-mpi-message-start-delimiter nil t) (let ((mbeg0 (match-beginning 0)) (mbeg (match-end 0))) (if (search-forward ess-mpi-message-end-delimiter nil t) (let* ((mend (match-beginning 0)) (mend0 (match-end 0)) (msg (buffer-substring mbeg mend)) (payload (mapcar #'ess-mpi-convert (split-string msg ess-mpi-message-field-separator))) (head (pop payload)) (handler (cdr (assoc head ess-mpi-handlers)))) (unwind-protect (if handler (with-current-buffer obuf (apply handler payload)) (error "No handler defined for MPI message '%s" head)) (goto-char mbeg0) (delete-region mbeg0 mend0))) (setq out :incomplete)))) out))) (defun ess--replace-long+-in-prompt (proc prompt is-final) "Replace long + + + in PROMPT based on `inferior-ess-replace-long+' value. If IS-FINAL means that PROMPT occurs at the end of the process chunk. If non-nil, special care is taken not to drop last '+' value as it might be a continuation prompt." ;; see #576 for interesting input examples (let ((len (length prompt)) (inferior-ess-replace-long+ (buffer-local-value 'inferior-ess-replace-long+ (process-buffer proc)))) (if (or (null inferior-ess-replace-long+) (< len 2)) prompt (let ((last+ (eq (elt prompt (- len 2)) ?+))) (cond ((eq inferior-ess-replace-long+ 'strip) (if (and last+ is-final) "+ " "> ")) ((eq inferior-ess-replace-long+ t) (let ((prompt (replace-regexp-in-string "\\(\\+ \\)\\{2\\}\\(\\+ \\)+" ess-long+replacement prompt))) (if (and last+ (not is-final)) ;; append > for aesthetic reasons (concat prompt "> ") prompt))) (t (error "Invalid values of `inferior-ess-replace-long+'"))))))) (defun ess--offset-output (prev-prompt str) "Add suitable offset to STR given the preceding PREV-PROMPT. Do nothing if `inferior-ess-fix-misaligned-output' is nil." (if (and inferior-ess-fix-misaligned-output prev-prompt) (let ((len (length prev-prompt))) ;; prompts have at least 2 chars (if (eq (elt prev-prompt (- len 2)) ?+) ;; when last + append > for aesthetic reasons (concat "> \n" str) (if (eq (elt str 0) ?\n) ;; don't insert empty lines str (concat "\n" str)))) str)) (defun ess--flush-accumulated-output (proc) "Flush accumulated output of PROC into its output buffer. Insertion happens chunk by chunk. A chunk is a region between two prompts." (let* ((abuf (ess--accumulation-buffer proc)) (pbuf (process-buffer proc)) (visibly (process-get proc :eval-visibly)) (nowait (eq visibly 'nowait)) (flush-timer (process-get proc 'flush-timer))) (when (> (buffer-size abuf) 0) (when (timerp flush-timer) (cancel-timer flush-timer)) (if (eq (buffer-local-value 'major-mode pbuf) 'fundamental-mode) ;; FIXME: this cannot be, ess-command changes the filter ;; Just in case if we are in *ess-command* buffer; restart the timer. (process-put proc 'flush-timer (run-at-time .02 nil #'ess--flush-accumulated-output proc)) ;; Incomplete mpi should hardly happen. Only on those rare occasions ;; when an mpi is issued after a long task and split by the Emacs input ;; handler, or mpi printing itself takes very long. (unless (eq :incomplete (ess-mpi-handle-messages abuf)) (with-current-buffer abuf ;; Uncomment this line when debugging. This pops up the ;; accumulation buffer and causes point to follow ;; automatically as the parsing progresses. ;; (pop-to-buffer (current-buffer)) (goto-char (point-min)) (let ((case-fold-search nil)) (when (re-search-forward "Error\\(:\\| +in\\)" nil t) (unless (get-buffer-window pbuf 'visible) (setq next-error-last-buffer pbuf) (display-buffer pbuf nil t)))) (goto-char (point-min)) ;; First long + + in the output mirrors the sent input by the user and ;; is unnecessary in nowait case. A single + can be a continuation in ;; the REPL, thus we check if there is an extra output after the + . (when nowait (when (looking-at "\\([+>] \\)\\{2,\\}\n?") (goto-char (match-end 0)) (when (eq (point) (point-max)) ;; if this is the last prompt in the output back-up one prompt ;; (cannot happen after \n) (backward-char 2)))) (let ((do-clean (not (eq visibly t))) (pos2 (point)) (pos1 (point)) (tpos nil) (prompt nil) (regexp (if nowait ;; we cannot disambiguate printed input fields and ;; prompts in output in this case; match 2+ pluses or ;; > and 2+ spaces "\\(^\\([+>] \\)\\{2,\\}\\)\\|\\(> \\) +" "^\\([+>] \\)+")) (prev-prompt (process-get proc 'prev-prompt))) (while (re-search-forward regexp nil t) (setq pos1 (match-beginning 0) tpos (if nowait (or (match-end 1) (match-end 3)) (match-end 0))) (when (> pos1 pos2) (let ((str (buffer-substring pos2 pos1))) (comint-output-filter proc (ess--offset-output prev-prompt str)))) (setq pos2 tpos) (setq prompt (let ((prompt (buffer-substring pos1 pos2))) (if do-clean (ess--replace-long+-in-prompt proc prompt (eq pos2 (point-max))) prompt))) ;; Cannot bypass this trivial call to comint-output-filter because ;; external tools could rely on prompts (org-babel [#598] for ;; example). Setting dummy regexp in order to avoid comint erasing ;; this prompt which contrasts to how we output prompts in all ;; other cases. (with-current-buffer pbuf (let ((comint-prompt-regexp "^$")) (comint-output-filter proc prompt))) (setq prev-prompt (and do-clean prompt) pos1 pos2)) ;; insert last chunk if any (unless (eq pos1 (point-max)) (let ((str (buffer-substring-no-properties pos1 (point-max)))) (comint-output-filter proc (ess--offset-output prev-prompt str)) (setq prev-prompt nil))) (process-put proc 'prev-prompt prev-prompt) (process-put proc 'flush-time (and (process-get proc 'busy) (float-time))) (erase-buffer)))))))) (defun inferior-ess-tracebug-output-filter (proc string) "Standard output filter for the inferior ESS process. When `ess-debug' is active, this is the filter. Call `inferior-ess-output-filter'. Check for debug reg-expressions (see `ess--dbg-regexp-debug',...), when found puts iESS in the debugging state. If in debugging state, mirrors the output into *ess.dbg* buffer." (let* ((is-iess (or (derived-mode-p 'ess-watch-mode) (derived-mode-p 'inferior-ess-mode))) (pbuf (process-buffer proc)) (abuf (ess--accumulation-buffer proc)) (dbuff (process-get proc 'dbg-buffer)) (wbuff (get-buffer ess-watch-buffer)) (was-in-dbg (process-get proc 'dbg-active)) (was-in-recover (process-get proc 'is-recover)) (input-point (point-marker)) (match-jump (string-match ess--dbg-regexp-jump string)) (match-input (string-match ess--dbg-regexp-input string)) (match-selection (and match-input (match-string 2 string))) ;; Selection: (match-skip (and ess-debug-skip-first-call (string-match ess--dbg-regexp-skip string) (not (string-match ess--dbg-regexp-no-skip string)))) (match-dbg (or match-skip (and match-input (not match-selection)))) (is-ready (inferior-ess--set-status proc string)) (new-time (float-time)) (last-time (process-get proc 'flush-time)) (flush-timer (process-get proc 'flush-timer))) ;; current-buffer is still the user's input buffer here (ess--if-verbose-write-process-state proc string "tracebug-filter") (inferior-ess-run-callback proc string) (process-put proc 'is-recover match-selection) (if (or (process-get proc 'suppress-next-output?) ess--suppress-next-output?) ;; works only for suppressing short output, enough for now (for callbacks) (process-put proc 'suppress-next-output? nil) (with-current-buffer abuf (goto-char (point-max)) (insert string)) ;; cancel the timer each time we enter this filter (when (timerp flush-timer) (cancel-timer flush-timer) (process-put proc 'flush-timer nil)) (unless last-time ;; don't flush for the first time (setq last-time new-time) (process-put proc 'flush-time new-time)) ;; flush periodically (let ((fast-flush (or is-ready ;; for the sake of ess-eval-linewise (process-get proc 'sec-prompt)))) (if (or ;; theoretically we should flush asynchronously in all cases but ;; somewhat unexpectedly it introduces much more randomness during ;; batch testing. TODO: flush directly for now and either remove or ;; improve on the next refactoring iteration fast-flush (> (- new-time last-time) .5) (bound-and-true-p edebug-mode) ;; the flush is not getting called if the third party call ;; accept-process-output in a loop (e.g. org-babel-execute-src-block) (bound-and-true-p org-babel-current-src-block-location)) (ess--flush-accumulated-output proc) ;; Setup new flush timer. Ideally also for fast-flush case in order to ;; avoid detecting intermediate prompts as end-of-output prompts. (let ((timeout (if fast-flush .01 .2))) (process-put proc 'flush-timer (run-at-time timeout nil #'ess--flush-accumulated-output proc)))))) ;; WATCH (when (and is-ready wbuff) ;; refresh only if the process is ready and wbuff exists, (not only in the debugger!!) (ess-watch-refresh-buffer-visibly wbuff)) ;; JUMP to line if debug expression was matched (when match-jump (with-current-buffer dbuff ;; insert string in *ess.dbg* buffer (goto-char (point-max)) (insert (concat "|-" string "-|"))) (ess--dbg-goto-last-ref-and-mark dbuff is-iess)) ;; (with-current-buffer dbuff ;; un-comment to see the value of STRING just before debugger exists ;; (let ((inhibit-read-only t)) ;; (goto-char (point-max)) ;; (insert (concat " ---\n " string "\n ---")) ;; )) ;; SKIP if needed (when (and match-skip (not was-in-recover)) (process-send-string proc "n\n")) ;; EXIT the debugger (when (and was-in-dbg (not (or match-jump match-dbg)) (or is-ready match-selection)) (ess--dbg-deactivate-overlays) (process-put proc 'dbg-active nil) ;; (message "|<-- exited debugging -->|") (when wbuff (ess-watch-refresh-buffer-visibly wbuff))) ;; ACTIVATE the debugger if entered for the first time (when (and (not was-in-dbg) (not match-selection) (or match-jump match-dbg)) (unless is-iess (ring-insert ess--dbg-forward-ring input-point)) (process-put proc 'dbg-active t) (message (ess--debug-keys-message-string)) (unless match-jump ;; no source reference, simply show the inferior (display-buffer pbuf))) (when (and match-selection (not is-iess)) ;(and (not was-in-recover) match-selection) (ess-electric-selection t)))) (defvar ess-debug-minor-mode-map (let ((map (make-sparse-keymap))) (define-key map (kbd "M-C") #'ess-debug-command-continue) (define-key map [(control meta ?C)] #'ess-debug-command-continue-multi) (define-key map (kbd "M-N") #'ess-debug-command-next) (define-key map [(control meta ?N)] #'ess-debug-command-next-multi) (define-key map (kbd "M-Q") #'ess-debug-command-quit) (define-key map (kbd "M-U") #'ess-debug-command-up) map) "Keymap active when ESS process is in debugging state. \\{ess-debug-minor-mode-map}") (define-minor-mode ess-debug-minor-mode "Minor mode activated when ESS process is in debugging state." :lighter nil :keymap ess-debug-minor-mode-map) (defun ess--dbg-goto-last-ref-and-mark (dbuff &optional other-window) "Open the most recent debug reference and set the necessary marks and overlays. It's called from `inferior-ess-tracebug-output-filter'. DBUFF must be the *ess.dbg* buffer associated with the process. If OTHER-WINDOW is non nil, attempt to open the location in a different window." (let (t-debug-position ref) (with-current-buffer dbuff (setq ref (ess--dbg-get-next-ref -1 (point-max) ess--dbg-last-ref-marker ess--dbg-regexp-reference)) ; sets point at the end of found ref (when ref (move-marker ess--dbg-last-ref-marker (line-end-position)) ;; each new step repositions the current-ref! (move-marker ess--dbg-current-ref ess--dbg-last-ref-marker))) (when ref (let ((buf (apply #'ess--dbg-goto-ref other-window ref))) (if buf ;; if referenced buffer has been found, put overlays: (with-current-buffer buf (setq t-debug-position (copy-marker (line-beginning-position))) (if (equal t-debug-position ess--dbg-current-debug-position) (progn ;; highlights the overlay for ess--dbg-blink-interval seconds (overlay-put ess--dbg-current-debug-overlay 'face 'ess--dbg-blink-same-ref-face) (run-with-timer ess-debug-blink-interval nil (lambda () (overlay-put ess--dbg-current-debug-overlay 'face 'ess-debug-current-debug-line-face)))) ;; else (ess--dbg-activate-overlays))) ;;else, buffer is not found: highlight and give the corresponding message (overlay-put ess--dbg-current-debug-overlay 'face 'ess--dbg-blink-ref-not-found-face) (run-with-timer ess-debug-blink-interval nil (lambda () (overlay-put ess--dbg-current-debug-overlay 'face 'ess-debug-current-debug-line-face))) (message "Reference %s not found" (car ref))))))) (defun ess--dbg-goto-ref (other-window file line &optional col) "Opens the reference given by FILE, LINE and COL. Try to open in a different window if OTHER-WINDOW is nil. Return the buffer if found, or nil otherwise be found. `ess--dbg-find-buffer' is used to find the FILE and open the associated buffer. If FILE is nil return nil." (let ((mrk (car (ess--dbg-create-ref-marker file line col))) (lpn ess-local-process-name)) (when mrk (let ((buf (marker-buffer mrk))) (if (not other-window) (pop-to-buffer-same-window buf) (let ((this-frame (window-frame (get-buffer-window (current-buffer))))) (display-buffer buf) ;; simple save-frame-excursion (unless (eq this-frame (window-frame (get-buffer-window buf t))) (ess-select-frame-set-input-focus this-frame)))) ;; set or re-set to lpn as this is the process with debug session on (with-current-buffer buf (setq ess-local-process-name lpn) (goto-char mrk) (set-window-point (get-buffer-window buf) mrk)) buf)))) ;; temporary, hopefully org folks implement something similar (defvar org-babel-tangled-file nil) (declare-function org-babel-tangle-jump-to-org "ob-tangle.el") (defun ess--dbg-create-ref-marker (file line &optional col) "Create markers to the reference given by FILE, LINE and COL. Return list of two markers MK-start and MK-end. MK-start is the position of error. Mk-end is the end of the line where error occurred. If buffer associated with FILE is not found, or line is nil, or TB-INDEX is not found return nil." (if (stringp line) (setq line (string-to-number line))) (if (stringp col) (setq col (string-to-number col))) (let* ((srcref (gethash file ess--srcrefs)) (file (replace-regexp-in-string "^\n" "" ;; hack for gnu regexp (or (car srcref) file))) (tb-index (cadr srcref)) (buffer (ess--dbg-find-buffer file)) pos) (when (and buffer line) (save-excursion (with-current-buffer buffer (save-restriction (widen) ;; how does this behave in narrowed buffers? tothink: (goto-char 1) (setq pos (point)) (when tb-index (while (and (not (eq tb-index (get-text-property pos 'tb-index))) (setq pos (next-single-property-change pos 'tb-index))))) (unless pos ;; use beg position if index not found (setq pos (nth 2 srcref))) (when pos (goto-char pos) (forward-line (1- line)) (if col (goto-char (+ (line-beginning-position) col)) (back-to-indentation)) (when (bound-and-true-p org-babel-tangled-file) (org-babel-tangle-jump-to-org)) (list (point-marker) (copy-marker (line-end-position)))))))))) (defvar ess-r-package-library-paths) (defun ess--dbg-find-buffer (filename) "Find a buffer for file FILENAME. If FILENAME is not found at all, ask the user where to find it if `ess--dbg-ask-for-file' is non-nil. Search the directories in `ess-tracebug-search-path' and `ess-r-package-library-paths'." (let ((dirs (append (ess-r-package-source-dirs) ess-r-package-library-paths (cl-loop for d in (append ess-tracebug-search-path) append (ess-r-package--all-source-dirs d)))) (filematch (format "%s\\'" filename)) buffer name) (setq dirs (delq nil (cons (with-ess-process-buffer t default-directory) dirs))) ;; 1. The file name is absolute. Use its explicit directory as ;; the first in the search path, and strip it from FILENAME. (when (and (null buffer) (file-name-absolute-p filename)) (setq filename (abbreviate-file-name (expand-file-name filename)) dirs (cons (file-name-directory filename) dirs) filename (file-name-nondirectory filename))) (or ;; 2. Search the path. (while (and (null buffer) dirs) (let ((thisdir (pop dirs))) (setq name (expand-file-name filename thisdir) buffer (and (file-exists-p name) (find-file-noselect name))))) buffer ;; 3. search already open buffers for match (associated file might not even exist yet) (cl-dolist (bf (buffer-list)) (with-current-buffer bf (when (and buffer-file-name (string-match filematch buffer-file-name)) (setq buffer bf) (cl-return)))) buffer ;; 4. Ask for file if not found (tothink: maybe remove this part?) (when ess-debug-ask-for-file (save-excursion ;This save-excursion is probably not right. (let* ((pop-up-windows t) (name (read-file-name (format "Find next line in (default %s): " filename) nil filename t nil)) (origname name)) (cond ((not (file-exists-p name)) (message "Cannot find file `%s'" name) (ding) (sit-for 2)) ((and (file-directory-p name) (not (file-exists-p (setq name (expand-file-name filename name))))) (message "No `%s' in directory %s" filename origname) (ding) (sit-for 2)) (t (setq buffer (find-file-noselect name))))))) buffer))) (defun ess--dbg-get-next-ref (n &optional pt BOUND REG nF nL nC) "Move point to the next reference in the *ess.dbg* buffer. Must be called from *ess.dbg* buffer. It returns the reference in the form (file line col) /all strings/ , or NIL if not found . Prefix arg N says how many error messages to move forwards (or backwards, if negative). Optional arg PT, if non-nil, specifies the value of point to start looking for the next message, default to (point). BOUND is the limiting position of the search. REG is the regular expression to search with. nF - sub-expression of REG giving the `file'; defaults to 1. nL - giving the `line'; defaults to 2. nC - sub-expr giving the `column'; defaults to 3." (unless ess--dbg-buf-p (error "Not in *ess.dbg* buffer")) (setq nF (or nF 1) nL (or nL 2) nC (or nC 3)) (or pt (setq pt (point))) ;; (message "ess--dbg-last-ref-marker%s vs pt%s vs point-max%s" ess--dbg-last-ref-marker pt (point-max)) (goto-char pt) (if (search-forward-regexp REG BOUND t n) (list (match-string nF) (match-string-no-properties nL) (match-string-no-properties nC)) nil)) (defun ess--debug-keys-message-string (&optional map) (let ((overriding-local-map (or map ess-debug-minor-mode-map))) (substitute-command-keys (mapconcat #'identity '("(\\[ess-debug-command-continue])cont" "(\\[ess-debug-command-continue-multi])cont-multi" "(\\[ess-debug-command-next])next" "(\\[ess-debug-command-next-multi])next-multi" "(\\[ess-debug-command-up])up" "(\\[ess-debug-command-quit])quit") " ")))) (defun ess-electric-selection (&optional wait) "Call commands defined in `ess-electric-selection-map'. Single-key input commands are those, which once executed do not require the prefix command for subsequent invocation. If WAIT is t, wait for next input and ignore the keystroke which triggered the command." (interactive) (ess--execute-electric-command ess-electric-selection-map "Selection: " wait (not (ess-process-get 'is-recover)))) (defun ess-debug-command-digit (&optional ev) "Digit commands in selection mode. If supplied, EV must be a proper key event or a string representing the digit." (interactive) (ess-force-buffer-current) (unless (ess--dbg-is-recover-p) (error "Recover is not active")) (unless ev (setq ev last-command-event)) (let* ((ev-char (if (stringp ev) ev (char-to-string (event-basic-type ev)))) (proc (get-process ess-current-process-name)) (mark-pos (marker-position (process-mark proc))) (comint-prompt-read-only nil) prompt depth) (with-current-buffer (process-buffer proc) (goto-char mark-pos) (save-excursion (when (re-search-backward "\\(?: \\|^\\)\\([0-9]+\\):[^\t]+Selection:" ess--tb-last-input t) (setq depth (string-to-number (match-string 1))) (when (> depth 9) (setq ev-char (ess-completing-read "Selection" (mapcar #'number-to-string (number-sequence depth 0 -1)) nil t ev-char nil))))) (setq prompt (delete-and-extract-region (line-beginning-position) mark-pos)) (insert (concat prompt ev-char "\n")) (ess-send-string proc ev-char) (move-marker (process-mark proc) (max-char))))) (defun ess-debug-command-next () "Step next in debug mode. Equivalent to `n' at the R prompt." (interactive) (ess-force-buffer-current) (unless (ess--dbg-is-active-p) (error "Debugger is not active")) (if (ess--dbg-is-recover-p) (ess-send-string (ess-get-process) "0") (ess-send-string (ess-get-process) "n"))) (defun ess-debug-command-next-multi (&optional N) "Ask for N and step (n) N times in debug mode." (interactive) (ess-force-buffer-current) (unless (ess--dbg-is-active-p) (error "Debugger is not active")) (let ((N (or N (read-number "Number of steps: " 10))) (ess--suppress-next-output? t)) (while (and (ess--dbg-is-active-p) (> N 0)) (ess-debug-command-next) (ess-wait-for-process) (setq N (1- N)))) (ess-debug-command-next)) (defun ess-debug-command-continue-multi (&optional N) "Ask for N, and continue (c) N times in debug mode." (interactive) (ess-force-buffer-current) (unless (ess--dbg-is-active-p) (error "Debugger is not active")) (let ((N (or N (read-number "Number of continuations: " 10))) (ess--suppress-next-output? t)) (while (and (ess--dbg-is-active-p) (> N 1)) (ess-debug-command-continue) (ess-wait-for-process) (setq N (1- N)))) (ess-debug-command-continue)) (defun ess-debug-command-up () "Step up one call frame.." (interactive) (ess-force-buffer-current) (unless (ess--dbg-is-active-p) (error "Debugger is not active")) (let ((up-cmd "try(browserSetDebug(), silent=T)\nc\n")) (ess-send-string (ess-get-process) up-cmd))) ;; (defun ess-debug-previous-error (&optional ev) ;; "Go to previous reference during the debug process. ;; R doesn't support step backwards. This command just takes you through ;; debug history." ;; (interactive) ;; (previous-error)) (defun ess-debug-command-quit () "Quits the browser/debug in R process. Equivalent of `Q' at the R prompt." (interactive) (ess-force-buffer-current) (cond ((ess--dbg-is-recover-p) (ess-send-string (ess-get-process) "0" t)) ;; if recover is called in a loop the following stalls Emacs ;; (ess-wait-for-process proc nil 0.05) ((ess--dbg-is-active-p) (ess-send-string (ess-get-process) "Q" t)) (t (error "Debugger is not active")))) (defun ess-debug-command-continue () "Continue the code execution. Equivalent of `c' at the R prompt." (interactive) (ess-force-buffer-current) (cond ((ess--dbg-is-recover-p) (ess-send-string (ess-get-process) "0")) ((ess--dbg-is-active-p) (ess-send-string (ess-get-process) "c")) (t (error "Debugger is not active")))) (defun ess-tracebug-set-last-input (&rest _args) "Move `ess--tb-last-input' marker to the process mark. ARGS are ignored to allow using this function in process hooks." (let* ((last-input-process (get-process ess-local-process-name)) (last-input-mark (copy-marker (process-mark last-input-process)))) (with-current-buffer (process-buffer last-input-process) (when (local-variable-p 'ess--tb-last-input) ;; TB might not be active in all processes (save-excursion (setq ess--tb-last-input last-input-mark) (goto-char last-input-mark) (inferior-ess-move-last-input-overlay)))))) ;;;_ + BREAKPOINTS (defface ess-bp-fringe-inactive-face '((((class color) (background light) (min-colors 88)) (:foreground "DimGray")) (((class color) (background dark) (min-colors 88)) (:foreground "LightGray")) (((background light) (min-colors 8)) (:foreground "blue")) (((background dark) (min-colors 8)) (:foreground "cyan"))) "Face used to highlight inactive breakpoints." :group 'ess-debug) (defface ess-bp-fringe-logger-face '((((class color) (background light) (min-colors 88)) (:foreground "dark red")) (((class color) (background dark) (min-colors 88)) (:foreground "tomato1")) (((background light) (min-colors 8)) (:foreground "blue")) (((background dark) (min-colors 8)) (:foreground "cyan"))) "Face used to highlight loggers." :group 'ess-debug) (defface ess-bp-fringe-browser-face '((((class color) (background light) (min-colors 88)) (:foreground "medium blue")) (((class color) (background dark) (min-colors 88)) (:foreground "deep sky blue")) (((background light) (min-colors 8)) (:foreground "blue")) (((background dark) (min-colors 8)) (:foreground "cyan"))) "Face used to highlight `browser' breakpoints." :group 'ess-debug) (defface ess-bp-fringe-recover-face '((((class color) (background light) (min-colors 88)) (:foreground "dark magenta")) (((class color) (background dark) (min-colors 88)) (:foreground "magenta")) (((background light) (min-colors 8)) (:foreground "magenta")) (((background dark) (min-colors 8)) (:foreground "magenta"))) "Face used to highlight `recover' breakpoints fringe." :group 'ess-debug) (defun ess--bp-pipe-block-p () (save-excursion (let ((inhibit-field-text-motion t)) (forward-line -1) (end-of-line) (looking-back "%>%[ \t]*" (line-beginning-position))))) (defun ess--bp-pipe-native-block-p () (save-excursion (let ((inhibit-field-text-motion t)) (forward-line -1) (end-of-line) (looking-back "|>[ \t]*" (line-beginning-position))))) (defvar ess--bp-identifier 1) (defcustom ess-bp-type-spec-alist '((pipe ".ess_pipe_browser() %%>%%" "B %>%\n" filled-square ess-bp-fringe-browser-face ess--bp-pipe-block-p) (pipe-native ".ess_pipe_browser() |>" "B |>\n" filled-square ess-bp-fringe-browser-face ess--bp-pipe-native-block-p) (browser "browser(expr=is.null(.ESSBP.[[%s]]));" "B>\n" filled-square ess-bp-fringe-browser-face) (recover "recover()" "R>\n" filled-square ess-bp-fringe-recover-face)) "List of lists of breakpoint types. Each sublist has five elements: 1- symbol giving the name of specification 2- R expression to be inserted (%s is substituted with unique identifier). 3- string to be displayed instead of the expression 4- fringe bitmap to use 5- face for fringe and displayed string 6- optional, a function which should return nil if this BP doesn't apply to current context." :group 'ess-debug :type '(alist :key-type symbol :value-type (group string string symbol face))) (defcustom ess-bp-inactive-spec '(inactive "##" filled-square ess-bp-fringe-inactive-face) "List giving the inactive breakpoint specifications." ;; List format is identical to that of the elements of ;; `ess-bp-type-spec-alist' except that the second element giving ;; the R expression is meaningless here." ;;fixme: second element is missing make it nil for consistency with all other specs :group 'ess-debug :type 'list) (defcustom ess-bp-conditional-spec '(conditional "browser(expr={%s})" "CB[ %s ]>\n" question-mark ess-bp-fringe-browser-face) "List giving the conditional breakpoint specifications. List format is identical to that of the elements of `ess-bp-type-spec-alist'. User is asked for the conditional expression to be replaced instead of %s in the second and third elements of the specifications." :group 'ess-debug :type 'list) (defcustom ess-bp-logger-spec '(logger ".ess_log_eval('%s')" "L[ \"%s\" ]>\n" hollow-square ess-bp-fringe-logger-face) "List giving the loggers specifications. List format is identical to that of `ess-bp-type-spec-alist'." :group 'ess-debug :type 'list) (defun ess-bp-get-bp-specs (type &optional condition no-error) "Get specs for TYPE." (let ((spec-alist (cond ((eq type 'conditional) (let ((tl (copy-sequence ess-bp-conditional-spec))) (when (eq (length condition) 0) (setq condition "TRUE")) (setcar (cdr tl) (format (cadr tl) condition)) (setcar (cddr tl) (format (caddr tl) condition)) (list tl))) ((eq type 'logger) (let ((tl (copy-sequence ess-bp-logger-spec))) (when (eq (length condition) 0) (setq condition "watchLog")) (setcar (cdr tl) (format (cadr tl) condition)) (setcar (cddr tl) (format (caddr tl) condition)) (list tl))) (t (copy-sequence ess-bp-type-spec-alist))))) (or (assoc type spec-alist) (if no-error nil (error "Undefined breakpoint type %s" type))))) (defun ess-bp-create (type &optional condition no-error) "Set breakpoint for the current line. Returns the beginning position of the hidden text." (let* ((bp-specs (ess-bp-get-bp-specs type condition no-error)) (init-pos (point-marker)) (fringe-bitmap (nth 3 bp-specs)) (fringe-face (nth 4 bp-specs)) (displ-string (nth 2 bp-specs)) (bp-id (format "\"@%s@\"" (setq ess--bp-identifier (1+ ess--bp-identifier)))) (bp-command (concat (format (nth 1 bp-specs) bp-id) "##:ess-bp-end:##\n")) (dummy-string (format "##:ess-bp-start::%s@%s:##\n" (car bp-specs) condition)) insertion-pos) (when bp-specs (set-marker init-pos (1+ init-pos)) (setq displ-string (propertize displ-string 'face fringe-face 'font-lock-face fringe-face)) (setq bp-command (propertize bp-command 'ess-bp t 'bp-id bp-id 'bp-active t 'cursor-intangible 'ess-bp 'rear-nonsticky '(cursor-intangible ess-bp bp-type) 'bp-type type 'bp-substring 'command 'display displ-string)) (setq dummy-string (propertize (ess-tracebug--propertize dummy-string fringe-bitmap fringe-face "*") 'ess-bp t 'cursor-intangible 'ess-bp 'bp-type type 'bp-substring 'dummy)) (ess-tracebug--set-left-margin) (back-to-indentation) (setq insertion-pos (point) ) (insert (concat dummy-string bp-command)) (indent-for-tab-command) (goto-char (1- init-pos)) ;; sort of save-excursion insertion-pos))) (defun ess-bp-recreate-all () "Internal function to recreate all bp." (save-excursion (save-restriction (with-silent-modifications (cursor-intangible-mode) (widen) (goto-char (point-min)) (while (re-search-forward "\\(##:ess-bp-start::\\(.*\\):##\n\\)\\(.+##:ess-bp-end:##\n\\)" nil t) (let ((dum-beg (match-beginning 1)) (dum-end (match-end 1)) (comm-beg (match-beginning 3)) (comm-end (match-end 3)) (type (match-string 2)) (bp-command (match-string 3)) bp-id dum-props condition) (when (string-match "^\\(\\w+\\)@\\(.*\\)\\'" type) (setq condition (match-string 2 type)) (setq type (match-string 1 type))) (setq bp-id (if (string-match "\"@[0-9]+@\"" bp-command) (match-string 0 bp-command) (setq ess--bp-identifier (1+ ess--bp-identifier)))) (setq type (intern type)) (let* ((bp-specs (ess-bp-get-bp-specs type condition t)) (displ-string (nth 2 bp-specs)) (fringe-face (nth 4 bp-specs)) (fringe-bitmap (nth 3 bp-specs))) (when bp-specs (setq displ-string (propertize displ-string 'face fringe-face 'font-lock-face fringe-face)) (add-text-properties comm-beg comm-end (list 'ess-bp t 'bp-id bp-id 'cursor-intangible 'ess-bp 'rear-nonsticky '(cursor-intangible ess-bp bp-type) 'bp-type type 'bp-substring 'command 'display displ-string)) (setq dum-props (if window-system (list 'display (list 'left-fringe fringe-bitmap fringe-face)) (list 'display (list '(margin left-margin) (propertize "dummy" 'font-lock-face fringe-face 'face fringe-face))))) (add-text-properties dum-beg dum-end (append dum-props (list 'ess-bp t 'cursor-intangible 'ess-bp 'bp-type type 'bp-substring 'dummy))) ;; (when comment-beg ;; (add-text-properties comment-beg comment-end ;; (list 'ess-bp t ;; 'bp-id bp-id ;; 'cursor-intangible 'ess-bp ;; 'display (propertize (nth 1 ess-bp-inactive-spec) 'face fringe-face) ;; 'bp-type type ;; 'bp-substring 'comment))) )))))))) (add-hook 'ess-r-mode-hook #'ess-bp-recreate-all) (defun ess-bp-get-bp-position-nearby () "Get nearby break points. Return the cons (beg . end) of breakpoint limit points closest to the current position. Only currently visible region of the buffer is searched. This command is intended for use in interactive commands like `ess-bp-toggle-state' and `ess-bp-kill'. Use `ess-bp-previous-position' in programs." (interactive) (let* ((pos-end (if (get-char-property (1- (point)) 'ess-bp) (point) (previous-single-property-change (point) 'ess-bp nil (window-start)))) (pos-start (if (get-char-property (point) 'ess-bp) ;;check for bobp (point) (next-single-property-change (point) 'ess-bp nil (window-end)))) dist-up dist-down) (unless (eq pos-end (window-start)) (setq dist-up (- (line-number-at-pos (point)) (line-number-at-pos pos-end)))) (unless (eq pos-start (window-end)) (setq dist-down (- (line-number-at-pos pos-start) (line-number-at-pos (point))))) (if (and dist-up dist-down) (if (< dist-up dist-down) (cons (previous-single-property-change pos-end 'ess-bp nil (window-start)) pos-end) (cons pos-start (next-single-property-change pos-start 'ess-bp nil (window-end)))) (if dist-up (cons (previous-single-property-change pos-end 'ess-bp nil (window-start)) pos-end) (if dist-down (cons pos-start (next-single-property-change pos-start 'ess-bp nil (window-end)))))))) (defun ess-bp-previous-position () "Get previous breakpoints. Return the cons (beg . end) of breakpoint limit points closest to the current position, nil if not found." (let* ( (pos-end (if (get-char-property (1- (point)) 'ess-bp) (point) (previous-single-property-change (point) 'ess-bp )))) (if pos-end (cons (previous-single-property-change pos-end 'ess-bp) pos-end)))) (defun ess-bp-set () "Set a breakpoint." (interactive) (let* ((pos (ess-bp-get-bp-position-nearby)) (same-line (and pos (<= (line-beginning-position) (cdr pos)) (>= (line-end-position) (car pos)))) (types ess-bp-type-spec-alist) (ev last-command-event) (com-char (event-basic-type ev)) bp-type) (when same-line ;; set bp-type to next type in types (setq bp-type (get-text-property (car pos) 'bp-type)) (setq types (cdr (member (assq bp-type types) types))) ; nil if bp-type is last in the list (when (null types) (setq types ess-bp-type-spec-alist)) (ess-bp-kill) (indent-for-tab-command)) ;; skip contextual bps (while (and (nth 5 (car types)) (not (funcall (nth 5 (car types))))) (pop types)) (setq bp-type (pop types)) (ess-bp-create (car bp-type)) (while (eq (event-basic-type (setq ev (read-event (format "'%c' to cycle" com-char)))) com-char) (if (null types) (setq types ess-bp-type-spec-alist)) (ess-bp-kill) ;; skip contextual bps (while (and (nth 5 (car types)) (not (funcall (nth 5 (car types))))) (pop types)) (setq bp-type (pop types)) (ess-bp-create (car bp-type)) (indent-for-tab-command)) (push ev unread-command-events))) (defun ess-bp-set-conditional (condition) (interactive "sBreakpoint condition: ") (ess-bp-create 'conditional condition) (indent-for-tab-command)) (defun ess-bp-set-logger (name) (interactive "sLogger name : ") (ess-bp-create 'logger name) (indent-for-tab-command)) (defun ess-bp-kill (&optional interactive?) "Remove the breakpoint nearby." (interactive "p") (let ((pos (ess-bp-get-bp-position-nearby)) (init-pos (make-marker))) (if (null pos) (if interactive? (message "No breakpoints nearby")) (if (eq (point) (line-end-position)) (goto-char (1- (point)))) ;; work-around for issue 3 (set-marker init-pos (point)) (goto-char (car pos)) (delete-region (car pos) (cdr pos)) (indent-for-tab-command) (goto-char init-pos) (if (eq (point) (line-end-position)) (forward-char))))) (defun ess-bp-kill-all nil "Delete all breakpoints in current buffer." (interactive) (let ((count 0) (init-pos (make-marker)) pos) (set-marker init-pos (1+ (point))) (save-excursion ;; needed if error (goto-char (point-max)) (while (setq pos (ess-bp-previous-position)) (goto-char (car pos)) (delete-region (car pos) (cdr pos)) (indent-for-tab-command) (setq count (1+ count))) (if (eq count 1) (message "Killed 1 breakpoint") (message "Killed %d breakpoint(s)" count))) (goto-char (1- init-pos)))) (defun ess-bp-toggle-state () "Toggle the breakpoint between active and inactive states. For standard breakpoints, the effect of this command is immediate, that is you don't need to source your code and it works even in the process of debugging. For loggers, recover and conditional breakpoints this command just comments the breakpoint in the source file. If there is no active R session, this command triggers an error." (interactive) (unless (and ess-local-process-name (get-process ess-local-process-name)) (error "No R session in this buffer")) (save-excursion (let ((pos (ess-bp-get-bp-position-nearby)) (fringe-face (nth 3 ess-bp-inactive-spec)) (cursor-sensor-inhibit 'ess-bp-toggle-state) bp-id bp-specs beg-pos-command) (if (null pos) (message "No breakpoints in the visible region") (goto-char (car pos)) (setq beg-pos-command (previous-single-property-change (cdr pos) 'bp-substring nil (car pos)) bp-id (get-char-property beg-pos-command 'bp-id)) (goto-char beg-pos-command) (if (get-char-property beg-pos-command 'bp-active) (progn (put-text-property (car pos) beg-pos-command ;; dummy display change 'display (list 'left-fringe (nth 2 ess-bp-inactive-spec) fringe-face)) (put-text-property beg-pos-command (cdr pos) 'bp-active nil) (ess-command (format ".ESSBP.[[%s]] <- TRUE\n" bp-id))) (setq bp-specs (assoc (get-text-property (point) 'bp-type) ess-bp-type-spec-alist)) (put-text-property beg-pos-command (cdr pos) 'bp-active t) (put-text-property (car pos) beg-pos-command 'display (list 'left-fringe (nth 3 bp-specs) (nth 4 bp-specs))) (ess-command (format ".ESSBP.[[%s]] <- NULL\n" bp-id)) ;; (insert (propertize "##" ;; 'ess-bp t ;; 'cursor-intangible 'ess-bp ;; 'display (propertize (nth 1 ess-bp-inactive-spec) 'face fringe-face) ;; 'bp-type (get-char-property (point) 'bp-type) ;; 'bp-substring 'comment)) ))))) (defun ess-bp-make-visible () "Make bp text visible." (interactive) (let ((pos (ess-bp-get-bp-position-nearby))) (set-text-properties (car pos) (cdr pos) (list 'display nil)))) (defun ess-bp-next nil "Goto next breakpoint." (interactive) (when-let ((bp-pos (next-single-property-change (point) 'ess-bp))) (save-excursion (goto-char bp-pos) (when (get-text-property (1- (point)) 'ess-bp) (setq bp-pos (next-single-property-change bp-pos 'ess-bp)))) (if bp-pos (goto-char bp-pos) (message "No breakpoints found")))) (defun ess-bp-previous nil "Goto previous breakpoint." (interactive) (if-let ((bp-pos (previous-single-property-change (point) 'ess-bp))) (goto-char (or (previous-single-property-change bp-pos 'ess-bp) bp-pos)) (message "No breakpoints before the point found"))) ;;;_ + WATCH (defvar ess-watch-command ;; assumes that every expression is a structure of length 1 as returned by parse. ".ess_watch_eval()\n") (if (fboundp 'define-fringe-bitmap) ;;not clear to me why is this not bound in SSH session? - :TODO check (define-fringe-bitmap 'current-watch-bar [#b00001100] nil nil '(top t))) (defun ess-tracebug--set-left-margin () "Set the margin on non-X displays." (unless window-system (when (= left-margin-width 0) (setq left-margin-width 1) (set-window-buffer (selected-window) (current-buffer))))) (define-derived-mode ess-watch-mode special-mode "ESS watch" "Major mode in `ess-watch' window." :group 'ess-tracebug (let ((cur-block (max 1 (ess-watch-block-at-point))) (dummy-string (ess-tracebug--propertize "|" 'current-watch-bar 'font-lock-keyword-face))) (ess-tracebug--set-left-margin) (setq-local revert-buffer-function #'ess-watch-revert-buffer) (turn-on-font-lock) (setq ess-watch-current-block-overlay (make-overlay (point-min) (point-max))) (overlay-put ess-watch-current-block-overlay 'line-prefix dummy-string) (overlay-put ess-watch-current-block-overlay 'face 'ess-watch-current-block-face) (ess-watch-set-current cur-block) ;; (require 'face-remap) ;; scale the font (setq text-scale-mode-amount ess-watch-scale-amount) (text-scale-mode))) (defun ess-watch () "Run `ess-watch-mode' on R objects. This is the trigger function. See documentation of `ess-watch-mode' for more information." (interactive) (ess-force-buffer-current) (let ((wbuf (get-buffer-create ess-watch-buffer)) (pname ess-local-process-name)) (pop-to-buffer wbuf ;; not strongly dedicated '(nil . ((dedicated . 1)))) (setq ess-local-process-name pname) (ess-watch-mode) ;; evals the ess-command and displays the buffer if not visible (ess-watch-refresh-buffer-visibly wbuf))) (defun ess-watch-refresh-buffer-visibly (wbuf &optional sleep no-prompt-check) "Eval `ess-watch-command' and direct the output into the WBUF. Call `ess-watch-buffer-show' to make the buffer visible, without selecting it. SLEEP and NO-PROMPT-CHECK get passed to `ess-command'. This function is used for refreshing the watch window after each step during the debugging." ;; assumes that the ess-watch-mode is on!! ;; particularly ess-watch-current-block-overlay is installed (ess-watch-buffer-show wbuf) ;; if visible do nothing (let ((pname ess-local-process-name)) ;; watch might be used from different dialects, need to reset (with-current-buffer wbuf (let ((curr-block (max 1 (ess-watch-block-at-point))) ;;can be 0 if (inhibit-read-only t)) (when pname (setq ess-local-process-name pname)) (ess-command ess-watch-command wbuf sleep no-prompt-check) ;; delete the ++++++> line ;; not very reliable but works fine so far. (goto-char (point-min)) (delete-region (line-beginning-position) (+ 1 (line-end-position))) (ess-watch-set-current curr-block) (set-window-point (get-buffer-window wbuf) (point)))))) (defun ess-watch-buffer-show (buffer-or-name) "Make watch buffer BUFFER-OR-NAME visible, and position accordingly. If already visible, do nothing. Currently the only positioning rule implemented is to split the R process window in half. The behavior is controlled by `split-window-sensibly' with parameters `split-height-threshold' and `split-width-threshold' replaced by `ess-watch-height-threshold' and `ess-watch-width-threshold' respectively." (interactive) (unless (get-buffer-window ess-watch-buffer 'visible) (save-selected-window (ess-switch-to-ESS t) (let* ((split-width-threshold (or ess-watch-width-threshold split-width-threshold)) (split-height-threshold (or ess-watch-height-threshold split-height-threshold)) (win (split-window-sensibly (selected-window)))) (if win (set-window-buffer win buffer-or-name) (display-buffer buffer-or-name) ;; resort to usual mechanism if could not split ))))) (defun ess-watch-revert-buffer (_ignore _noconfirm) "Update the watch buffer. Arguments IGNORE and NOCONFIRM currently not used." (ess-watch) (message "Watch reverted")) (defface ess-watch-current-block-face '((default (:inherit highlight))) "Face used to highlight current watch block." :group 'ess-debug) (defvar ess-watch-start-block "@----" ;; fixme: make defcustom and modify the injected command correspondingly "String indicating the beginning of a block in watch buffer." ;; :group 'ess-debug ;; :type 'string ) (defvar ess-watch-start-expression "@---:" "String indicating the beginning of an R expression in watch buffer." ;; :group 'ess-debug ;; :type 'string ) (defun ess-watch-block-limits-at-point () "Return start and end positions of the watch block." (interactive) (save-excursion (let ((curr (point)) start-pos end-pos) (end-of-line) (setq start-pos (if (re-search-backward ess-watch-start-block nil t ) (point) (point-min))) (goto-char curr) (beginning-of-line) (setq end-pos (if (re-search-forward ess-watch-start-block nil t) (match-beginning 0) (point-max))) (list start-pos end-pos)))) (defun ess-watch-block-at-point () "Return the current block's order count, 0 if no block was found." (save-excursion (let ((cur-point (point)) (count 0)) (goto-char (point-min)) (while (re-search-forward ess-watch-start-block cur-point t) (setq count (1+ count))) count))) (defun ess-watch-set-current (nr) "Move the overlay over the block with count NR in current watch buffer." (goto-char (point-min)) (re-search-forward ess-watch-start-expression nil t nr) (goto-char (match-end 0)) (apply #'move-overlay ess-watch-current-block-overlay (ess-watch-block-limits-at-point))) (defun ess-watch--make-alist () "Create an alist of expressions from the current watch buffer. Each element of assoc list is of the form (pos name expr) where pos is an unique integer identifying watch blocks by position, name is a string giving the name of expression block, expr is a string giving the actual R expression." (interactive) (save-excursion (let* ((reg-name (concat "^" ess-watch-start-block " *\\(\\S-*\\).*$")) (reg-expr (concat "^" ess-watch-start-expression "\\s-*\\(.*\\)$")) (reg-all (concat "\\(" reg-name "\\)\n\\(" reg-expr "\\)")) (pos 0) wal name expr) (goto-char (point-min)) (while (re-search-forward reg-all nil t) (setq pos (+ 1 pos)) (setq name (match-string-no-properties 2)) (setq expr (match-string-no-properties 4)) (if (not (eq (string-to-number name) 0)) ;;if number of any kind set the name to "" (setq name "")) (setq wal (append wal (list (list pos name expr))))) wal))) (defun ess-watch--parse-assoc (al) "Return a string command ready to be passed to R process. The command is of the form `assign(\".ess_watch_expressions\", list(a = parse(expr_a), b= parse(expr_b)), envir = .GlobalEnv)'. AL is an association list as return by `ess-watch--make-alist'" (concat ".ess_watch_assign_expressions(list(" (mapconcat (lambda (el) (if (> (length (cadr el) ) 0) (concat "`" (cadr el) "` = parse(text = '" (caddr el) "')") (concat "parse(text = '" (caddr el) "')"))) al ", ") "))\n")) (defun ess-watch--install-.ess_watch_expressions () ;; used whenever watches are added/deleted/modified from the watch ;; buffer. this is the only way to insert expressions into ;; .ess_watch_expressions object in R. Assumes R watch being the current ;; buffer, otherwise will most likely install empty list. (interactive) (process-send-string (ess-get-process ess-current-process-name) (ess-watch--parse-assoc (ess-watch--make-alist))) ;;TODO: delete the prompt at the end of proc buffer TODO: defun ess-send-string!! (sleep-for 0.05) ;; need here, if ess-command is used immediately after, for some weird reason the process buffer will not be changed ) (defun ess-watch-quit () "Quit (kill) the watch buffer. If watch buffer exists, it is displayed during the debug process. The only way to avoid the display, is to kill the buffer." (interactive) (kill-buffer) ;; dedicated, window is deleted unless not the only one ) ;;;_ + MOTION (defun ess-watch-next-block (&optional n) "Move the overlay over the next block. Optional N if supplied gives the number of steps forward `backward-char'." (interactive "P") (setq n (prefix-numeric-value n)) (goto-char (overlay-end ess-watch-current-block-overlay)) (unless (re-search-forward ess-watch-start-expression nil t n) (goto-char (point-min)) ;;circular but always moves to start! (re-search-forward ess-watch-start-expression nil t 1)) (apply #'move-overlay ess-watch-current-block-overlay (ess-watch-block-limits-at-point))) (defun ess-watch-previous-block (&optional n) "Move the overlay over the previous block. Optional N if supplied gives the number of backward steps." (interactive "P") (setq n (prefix-numeric-value n)) (goto-char (overlay-start ess-watch-current-block-overlay)) (unless (re-search-backward ess-watch-start-expression nil t n) (goto-char (point-max)) ;;circular but always moves to last! (re-search-backward ess-watch-start-expression nil t 1)) (goto-char (match-end 0)) (apply #'move-overlay ess-watch-current-block-overlay (ess-watch-block-limits-at-point))) ;;;_ + BLOCK MANIPULATION and EDITING (defun ess-watch-rename () "Rename the currently selected watch block." (interactive) (end-of-line) (unless (re-search-backward ess-watch-start-block nil t) (error "Can not find a watch block")) (let ((reg-name (concat ess-watch-start-block " *\\(\\S-*\\).*$")) name start end) ;; (reg-expr (concat "^" ess-watch-start-expression "\\s-*\\(.*\\)$")) ;; (reg-all (concat "\\(" reg-name "\\)\n\\(" reg-expr "\\)")) ;; (pos 0) wal name expr) (unless (re-search-forward reg-name (line-end-position) t) (error "Can not find the name substring in the current watch block ")) (setq name (match-string-no-properties 1)) (setq start (match-beginning 1)) (setq end (match-end 1)) (goto-char start) ;; TODO: highlight the name in R-watch here (setq name (read-string (concat "New name (" name "): ") nil nil name) ) (setq buffer-read-only nil) (delete-region start end) (insert name) (setq buffer-read-only t) (ess-watch--install-.ess_watch_expressions) (ess-watch-refresh-buffer-visibly (current-buffer)))) (defun ess-watch-edit-expression () "Edit in the minibuffer the R expression from the current watch block." (interactive) (end-of-line) (unless (re-search-backward ess-watch-start-block nil 1) (error "Can not find a watch block")) (let ((reg-expr (concat ess-watch-start-expression " *\\(.*\\)$")) expr start end) (unless (re-search-forward reg-expr nil t) (error "Can not find an expression string in the watch block")) (setq expr (match-string-no-properties 1)) (setq start (match-beginning 1)) (setq end (match-end 1)) (goto-char start) ;; TODO: highlight the name in R-watch here (setq expr (read-string "New expression: " expr nil expr) ) (setq buffer-read-only nil) (delete-region start end) (insert expr) (setq buffer-read-only t) (ess-watch--install-.ess_watch_expressions) (ess-watch-refresh-buffer-visibly (current-buffer)))) (defun ess-watch-add () "Ask for new R expression and append to the current list of watch expressions." (interactive) (let (nr expr name) (goto-char (point-max)) (setq nr (number-to-string (1+ (ess-watch-block-at-point)))) (setq name nr) ;; (setq name (read-string (concat "Name (" nr "):") nil nil nr )) ;;this one is quite annoying and not really needed than for logging (setq expr (read-string "New expression: " nil nil "\"Empty watch!\"")) (setq buffer-read-only nil) (insert (concat "\n" ess-watch-start-block " " name " -@\n" ess-watch-start-expression " " expr "\n")) (setq buffer-read-only t) (ess-watch--install-.ess_watch_expressions))) (defun ess-watch-insert () "Ask for new R expression and name and insert it in front of current watch block." (interactive) (let (nr expr name) (setq nr (number-to-string (ess-watch-block-at-point))) (setq name nr) ;; (setq name (read-string (concat "Name (" nr "):") nil nil nr )) (setq expr (read-string "New expression: " nil nil "\"Empty watch!\"")) (re-search-backward ess-watch-start-block nil 1) ;;point-min if not found (setq buffer-read-only nil) (insert (concat "\n" ess-watch-start-block " " name " -@\n" ess-watch-start-expression " " expr "\n")) (setq buffer-read-only t) (ess-watch--install-.ess_watch_expressions))) (defun ess-watch-move-up () "Move the current block up." (interactive) (let ((nr (ess-watch-block-at-point)) wbl) (when (> nr 1) (setq buffer-read-only nil) (setq wbl (apply #'delete-and-extract-region (ess-watch-block-limits-at-point))) (re-search-backward ess-watch-start-block nil t 1) ;; current block was deleted, point is at the end of previous block (insert wbl) (ess-watch--install-.ess_watch_expressions) (setq buffer-read-only t)))) (defun ess-watch-move-down () "Move the current block down." (interactive) (let ((nr (ess-watch-block-at-point)) (nr-all (save-excursion (goto-char (point-max)) (ess-watch-block-at-point))) wbl) (when (< nr nr-all) (setq buffer-read-only nil) (setq wbl (apply #'delete-and-extract-region (ess-watch-block-limits-at-point))) (end-of-line) (when (re-search-forward ess-watch-start-block nil t 1) ;; current block was deleted, point is at the end of previous block or point-max (goto-char (match-beginning 0))) (insert wbl) (ess-watch--install-.ess_watch_expressions) (setq buffer-read-only t)))) (defun ess-watch-kill () "Kill the current block." (interactive) (setq buffer-read-only nil) (apply #'delete-region (ess-watch-block-limits-at-point)) (ess-watch--install-.ess_watch_expressions)) ;;;_ + Debug/Undebug at point (defun ess--dbg-get-signatures (method) "Get signatures for the method METHOD." (let ((tbuffer (get-buffer-create " *ess-command-output*")); initial space: disable-undo signatures) (save-excursion (ess-if-verbose-write (format "ess-get-signatures*(%s).. " method)) (ess-command (concat "showMethods(\"" method "\")\n") tbuffer) (message "%s" ess-local-process-name) (message "%s" ess-current-process-name) (ess-if-verbose-write " [ok] ..\n") (set-buffer tbuffer) (goto-char (point-min)) (if (not (re-search-forward "Function:" nil t)) (progn (ess-if-verbose-write "not seeing \"Function:\".. \n") (error (buffer-string)) ;; (error "Cannot trace method '%s' (Is it a primitive method which you have already traced?)" method) ) ;; (setq curr-point (point)) ;; (while (re-search-forward ", " nil t) ;replace all ", " with ":" for better readability in completion buffers?? ;; (replace-match ":")) ;; (goto-char curr-point) (while (re-search-forward "^.+$" nil t) (setq signatures (cons (match-string-no-properties 0) signatures)))) ; (kill-buffer tbuffer) ) signatures)) (defun ess-debug-flag-for-debugging () "Set the debugging flag on a function. Ask the user for a function and if it turns to be generic, ask for signature and trace it with browser tracer." (interactive) (ess-force-buffer-current "Process to use: ") (let* ((tbuffer (get-buffer-create " *ess-command-output*")) ;; output buffer name is hard-coded in ess-inf.el (pkg (ess-r-package-name)) (all-functions (ess-get-words-from-vector--foreground (if pkg (format ".ess_all_functions(c('%s'))\n" pkg) ".ess_all_functions()\n"))) (obj-at-point (ess-helpobjs-at-point--read-obj)) (default (and obj-at-point (let* ((reg (regexp-quote obj-at-point)) (matches (cl-loop for el in all-functions if (string-match reg el) collect el))) (car (sort matches (lambda (a b) (< (length a) (length b)))))))) (ufunc (ess-completing-read "Debug" all-functions nil nil nil nil (or default obj-at-point))) signature) ;; FIXME: Most of the following logic should be in R (if (ess-boolean-command (format "as.character(isGeneric('%s'))\n" ufunc)) ;; it's S4 generic: (save-excursion ;; ask for exact signature (setq signature (ess-completing-read (concat "Method for generic '" ufunc "'") (ess--dbg-get-signatures ufunc) ;signal an error if not found nil t nil nil "*default*")) (if (equal signature "*default*") ;;debug, the default ufunc (ess-command (format "trace('%s', tracer = browser)\n" ufunc) tbuffer) (ess-command (format "trace('%s', tracer = browser, signature = c('%s'))\n" ufunc signature) tbuffer)) (with-current-buffer tbuffer ;; give appropriate message or error (message "%s" (buffer-substring-no-properties (point-min) (point-max))))) ;;else, not an S4 generic (when (ess-boolean-command (format "as.character(.knownS3Generics['%s'])\n" ufunc)) ;; it's S3 generic: (setq all-functions (ess-get-words-from-vector (format "local({gens<-methods('%s');as.character(gens[attr(gens, 'info')$visible])})\n" ufunc))) (setq all-functions ;; cannot debug non-visible methods (delq nil (mapcar (lambda (el) (if (not (char-equal ?* (aref el (1- (length el))))) el)) all-functions))) (setq ufunc (ess-completing-read (format "Method for S3 generic '%s'" ufunc) (cons ufunc all-functions) nil t))) (ess-command (format ".ess_dbg_flag_for_debuging('%s')\n" ufunc))))) (defun ess-debug-unflag-for-debugging () "Prompt for the debugged/traced function or method and undebug/untrace it." (interactive) (let ((tbuffer (get-buffer-create " *ess-command-output*")); initial space: disable-undo\ (debugged (ess-get-words-from-vector (if nil ;; FIXME: was checking `ess-developer-packages` (format ".ess_dbg_getTracedAndDebugged(c('%s'))\n" (mapconcat 'identity ess-developer-packages "', '")) ".ess_dbg_getTracedAndDebugged()\n"))) out-message fun def-val) ;; (prin1 debugged) (if (eq (length debugged) 0) (setq out-message "No debugged or traced functions/methods found") (setq def-val (if (eq (length debugged) 1) (car debugged) "*ALL*")) (setq fun (ess-completing-read "Undebug" debugged nil t nil nil def-val)) (if (equal fun "*ALL*" ) (ess-command (concat ".ess_dbg_UndebugALL(c(\"" (mapconcat 'identity debugged "\", \"") "\"))\n") tbuffer) (ess-command (format ".ess_dbg_UntraceOrUndebug(\"%s\")\n" fun) tbuffer)) (with-current-buffer tbuffer (if (= (point-max) 1) ;; not reliable TODO: (setq out-message (format "Undebugged '%s' " fun)) (setq out-message (buffer-substring-no-properties (point-min) (point-max))) ;; untrace info or warning, or error occurred ))) (message "%s" out-message))) ;;;_ * Kludges and Fixes ;;; delete-char and delete-backward-car do not delete whole intangible text (defun ess--tracebug-delete-char (n &rest _) "When deleting an intangible char, delete the whole intangible region. Only do this when N is 1" (when (and (ess-derived-mode-p) (= n 1) (get-text-property (point) 'cursor-intangible)) (kill-region (point) (or (next-single-property-change (point) 'cursor-intangible) (point-max))) (indent-according-to-mode))) (advice-add 'delete-char :before-until #'ess--tracebug-delete-char) (defun ess--tracebug-delete-backward-char (n &rest _) "When deleting an intangible char, delete the whole intangible region. Only do this when called interactively and N is 1" (when (and (ess-derived-mode-p) (= n 1) (> (point) (point-min)) (get-text-property (1- (point)) 'cursor-intangible)) (kill-region (or (previous-single-property-change (point) 'cursor-intangible) (point-min)) (point)))) (advice-add 'delete-backward-char :before-until #'ess--tracebug-delete-backward-char) (provide 'ess-tracebug) ;;; ess-tracebug.el ends here ESS-24.01.1/lisp/ess-trns.el000066400000000000000000000223171455642170100153720ustar00rootroot00000000000000;;; ess-trns.el --- Support for manipulating S transcript files -*- lexical-binding: t; -*- ;; Copyright (C) 1989-2020 Free Software Foundation, Inc. ;; Author: David Smith ;; Maintainer: ESS-core ;; This file is part of GNU Emacs. ;;; License: ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see ;; ;;; Commentary: ;; Code for dealing with ESS transcripts. ;;; Code: ; Requires and autoloads (require 'ess-mode) (require 'ess-inf) (require 'comint) (declare-function ess-display-help-on-object "ess-help" (object &optional command)) ; ess-transcript-mode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; In this section: ;;;; ;;;; * The major mode ess-transcript-mode ;;;; * Commands for ess-transcript-mode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defcustom ess-transcript-mode-hook nil "Hook for customizing ESS transcript mode." :group 'ess-hooks :type 'hook) ;;*;; Major mode definition (defvar ess-transcript-mode-map (let ((map (make-sparse-keymap))) (define-key map "\C-c\C-s" #'ess-switch-process) (define-key map "\C-c\C-r" #'ess-eval-region) (define-key map "\C-c\M-r" #'ess-eval-region-and-go) (define-key map "\C-c\C-k" #'ess-force-buffer-current) (define-key map "\C-c\C-q" #'ess-quit) (define-key map "\C-c\C-j" #'ess-transcript-send-command) (define-key map "\C-c\M-j" #'ess-transcript-send-command-and-move) (define-key map "\M-\C-a" #'ess-goto-end-of-function-or-para) (define-key map "\M-\C-e" #'ess-goto-end-of-function-or-para) (define-key map "\C-c\C-y" #'ess-switch-to-ESS) (define-key map "\C-c\C-z" #'ess-switch-to-end-of-ESS) (define-key map "\C-c\C-v" #'ess-display-help-on-object) (define-key map "\C-c\C-d" #'ess-dump-object-into-edit-buffer) (define-key map "\C-a" #'comint-bol) (define-key map "\M-\t" #'comint-replace-by-expanded-filename) (define-key map "\M-?" #'comint-dynamic-list-completions) (define-key map "\C-c\C-k" #'ess-request-a-process) (define-key map "{" #'skeleton-pair-insert-maybe) (define-key map "}" #'skeleton-pair-insert-maybe) (define-key map "\e\C-h" #'ess-mark-function-or-para) (define-key map "\e\C-q" #'ess-indent-exp) (define-key map "\t" #'ess-indent-command) (define-key map "\C-c\C-p" #'comint-previous-prompt) (define-key map "\C-c\C-n" #'comint-next-prompt) (define-key map "\r" #'ess-transcript-send-command-and-move) (define-key map "\M-\r" #'ess-transcript-send-command) (define-key map "\C-c\r" #'ess-transcript-copy-command) (define-key map "\C-c\C-w" #'ess-transcript-DO-clean-region) (define-key map "\C-c\M-c" #'ess-transcript-clean-buffer) map) "Keymap for `ess-transcript-mode'.") (easy-menu-define ess-transcript-mode-menu ess-transcript-mode-map "Menu for use in S transcript mode." '("ESS-trans" ["Describe" describe-mode t] ["About" (ess-goto-info "Transcript Mode") t] ["Send bug report" ess-submit-bug-report t] "------" ["Mark cmd group" mark-paragraph t] ["Previous prompt" comint-previous-prompt t] ["Next prompt" comint-next-prompt t] "------" ["Send and move" ess-transcript-send-command-and-move t] ["Copy command" ess-transcript-copy-command t] ["Send command" ess-transcript-send-command t] ["Clean Region" ess-transcript-DO-clean-region t] ["Clean Whole Buffer" ess-transcript-clean-buffer t] ["Switch S process" ess-switch-process t] )) ;;;###autoload (define-derived-mode ess-transcript-mode ess-mode "ESS Transcript" "Major mode for transcript files. Type \\[ess-transcript-send-command] to send a command in the transcript to the current inferior process. \\[ess-transcript-copy-command] copies the command but does not execute it, allowing you to edit it in the process buffer first. Type \\[ess-transcript-clean-region] to delete all outputs and prompts in the region, leaving only the commands." :group 'ess (setq buffer-read-only t ess-local-process-name nil mode-line-process '(" [" ess-local-process-name "]")) ;; TODO: Set this more normally in various major modes (unless inferior-ess-prompt ;; For S languages it is set in custom-alist (setq inferior-ess-prompt ;; Do not anchor to bol with `^' (concat "\\(" inferior-ess-primary-prompt "\\|" inferior-ess-secondary-prompt "\\)"))) (setq-local paragraph-start (concat "^" inferior-ess-prompt "\\|^\^L")) (setq-local paragraph-separate "^\^L") (setq-local comint-use-prompt-regexp t) (setq-local comint-prompt-regexp (concat "^" inferior-ess-prompt)) (setq font-lock-defaults '(ess-build-font-lock-keywords nil nil ((?\. . "w") (?\_ . "w") (?' . "."))))) ;;*;; Commands used in S transcript mode (defun ess-transcript-send-command () "Send the command at point in the transcript to the ESS process. The line should begin with a prompt. The ESS process buffer is displayed if it is not already." (interactive) (let* ((proc (or ess-local-process-name (ess-request-a-process "Evaluate into which process? " t))) (ess-buf (ess-get-process-buffer proc))) (setq ess-local-process-name proc) (if (get-buffer-window ess-buf) nil (display-buffer ess-buf t)) (let ((input (inferior-ess-get-old-input))) (with-current-buffer ess-buf (goto-char (point-max)) (ess-eval-linewise input))))) (defun ess-transcript-send-command-and-move () "Send the command on this line, and move point to the next command." (interactive) (let* ((proc (or ess-local-process-name (ess-request-a-process "Evaluate into which process? " t))) (ess-buf (ess-get-process-buffer proc))) (setq ess-local-process-name proc) (if (get-buffer-window ess-buf) nil (display-buffer ess-buf t)) (let ((input (inferior-ess-get-old-input))) (with-current-buffer ess-buf (goto-char (point-max)) (ess-eval-linewise input nil nil nil 1)))) (comint-next-prompt 1)) (defun ess-transcript-copy-command () "Copy the command at point to the command line of the ESS process." (interactive) (let* ((proc (or ess-local-process-name (ess-request-a-process "Evaluate into which process? " t))) (ess-buf (process-buffer (get-process proc))) (input (inferior-ess-get-old-input))) (setq ess-local-process-name proc) (if (get-buffer-window ess-buf) nil (display-buffer ess-buf t)) (with-current-buffer ess-buf (goto-char (point-max)) (insert input))) (ess-switch-to-end-of-ESS)) (defun ess-transcript-clean-region (beg end even-if-read-only) "Strip the transcript in the region, leaving only (R/S/Lsp/..) commands. Deletes any lines not beginning with a prompt, and then removes the prompt from those lines that remain. Prefix argument means to clean even if the buffer is \\[read-only]." (interactive "r\nP") (unless inferior-ess-prompt (error "Cannot clean ESS transcript region in this mode! That only works in ess-transcript-mode or inferior-ess-mode ('*R*' etc)." ;; Maybe call ess-clean-region-in-new-transcript ?")) )) (let ((do-toggle (and buffer-read-only even-if-read-only)) (ess-prompt-rx (if inferior-ess-secondary-prompt (concat "^\\(\\(" inferior-ess-prompt "\\)\\|\\(" inferior-ess-secondary-prompt "\\)\\)") (concat "^" inferior-ess-prompt)))) (save-excursion (if do-toggle (setq buffer-read-only nil)) (save-restriction (deactivate-mark) (narrow-to-region beg end) (goto-char (point-min)) (delete-non-matching-lines ess-prompt-rx) (goto-char (point-min)) ;; (replace-regexp * * ) : (while (re-search-forward ess-prompt-rx nil t) (replace-match "" nil nil))) (if do-toggle (setq buffer-read-only t))))) (defun ess-transcript-DO-clean-region (beg end) "Clean the current via \\[ess-transcript-clean-region] even if the buffer is read-only." (interactive "r") (ess-transcript-clean-region beg end 'In-ANY-case)) (defun ess-transcript-clean-buffer () "Cleanup the whole buffer. Use point-min/max to obey `narrow-to-region'." (interactive) (ess-transcript-clean-region (point-min) (point-max) 'In-ANY-case)) (provide 'ess-trns) ;;; ess-trns.el ends here ESS-24.01.1/lisp/ess-utils.el000066400000000000000000001312631455642170100155450ustar00rootroot00000000000000;;; ess-utils.el --- General Emacs utility functions used by ESS -*- lexical-binding: t; -*- ;; Copyright (C) 1998-2022 Free Software Foundation, Inc. ;; Author: Martin Maechler ;; Created: 9 Sept 1998 ;; Maintainer: ESS-core ;; This file is part of GNU Emacs. ;;; License: ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see ;; ;;; Commentary: ;; Various utilities for ESS. ;;; Code: (require 'cl-lib) (require 'comint) (require 'project) (eval-when-compile (require 'tramp)) ;; The only ESS file this file should depend on is ess-custom.el (require 'ess-custom) (defvar ac-modes) (declare-function ess-eval-linewise "ess-inf" (text &optional invisibly eob even-empty wait-last-prompt sleep-sec wait-sec)) (declare-function color-lighten-name "color" (name percent)) (declare-function tramp-dissect-file-name "tramp" (name &optional nodefault)) ;; The following declares can be removed once we drop Emacs 25 (declare-function tramp-file-name-method "tramp") (declare-function tramp-file-name-user "tramp") (declare-function tramp-file-name-host "tramp") (declare-function tramp-file-name-localname "tramp") (declare-function tramp-file-name-hop "tramp") ;;*;; elisp tools (defun ess-next-code-line (&optional arg skip-to-eob) "Move ARG lines of code forward (backward if ARG is negative). If `ess-eval-empty' is non-nil, skip past all empty and comment lines. ARG is 1 by default. If ARG is 0 only comments are skipped forward. Don't skip the last empty and comment lines in the buffer unless SKIP-TO-EOB is non-nil. On success, return 0. Otherwise go as far as possible and return -1." (interactive "p") (if (or ess-eval-empty (and (fboundp 'ess-roxy-entry-p) (ess-roxy-entry-p))) (forward-line arg) (setq arg (or arg 1)) (beginning-of-line) (let ((pos (point)) (inc (if (>= arg 0) 1 -1)) (cnt (if (= arg 0) 1 arg)) (out 0)) ;; when orig-arg == 0, we skip only comments (while (and (/= cnt 0) (= out 0)) (unless (= arg 0) (setq out (forward-line inc))) ; out==0 means success (comment-beginning) (beginning-of-line) (forward-comment (* inc (buffer-size))) ;; as suggested in info file (if (or skip-to-eob (not (looking-at ess-no-skip-regexp))) ;; don't go to eob or whatever (setq cnt (- cnt inc)) (goto-char pos) (setq cnt 0) (forward-line inc)) ;; stop at next empty line (setq pos (point))) (goto-char pos) out))) (defun ess-goto-line (line) "Go to LINE in the widened buffer." (save-restriction (widen) (goto-char (point-min)) (forward-line (1- line)))) (defun ess-skip-thing (thing) "Leave point at the end of THING. THING can be \\='function, \\='paragraph, or \\='line." (cond ((eql thing 'line) (goto-char (line-end-position))) ((eql thing 'paragraph) (forward-paragraph)) ((eql thing 'function) (end-of-defun) (skip-chars-backward " \t\n")))) (defun ess-search-except (regexp &optional except backward) "Search for a REGEXP and store as match 1. Optionally ignore strings that match EXCEPT. If BACKWARD is non-nil, search backward." (let ((continue t) (exit nil)) (while continue (if (or (and backward (search-backward-regexp regexp nil t)) (and (not backward) (search-forward-regexp regexp nil t))) (progn (setq exit (match-string 1)) (setq continue (and except (string-match except exit))) (if continue (setq exit nil))) ;;else (setq continue nil))) exit)) (defun ess-save-and-set-local-variables () "If buffer was modified, save file and set Local Variables if defined. Return t if buffer was modified, nil otherwise." (let ((ess-temp-return-value (buffer-modified-p))) (save-buffer) (hack-local-variables) ess-temp-return-value)) (defun ess-get-file-or-buffer (file-or-buffer) "Return FILE-OR-BUFFER if it is a buffer. Otherwise return the buffer associated with the file which must be qualified by it's path; if the buffer does not exist, return nil." (declare (side-effect-free t) (obsolete nil "ESS 19.04")) (if (bufferp file-or-buffer) file-or-buffer (find-buffer-visiting file-or-buffer))) (defun ess-file-content (file) "Return the content of FILE as string." (if (file-exists-p file) (with-temp-buffer (insert-file-contents-literally file) (buffer-string)) (error "File '%s' does not exist" file))) (defun ess-uniq (list predicate) "Uniquify LIST, stably, deleting elements using PREDICATE. Return the list with subsequent duplicate items removed by side effects. PREDICATE is called with an element of LIST and a list of elements from LIST, and should return the list of elements with occurrences of the element removed. This function will work even if LIST is unsorted. See also `delete-dups'." (declare (obsolete 'delete-dups "ESS 19.04")) (let ((list list)) (while list (setq list (setcdr list (funcall predicate (car list) (cdr list)))))) list) (define-obsolete-function-alias 'ess-uniq-list #'delete-dups "ESS 19.04") (defalias 'ess-flatten-list ;; `flatten-tree' is a function in Emacs 27 (if (fboundp 'flatten-tree) 'flatten-tree (lambda (list) "Take the arguments and flatten them into one long LIST. Drops `nil' entries." ;; Taken from lpr.el ;; `lpr-flatten-list' is defined here (copied from "message.el" and ;; enhanced to handle dotted pairs as well) until we can get some ;; sensible autoloads, or `flatten-list' gets put somewhere decent. (ess-flatten-list-1 list)))) (defun ess-flatten-list-1 (list) "Internal helper for `ess-flatten-list', which see for LIST." (cond ((null list) (list)) ((consp list) (append (ess-flatten-list-1 (car list)) (ess-flatten-list-1 (cdr list)))) (t (list list)))) (define-obsolete-function-alias 'ess-delete-blank-lines #'delete-blank-lines "ESS 19.04") (define-obsolete-function-alias 'ess-line-to-list-of-words #'split-string "ESS 19.04") (defmacro ess--exit-protect (body &rest exit) "Run EXIT when BODY exits early. Unlike `unwind-protect', the unwind forms only run in case of early exits. Unlike `condition-case', they run inconditionally, no matter the reason for exiting early (e.g. error or quit)." (declare (indent 1) (debug (form &rest form))) `(let ((--early-exit t)) (unwind-protect (prog1 ,body (setq --early-exit nil)) (when --early-exit ,@exit)))) ;;*;; System (defun ess-revert-wisely () "Revert from disk if file and buffer last modification times are different." (interactive) ;; whether or not a revert is needed, force load local variables ;; for example, suppose that you change the local variables and then ;; save the file, a revert is unneeded, but a force load is (hack-local-variables) (unless (verify-visited-file-modtime (current-buffer)) (progn (let ((ess-temp-store-point (point))) (revert-buffer t t) (goto-char ess-temp-store-point)) t))) (define-obsolete-function-alias 'ess-find-exec #'ess-find-exec-completions "ESS 19.04") (defun ess-find-exec-completions (root) "Given the ROOT of an executable file name, find all possible completions. Search for the executables in the variable `exec-path'." (let (executables) (dolist (dir exec-path) (when (and (> (length dir) 0) (file-accessible-directory-p dir)) ;; the first test above excludes "" from exec-path, which can be ;; problematic with Tramp. (dolist (f (file-name-all-completions root dir)) (setq f (expand-file-name f dir)) (when (and (file-executable-p f) (not (backup-file-name-p f)) (not (file-directory-p f))) (push f executables))))) executables)) (defun ess-drop-non-directories (file-strings) "Drop all entries in FILE-STRINGS that do not \"look like\" directories." (ess-flatten-list (mapcar #'file-name-directory file-strings))) (defun ess--parent-dir (path n) "Return Nth parent of PATH." (let ((opath path)) (while (and path (> n 0)) (setq path (file-name-directory (directory-file-name opath))) (if (equal path opath) (setq path nil) (setq opath path n (1- n)))) path)) ;;*;; Interaction with inferiors (defmacro ess-when-new-input (time-var &rest body) "BODY is evaluate only if the value of process variable TIME-VAR is bigger than the time of the last user input (stored in `last-eval' process variable). TIME-VAR is the name of the process variable which holds the access time. See the code for `ess-synchronize-dirs' and `ess-cache-search-list'. Returns nil when no current process, or process is busy, or time-var > last-eval. Otherwise, execute BODY and return the last value. If BODY is executed, set process variable TIME-VAR to (current-time). Variable *proc* is bound to the current process during the evaluation of BODY. Should be used in `ess-idle-timer-functions' which call the process to avoid excessive requests." (declare (indent 1) (debug t)) `(with-ess-process-buffer 'no-error (let ((le (process-get *proc* 'last-eval)) (tv (process-get *proc* ',time-var))) (when (and (or (null tv) (null le) (time-less-p tv le)) (not (process-get *proc* 'busy))) (let ((out (progn ,@body))) (process-put *proc* ',time-var (current-time)) out))))) (defmacro with-ess-process-buffer (no-error &rest body) "Execute BODY in the process buffer of `ess-current-process-name'. If NO-ERROR is t don't trigger error when there is not current process. Symbol *proc* is bound to the current process during the evaluation of BODY." (declare (indent 1) (debug t)) `(let ((*proc* (and ess-local-process-name (get-process ess-local-process-name)))) (if *proc* (with-current-buffer (process-buffer *proc*) ,@body) (unless ,no-error (error "No current ESS process"))))) ;;*;; Emacs Integration (defun ess-derived-mode-p () "Non-nil if the current major mode is an ESS major mode." (or (derived-mode-p 'ess-mode) (derived-mode-p 'ess-julia-mode))) (defun ess--generate-eval-visibly-submenu (_menu) '(["yes" (lambda () (interactive) (setq ess-eval-visibly t)) :style radio :enable t :selected (eq ess-eval-visibly t)] ["nowait" (lambda () (interactive) (setq ess-eval-visibly 'nowait)) :style radio :enable t :selected (eq ess-eval-visibly 'nowait) ] ["no" (lambda () (interactive) (setq ess-eval-visibly nil)) :style radio :enable t :selected (eq ess-eval-visibly nil) ])) ;; Font Lock (defun ess--fl-keywords-values () "Return a cons (STANDARD-VALUE . CUSTOM-VALUE) of `ess-font-lock-keywords'." (let ((sym ess-font-lock-keywords)) (if (and (symbolp sym) (custom-variable-p sym)) (cons (eval (car (get sym 'standard-value)) t) (symbol-value sym)) (error "`ess-font-lock-keywords' must be a symbol of a custom variable")))) (defun ess--extract-fl-keywords () (let ((values (ess--fl-keywords-values))) (mapcar (lambda (kv) (let ((cust-kv (assoc (car kv) (cdr values)))) (when cust-kv (setcdr kv (cdr cust-kv)))) kv) (copy-alist (car values))))) (defun ess-build-font-lock-keywords () "Retrieve `font-lock-keywords' from ess-[dialect]-font-lock-keywords. Merge the customized values of that variable on top of the standard values and return the new list. For this to work, `ess-font-lock-keywords' should be a name of the ess-[dialect]-font-lock-keywords variable." (delq nil (mapcar (lambda (c) (when (cdr c) (symbol-value (car c)))) (ess--extract-fl-keywords)))) (defun ess-font-lock-toggle-keyword (keyword) "Toggle KEYWORD font-lock." (interactive (list (intern (ess-completing-read "Keyword to toggle" (mapcar (lambda (el) (symbol-name (car el))) (car (ess--fl-keywords-values))) nil t)))) (let* ((values (ess--fl-keywords-values)) (kwd (cond ;; already in custom values ((assoc keyword (cdr values))) ;; if keyword is not already in custom values (can happen if ;; we add new keywords but the user has the old value saved in ;; .emacs-custom.el) ((let ((kwd (assoc keyword (car values))) (sym ess-font-lock-keywords)) (when kwd (set sym (cons kwd (symbol-value sym))) kwd))) (t (error "Invalid keyword %s" keyword))))) (setcdr kwd (not (cdr kwd))) (let ((mode major-mode) (dialect ess-dialect)) ;; refresh font-lock defaults in all relevant buffers (mapc (lambda (b) (with-current-buffer b (when (and (eq major-mode mode) (eq ess-dialect dialect)) (font-lock-refresh-defaults)))) (buffer-list))))) (defun ess--generate-font-lock-submenu (_menu) "Generate ESS font-lock submenu." (append (mapcar (lambda (el) `[,(symbol-name (car el)) (lambda () (interactive) (ess-font-lock-toggle-keyword ',(car el))) :style toggle :enable t :selected ,(cdr el)]) (ess--extract-fl-keywords)) (list "-----" ["Save to custom" (lambda () (interactive) (customize-save-variable ess-font-lock-keywords (ess--extract-fl-keywords))) t]))) (declare-function untrace-function "trace" ()) (defvar ess--is-tracing nil) ;;;###autoload (define-minor-mode ess-elisp-trace-mode "Toggle tracing of ess-prefixed functions. Tracing is useful for debugging background ESS behaviour. When enabled, all functions prefixed in `ess-' and `inferior-ess' are instrumented with `trace-function'. Tracing is turned off by calling `untrace-function' on these functions." :global t :group 'ess (let ((fns (append (all-completions "ess-" obarray) (all-completions "inferior-ess-" obarray) (list "update-ess-process-name-list" "forward-ess-r-expr" "forward-ess-r-sexp" "backward-ess-r-expr" "backward-ess-r-sexp" "company-ess-julia-objects" "run-ess-r" "run-ess-r-newest"))) (do (symbol-function (if ess-elisp-trace-mode #'untrace-function #'trace-function)))) (dolist (fn fns) (when (symbol-function (intern fn)) (funcall do (intern fn)))))) ;;*;; External modes ;; Define these here for the byte compiler since ido dynamically ;; let-binds them: (defvar ido-choice-list) (defvar ido-context-switch-command) (defvar ido-directory-too-big) (defvar ido-directory-nonreadable) (defvar ido-current-directory) (defvar ido-enable-flex-matching) (declare-function ido-choose-completion-string "ido") (declare-function ido-minibuffer-setup "ido") (declare-function ido-read-internal "ido" (item prompt hist &optional default require-match initial)) (defun ess-completing-read (prompt collection &optional predicate require-match initial-input hist def) "Read a string in the minibuffer, with completion. Use `ido-completing-read' if IDO interface is present, or fall back on classical `completing-read' otherwise. Meaning of PROMPT, COLLECTION, PREDICATE, REQUIRE-MATCH, INITIAL-INPUT, HIST, and DEF is as in `completing-read'. PROMPT is automatically suffixed with ': ' and (default %s) when needed. If HIST is nil use `ess--completing-hist' as history. See also `ess-use-ido'." (let ((use-ido (and ess-use-ido (require 'ido nil t)))) (setq hist (or hist 'ess--completing-hist)) (when (and def (not use-ido)) ;; ido places in front and highlights the default (setq prompt (format "%s(default %s)" prompt def))) (setq prompt (concat prompt ": ")) (if use-ido (let ((reset-ido (and use-ido (not ido-mode))) ;people not using ido but having it) (ido-current-directory nil) (ido-directory-nonreadable nil) (ido-directory-too-big nil) (ido-context-switch-command 'ignore) (ido-enable-flex-matching ess-ido-flex-matching) ;it's fast and useful, may be get into options (ido-choice-list (copy-sequence collection)) ;ido removes the match (reported) sel) (unwind-protect (progn (add-hook 'minibuffer-setup-hook #'ido-minibuffer-setup) (add-hook 'choose-completion-string-functions #'ido-choose-completion-string) (setq sel (ido-read-internal 'list prompt hist def require-match initial-input)) (when hist ;; ido does not push into hist the whole match if C-SPC or RET is used (reported) (unless (string= sel (car (symbol-value hist))) (set hist (cons sel (symbol-value hist)))))) (when reset-ido (remove-hook 'minibuffer-setup-hook #'ido-minibuffer-setup) (remove-hook 'choose-completion-string-functions #'ido-choose-completion-string))) sel) ;; else usual completion (completing-read prompt collection predicate require-match initial-input hist def)))) (defun ess--setup-auto-complete (sources &optional inferior) "Setup auto-complete depending on user settings. SOURCES gets added to `ac-sources', INFERIOR should be t for inferior buffers." ;; auto-complete (when (and (boundp 'ac-sources) (if inferior (eq ess-use-auto-complete t) ess-use-auto-complete)) (add-to-list 'ac-modes major-mode) ;; files should be in front; ugly, but needed (setq ac-sources (delq 'ac-source-filename ac-sources)) (mapc (lambda (el) (add-to-list 'ac-sources el)) sources) (add-to-list 'ac-sources 'ac-source-filename))) (defun ess--setup-company (sources &optional inferior) "Setup company depending on user settings. SOURCES gets added to `company-backends', and when t, INFERIOR specifies inferior buffers." ;; company (when (and (boundp 'company-backends) (if inferior (eq ess-use-company t) ess-use-company)) (setq-local company-backends (cl-copy-list (append sources company-backends))) (delq 'company-capf company-backends))) (defun ess--setup-eldoc (fun) "Setup support for eldoc. FUN is the function to return data for eldoc." (when ess-use-eldoc (if (not (boundp 'eldoc-documentation-functions)) ;; older versions of Eldoc included in Emacs 27 and previous (add-function :before-until (local 'eldoc-documentation-function) fun) ;; new eldoc, in Emacs 28+ (add-hook 'eldoc-documentation-functions fun nil t) ;; Eldoc is on GNU ELPA so you can have new eldoc + Emacs 27.1 ;; or older, see bug#1130 and Emacs bug # 47388 for why we have ;; to do this (when (and (fboundp 'eldoc-documentation-default) (function-equal #'ignore eldoc-documentation-function)) (setq-local eldoc-documentation-function #'eldoc-documentation-default))))) (defmacro ess--execute-electric-command (map &optional prompt wait exit-form &rest args) "Execute keys defined in MAP till a key is pressed which is not in MAP. Single-key input commands are those that once executed do not require the prefix command for subsequent invocation. Return the value of the lastly executed command. PROMPT is passed to `read-event'. If WAIT is t, wait for next input and ignore the keystroke which triggered the command. Each command in map should accept one at least one argument, the most recent event (as read by `read-event'). ARGS are the supplementary arguments passed to the commands. EXIT-FORM should be supplied for a more refined control of the read-even loop. The loop is exited when EXIT-FORM evaluates to t. See examples in the tracebug code." ;;VS[09-06-2013]: check: it seems that set-temporary-overlay-map is designed ;;for this type of things; see also repeat.el package. `(let* ((ev last-command-event) (command (lookup-key ,map (vector ev))) out exit ) (if (not (or ,wait command)) (message "%s is undefined" (key-description (this-command-keys))) (unless ,wait (setq out (and command (funcall command ev ,@args)))) (while (and (not exit) (setq command (lookup-key ,map (vector (setq ev (read-event ,prompt)))))) (setq out (funcall command ev ,@args)) (sleep-for .01) (setq exit ,exit-form)) (unless exit ;; push only if an event triggered the exit (push ev unread-command-events)) out))) (cl-defgeneric ess-build-tags-command () "Command passed to generate tags. If nil, `ess-build-tags-for-directory' uses the mode's imenu expression. Otherwise, it should be a string with two %s formats: one for directory and another for the output file." nil) ;;*;; Emacs itself (defun ess-yank-cleaned-commands () "Yank and strip the code, leaving only (R/S/Lsp/..) commands. Deletes any lines not beginning with a prompt, and then removes the prompt from those lines that remain. Invoke this command with \\[universal-argument] \\[universal-argument] \\\\[yank]." (setq yank-window-start (window-start)) (let ((beg (point))) (push-mark beg) (setq this-command t) (insert-for-yank (current-kill 0)) (when (and (require 'ess-trns) (fboundp 'ess-transcript-clean-region)) (ess-transcript-clean-region beg (point) nil)) (if (eq (point) beg) (message "No commands found")) (if (eq this-command t) (setq this-command 'yank)))) (defun ess-yank (&optional arg) "Variant of `yank' that optionally extracts commands from transcripts. When called with double prefix ARG (\\[universal-argument] \\[universal-argument]), calls `ess-transcript-clean-region' before yanking. See `ess-yank-cleaned-commands'." (interactive "*P") (if (equal '(16) arg) (ess-yank-cleaned-commands) (let* ((remapped (command-remapping 'yank (point))) (command (cond ((eq remapped 'ess-yank) 'yank) ((null remapped) 'yank) (t remapped)))) (funcall command arg)))) (put 'ess-yank 'delete-selection 'yank) (defun ess-build-tags-for-directory (dir tagfile) "Ask for directory and tag file and build tags for current dialect. If the current language defines `ess-build-tags-command' use it and ask the subprocess to build the tags. Otherwise use imenu regexp and call find .. | etags .. in a shell command. You must have `find' and `etags' programs installed. Use M-. to navigate to a tag. \\[visit-tags-table] to append/replace the currently used tag table. If prefix is given, force tag generation based on imenu. Might be useful when different language files are also present in the directory (.cpp, .c etc)." (interactive "DDirectory to tag: GTags file (default TAGS): ") (when (or (eq (length (file-name-nondirectory tagfile)) 0) (file-directory-p tagfile)) (setq tagfile (concat (file-name-as-directory tagfile) "TAGS"))) ;; Emacs find-tags doesn't play well with remote TAG files :( (when (file-remote-p tagfile) (require 'tramp) (setq tagfile (with-parsed-tramp-file-name tagfile foo foo-localname))) (when (file-remote-p dir) (require 'tramp) (setq dir (with-parsed-tramp-file-name dir foo foo-localname))) (if (and (ess-build-tags-command) (null current-prefix-arg)) (ess-eval-linewise (format (ess-build-tags-command) dir tagfile)) ;; else generate from imenu (unless imenu-generic-expression (error "No ess-tag-command found, and no imenu-generic-expression defined")) (let* ((find-cmd (format "find %s -type f -size 1M \\( -regex \".*\\.\\(cpp\\|jl\\|[RsrSch]\\(nw\\)?\\)$\" \\)" dir)) (regs (delq nil (mapcar (lambda (l) (if (string-match "'" (cadr l)) nil ;; remove for time being (format "/%s/\\%d/" (replace-regexp-in-string "/" "\\/" (nth 1 l) t) (nth 2 l)))) imenu-generic-expression))) (tags-cmd (format "etags -o %s --regex='%s' -" tagfile (mapconcat #'identity regs "' --regex='")))) (message "Building tags: %s" tagfile) (when (= 0 (shell-command (format "%s | %s" find-cmd tags-cmd))) (message "Building tags .. ok!"))))) ;;*;; UI (defvar ess-current-region-overlay (let ((overlay (make-overlay (point) (point)))) (overlay-put overlay 'face 'highlight) overlay) "The overlay for highlighting currently evaluated region or line.") (defun ess-blink-region (start end) "Blink from START to END depending on option `ess-blink-region'." (when ess-blink-region (move-overlay ess-current-region-overlay start end) (run-with-timer ess-blink-delay nil (lambda () (delete-overlay ess-current-region-overlay))))) (defun ess-deactivate-mark () "Deactivate the mark, if active. If `evil-mode' is on, switch to `evil-normal-state'." (if (and (bound-and-true-p evil-mode) (fboundp 'evil-visual-state-p) (evil-visual-state-p)) (when (fboundp 'evil-normal-state) (evil-normal-state)) (when mark-active (deactivate-mark)))) ;; SJE: 2009-01-30 -- this contribution from ;; Erik Iverson (defun ess-tooltip-show-at-point (text xo yo) "Show a tooltip displaying TEXT at (around) point. XO and YO are x- and y-offsets for the toolbar from point." (let ( (fx (frame-parameter nil 'left)) (fy (frame-parameter nil 'top)) (fw (frame-pixel-width)) (fh (frame-pixel-height)) frame-left frame-top my-x-offset my-y-offset) ;; The following comment was found before code looking much like that ;; of frame-left and frame-top below in the file ;; tooltip-help.el. I include it here for acknowledgment, and I did observe ;; the same behavior with the Emacs window maximized under Windows XP. ;; -----original comment-------- ;; handles the case where (frame-parameter nil 'top) or ;; (frame-parameter nil 'left) return something like (+ -4). ;; This was the case where e.g. Emacs window is maximized, at ;; least on Windows XP. The handling code is "shamelessly ;; stolen" from cedet/speedbar/dframe.el ;; (contributed by Andrey Grigoriev) (setq frame-left (if (not (consp fx)) fx (if (eq (car fx) '-) (- (display-pixel-width) (car (cdr fx)) fw) (car (cdr fx))))) (setq frame-top (if (not (consp fy)) fy (if (eq (car fy) '-) (- (display-pixel-height) (car (cdr fy)) fh) (car (cdr fy))))) ;; calculate the offset from point, use xo and yo to adjust to preference (setq my-x-offset (+ (car(window-inside-pixel-edges)) (car(posn-x-y (posn-at-point))) frame-left xo)) (setq my-y-offset (+ (cadr(window-inside-pixel-edges)) (cdr(posn-x-y (posn-at-point))) frame-top yo)) (let ((tooltip-frame-parameters (cons (cons 'top my-y-offset) (cons (cons 'left my-x-offset) tooltip-frame-parameters)))) (tooltip-show text)))) (defun ess-select-frame-set-input-focus (frame) "Select FRAME, raise it, and set input focus, if possible. Copied almost verbatim from gnus-utils.el (but with test for mac added)." ;; The function `select-frame-set-input-focus' won't set ;; the input focus under Emacs 21.2 and X window system. ;;((fboundp 'select-frame-set-input-focus) ;; (defalias 'gnus-select-frame-set-input-focus ;; 'select-frame-set-input-focus) ;; (select-frame-set-input-focus frame)) (raise-frame frame) (select-frame frame) (cond ((and (memq window-system '(x mac)) (fboundp 'x-focus-frame)) (x-focus-frame frame)) ((and (eq window-system 'w32) ;; silence byte compiler warnings about w32-fns (fboundp 'w32-focus-frame)) (w32-focus-frame frame))) (when focus-follows-mouse (set-mouse-position frame (1- (frame-width frame)) 0))) (define-obsolete-function-alias 'ess-do-auto-fill #'do-auto-fill "ESS 19.04") ;;*;; Syntax (defun ess-containing-sexp-position () "Return the `cadr' of `syntax-ppss'." (cadr (syntax-ppss))) (defun ess-code-end-position () "Like (line-end-position) but stops at comments." (save-excursion (goto-char (1+ (line-end-position))) (forward-comment -1) (point))) ;; FIXME: The following function pattern stuff is specific to R but is ;; used throughout ESS (defvar ess-r-set-function-start ;; [MGAR].. <=> {setMethod(), set[Group]Generic(), setAs(), setReplaceMethod()} ;; see also set-S4-exp in ess-r-function-pattern below "^set[MGAR][GMa-z]+\\s-?(") (defvar ess-function-pattern nil ; in R set to ess-r-function-pattern "Regexp to match the beginning of a function in S buffers.") (defvar ess-r-symbol-pattern "\\(\\sw\\|\\s_\\)" "The regular expression for matching an R symbol.") (defvar ess-r-name-pattern (concat "\\(" ess-r-symbol-pattern "+\\|\\(`\\).+`\\)") "The regular expression for matching a R name.") (defvar ess--r-s-function-pattern (let* ((Q "\\s\"") ; quote (Sym-0 "\\(\\sw\\|\\s_\\)") ; symbol (Symb (concat Sym-0 "+")) (xSymb "[^ \t\n\"']+") ;; (concat "\\[?\\[?" Sym-0 "*")); symbol / [ / [[ / [symbol / [[symbol ;; FIXME: allow '%foo%' but only when quoted; don't allow [_0-9] at beg. (space "\\(\\s-\\|\n\\)*") ; white space (part-1 (concat "\\(" ;;--------outer Either------- "\\(\\(" ; EITHER Q xSymb Q ; any function name between quotes "\\)\\|\\(" Symb ; (beginning of name) + ess-r-symbol-pattern "\\)\\)")) ; END EITHER OR (set-S4-exp (concat "^set\\(As\\|Method\\|Generic\\|GroupGeneric\\|ReplaceMethod\\)(" ; S4 ... Q xSymb Q "," space ;; and now often `` signature(......), : '' ".*" ;; <<< FIXME ??? )) (part-2 (concat "\\|" ;;--------outer Or --------- set-S4-exp "\\)" ;;--------end outer Either/Or------- "\\(" space "\\s<.*\\s>\\)*" ; whitespace, comment ;; FIXME: in principle we should skip 'definition *= *' here space "function\\s-*(" ; whitespace, function keyword, parenthesis ))) `(,part-1 ,part-2)) "Partial regex for matching functions. Placeholder for use in constructing `ess-r-function-pattern' and `ess-s-function-pattern'.") (defvar ess-r-function-pattern (concat (car ess--r-s-function-pattern) "\\s-*\\(<-\\|=\\)" ; whitespace, assign (nth 1 ess--r-s-function-pattern)) "The regular expression for matching the beginning of an R function.") (defvar ess-s-function-pattern (concat (car ess--r-s-function-pattern) "\\s-*\\(<-\\|_\\|=\\)" ; whitespace, assign (incl. "_") (nth 1 ess--r-s-function-pattern)) "The regular expression for matching the beginning of an S function.") (defvar ess--fn-name-start-cache nil) (defun ess--fn-name-start () "Return (FN-NAME . START-POS). FN-NAME is a function name located before the pointer. START-POS is the position where FN-NAME starts. Store this cons in variable `ess--fn-name-start-cache'." (save-excursion (save-restriction (let* ((proc (get-buffer-process (current-buffer))) (mark (and proc (process-mark proc)))) (if (and mark (>= (point) mark)) (narrow-to-region mark (point))) (and (fboundp 'ess-noweb-narrow-to-chunk) (bound-and-true-p ess-noweb-mode) (ess-noweb-narrow-to-chunk)) (unless (ess-inside-string-p) (setq ess--fn-name-start-cache (condition-case nil ;; check if it is inside a function (progn ;; for the sake of big buffers, look only 1000 chars back (narrow-to-region (max (point-min) (- (point) 1000)) (point)) (up-list -1) (while (not (looking-at "(")) (up-list -1)) (let ((funname (symbol-name (ess-symbol-at-point)))) (when (and funname (not (member funname ess-S-non-functions))) (cons funname (- (point) (length funname)))))) (error nil)))))))) (defun ess-symbol-at-point () "Like `symbol-at-point' but consider fully qualified names. Fully qualified names include accessor symbols (like aaa$bbb and aaa@bbb in R)." (with-syntax-table (or ess-mode-completion-syntax-table (syntax-table)) (symbol-at-point))) (defun ess-bounds-of-symbol () "Get bounds of symbol at point. Intended for completion." (let ((bounds (with-syntax-table (or ess-mode-completion-syntax-table (syntax-table)) (bounds-of-thing-at-point 'symbol)))) (and bounds (not (save-excursion (goto-char (car bounds)) (looking-at "/\\|[.0-9]"))) bounds))) (defun ess-symbol-start () "Get initial position for objects completion. Symbols are fully qualified names that include accessor symbols (like aaa$bbb and aaa@bbb in R)." (car (ess-bounds-of-symbol))) (defun ess-arg-start () "Get initial position for args completion." (when (not (ess-inside-string-p)) (when (ess--fn-name-start) (if (looking-back "[(,]+[ \t\n]*" nil) (point) (ess-symbol-start))))) (defun ess-inside-string-p (&optional pos) "Return non-nil if POS is inside string. POS defaults to `point'." (let ((pos (or pos (point)))) (nth 3 (syntax-ppss pos)))) (defun ess-inside-comment-p (&optional pos) "Return non-nil if POS is inside string. POS defaults to `point'." (let ((pos (or pos (point)))) (nth 4 (syntax-ppss pos)))) (defun ess-inside-string-or-comment-p (&optional pos) "Return non-nil if POS is inside a string or comment. POS defaults to `point'." (or (ess-inside-string-p pos) (ess-inside-comment-p pos))) (defun ess-inside-brackets-p (&optional pos curly?) "Return t if position POS is inside brackets. POS defaults to point if no value is given. If CURLY?? is non nil also return t if inside curly brackets." (save-excursion (let ((ppss (syntax-ppss pos)) (r nil)) (while (and (> (nth 0 ppss) 0) (not r)) (goto-char (nth 1 ppss)) (when (or (char-equal ?\[ (char-after)) (and curly? (char-equal ?\{ (char-after)))) (setq r t)) (setq ppss (syntax-ppss))) r))) ;;*;; String manipulation (defun ess-quote-special-chars (string) "Quote special characters in STRING." (replace-regexp-in-string "\"" "\\\\\\&" (replace-regexp-in-string ;; replace backslashes "\\\\" "\\\\" string nil t))) (defun ess-rep-regexp (regexp to-string &optional fixedcase literal verbose) "Instead of (replace-regexp..) -- do NOT replace in strings or comments. If FIXEDCASE is non-nil, do *not* alter case of replacement text. If LITERAL is non-nil, do *not* treat `\\' as special. If VERBOSE is non-nil, (message ..) about replacements." (let ((case-fold-search (and case-fold-search (not fixedcase))); t <==> ignore case in search (ppt (point)); previous point (p)) (while (and (setq p (re-search-forward regexp nil t)) (< ppt p)) (setq ppt p) (cond ((not (ess-inside-string-or-comment-p (1- p))) (if verbose (let ((beg (match-beginning 0))) (message "buffer in (match-beg.,p)=(%d,%d) is '%s'" beg p (buffer-substring beg p)))) (replace-match to-string fixedcase literal)))))) (defun ess-replace-regexp-dump-to-src (regexp to-string &optional dont-query verbose) "Replace REGEXP matches from beginning of buffer with TO-STRING. If DONT-QUERY is non-nil, call `ess-rep-regexp' else call `query-replace-regexp'. VERBOSE can be passed to `ess-rep-regexp'." (save-excursion (goto-char (point-min)) (if dont-query (ess-rep-regexp regexp to-string nil nil verbose) (query-replace-regexp regexp to-string nil)))) (defun ess-space-around (word &optional from verbose) "Replace-regexp .. ensuring space around all occurrences of WORD. Start at from FROM, which defaults to point." (interactive "d\nP"); Defaults: point and prefix (C-u) (save-excursion (goto-char from) (ess-rep-regexp (concat "\\([^ \t\n]\\)\\(\\<" word "\\>\\)") "\\1 \\2" nil nil verbose) (goto-char from) (ess-rep-regexp (concat "\\(\\<" word "\\>\\)\\([^ \t\n]\\)") "\\1 \\2" nil nil verbose))) (defun ess-time-string (&optional clock) "Return a string for use as a timestamp, like \"13 Mar 1992\". Include hr:min if CLOCK is non-nil. Redefine to taste." (declare (obsolete format-time-string "ESS 19.04")) (format-time-string (concat "%e %b %Y" (if clock ", %H:%M")))) (defun ess-replace-in-string (str regexp newtext &optional literal) "Replace all matches in STR for REGEXP with NEWTEXT string. Optional LITERAL non-nil means do a literal replacement. Otherwise treat \\ in NEWTEXT string as special: \\& means substitute original matched text, \\N means substitute match for \(...\) number N, \\\\ means insert one \\." (if (not (stringp str)) (error "(replace-in-string): First argument must be a string: %s" str)) (if (stringp newtext) nil (error "(replace-in-string): 3rd arg must be a string: %s" newtext)) (let ((rtn-str "") (start 0) (special) match prev-start) (while (setq match (string-match regexp str start)) (setq prev-start start start (match-end 0) rtn-str (concat rtn-str (substring str prev-start match) (cond (literal newtext) (t (mapconcat (function (lambda (c) (if special (progn (setq special nil) (cond ((eq c ?\\) "\\") ((eq c ?&) (substring str (match-beginning 0) (match-end 0))) ((and (>= c ?0) (<= c ?9)) (if (> c (+ ?0 (length (match-data)))) ;; Invalid match num (error "(replace-in-string) Invalid match num: %c" c) (setq c (- c ?0)) (substring str (match-beginning c) (match-end c)))) (t (char-to-string c)))) (if (eq c ?\\) (progn (setq special t) nil) (char-to-string c))))) newtext "")))))) (concat rtn-str (substring str start)))) (defvar ess-nuke-trailing-whitespace-p nil;disabled by default 'ask "[Dis]activates (ess-nuke-trailing-whitespace). Disabled if nil; if t, it works unconditionally, otherwise, the user is queried. Note that setting the default to t may not be a good idea when you edit binary files!") ;;; MM: Newer Emacsen now have delete-trailing-whitespace ;;; -- but no customization like nuke-trailing-whitespace-p .. (defun ess-nuke-trailing-whitespace () "Nuke all trailing whitespace in the buffer. Whitespace in this case is just spaces or tabs. This is a useful function to put on `write-file-hooks'. If the variable `ess-nuke-trailing-whitespace-p' is nil, this function is disabled. If t, unreservedly strip trailing whitespace. If not nil and not t, query for each instance." (interactive) (let ((bname (buffer-name))) (cond ((or (string= major-mode "rmail-mode") (string= bname "RMAIL") nil)); do nothing.. (t (and (not buffer-read-only) ess-nuke-trailing-whitespace-p (save-match-data (save-excursion (save-restriction (widen) (goto-char (point-min)) (cond ((eq ess-nuke-trailing-whitespace-p t) (while (re-search-forward "[ \t]+$" (point-max) t) (delete-region (match-beginning 0) (match-end 0)))) (t (query-replace-regexp "[ \t]+$" ""))))))))) ;; always return nil, in case this is on write-file-hooks. nil)) (defun ess--strip-final-newlines (string) (replace-regexp-in-string "\n+$" "" string)) ;;*;; Debugging tools (defun ess-write-to-dribble-buffer (text) "Write TEXT to `ess-dribble-buffer'." (when (or ess-verbose ess-write-to-dribble) (with-current-buffer (get-buffer-create ess-dribble-buffer) (goto-char (point-max)) (insert-before-markers text)))) (defun ess-if-verbose-write (text) "Write TEXT to `ess-dribble-buffer' only if `ess-verbose' is non-nil." (when ess-verbose (ess-write-to-dribble-buffer text))) (defun ess-kill-last-line () (save-excursion (goto-char (point-max)) (forward-line -1) (delete-region (line-end-position) (point-max)))) (defun ess-sleep () "Put Emacs to sleep for `ess-sleep-for-shell' seconds (floats work)." (sleep-for ess-sleep-for-shell)) (defun ess-setq-vars-local (alist &optional buf) "Set language variables from ALIST, in buffer BUF, if desired." (when buf (set-buffer buf)) (mapc (lambda (pair) (make-local-variable (car pair)) (set (car pair) (eval (cdr pair) t)) (when (bound-and-true-p ess--make-local-vars-permanent) (put (car pair) 'permanent-local t))) ;; hack for Rnw alist)) (defmacro ess--alist (vars) "Build a self-named alist from VARS. VARS must be a list of symbols." (declare (debug 0)) `(list ,@(mapcar (lambda (var) `(cons ',var ,var)) vars))) (defvar ess-error-regexp "^\\(Syntax error: .*\\) at line \\([0-9]*\\), file \\(.*\\)$" "Regexp to search for errors.") (define-obsolete-function-alias 'ess-beginning-of-function #'beginning-of-defun "ESS 19.04") (define-obsolete-function-alias 'ess-end-of-function #'end-of-defun "ESS 19.04") (with-no-warnings (defalias 'ess--project-root ;; TODO: Remove once we drop support for Emacs 27 (if (and (fboundp 'project-root) ;; Issues caused unless we confirm `project-roots' is obsolete, see bug#1052 (get 'project-roots 'byte-obsolete-info)) 'project-root (lambda (project) "See `project-roots'." (car (project-roots project)))))) (provide 'ess-utils) ;;; ess-utils.el ends here ESS-24.01.1/lisp/ess.el000066400000000000000000000214421455642170100144040ustar00rootroot00000000000000;;; ess.el --- Emacs Speaks Statistics -*- lexical-binding: t; -*- ;; Copyright (C) 1997-2024 Free Software Foundation, Inc. ;; Author: David Smith ;; A.J. Rossini ;; Richard M. Heiberger ;; Kurt Hornik ;; Martin Maechler ;; Rodney A. Sparapani ;; Stephen Eglen ;; Sebastian P. Luque ;; Henning Redestig ;; Vitalie Spinu ;; Lionel Henry ;; J. Alexander Branham ;; ;; Maintainer: ESS Core Team ;; Created: 7 Jan 1994 ;; Version: 24.01.1 ;; URL: https://ess.r-project.org/ ;; Package-Requires: ((emacs "25.1")) ;; ESSR-Version: 1.8 ;; This file is part of GNU Emacs. ;;; License: ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see ;; ;;; Commentary: ;; ;; Emacs Speaks Statistics (ESS) is a package designed to support editing of ;; scripts and interaction with various statistical analysis programs such as R, ;; S-Plus, SAS, Stata and OpenBUGS/JAGS. For more details please visit ESS home ;; page at https://ess.r-project.org/ ;;; Code: (require 'ess-utils) (require 'cl-generic) (require 'lisp-mnt) (defvar reporter-prompt-for-summary-p) ;; Versions (defconst ess-version (eval-when-compile (lm-version (or (and (boundp 'load-true-file-name) load-true-file-name) load-file-name buffer-file-name))) "Version of ESS currently loaded.") (defconst essr-version (eval-when-compile (lm-with-file (or (and (boundp 'load-true-file-name) load-true-file-name) load-file-name buffer-file-name) (lm-header "ESSR-Version"))) "Version of ESSR package.") (defvar ess-revision nil "The revision and date of ESS. Is set by \\[ess-version-string].") ;;;###autoload (defun ess-version () "Return a string with ESS version information." (interactive) (message (format "ess-version: %s (loaded from %s)" (ess-version-string) (file-name-directory ess-lisp-directory)))) (defun ess-version-string () (let* ((ess-dir (file-name-directory ess-lisp-directory)) ; if() the top-level 'ess/' (is-release (file-exists-p (concat ess-etc-directory ".IS.RELEASE"))) (rel-string (if is-release "Released ")) (git-ref-fn (concat ess-dir ".git/HEAD")) (git-ref (when (file-exists-p git-ref-fn) (with-current-buffer (find-file-noselect git-ref-fn) (goto-char (point-min)) (when (re-search-forward "ref: \\(.*\\)\n" nil t) (match-string 1))))) (git-fname (if git-ref (concat ess-dir ".git/" git-ref) ;; For release (concat ess-etc-directory "git-ref"))) (git-rev (when (file-exists-p git-fname) (with-current-buffer (find-file-noselect git-fname) (goto-char (point-min)) (concat "git: "(buffer-substring (point-min) (line-end-position)))))) (elpa-fname (concat ess-dir "ess-pkg.el")) (elpa-rev (when (file-exists-p elpa-fname) ;; Get it from ELPA dir name, (probably won't work if installed manually) (concat "elpa: " (replace-regexp-in-string "ess-" "" (file-name-nondirectory (substring ess-dir 1 -1))))))) ;; Set the "global" ess-revision: (setq ess-revision (format "%s%s%s" (or rel-string "") (or git-rev "") (or elpa-rev ""))) (when (string= ess-revision "") (setq ess-revision "")) (concat ess-version " [" ess-revision "]"))) ;;; Bug Reporting ;;;###autoload (defun ess-submit-bug-report () "Submit a bug report to the ESS maintainers." (interactive) (let ((reporter-prompt-for-summary-p 't)) (reporter-submit-bug-report "ess-bugs@r-project.org" (concat "ess-mode " (ess-version-string)) (list 'ess-language 'ess-dialect 'ess-ask-for-ess-directory 'ess-ask-about-transfile 'default-directory 'ess-keep-dump-files 'ess-source-directory 'ess-use-ido 'ess-use-eldoc 'ess-use-tracebug 'ess-use-auto-complete 'ess-use-company 'ess-eval-visibly-p 'ess-can-eval-in-background 'ess-local-process-name) nil (lambda () ;;(goto-char (point-max)) (rfc822-goto-eoh) (forward-line 1) (insert "\n\n-------------------------------------------------------\n") (insert "This bug report will be sent to the ESS bugs email list\n") (insert "Press C-c C-c when you are ready to send your message.\n") (insert "-------------------------------------------------------\n\n") (insert (with-current-buffer ess-dribble-buffer (goto-char (point-max)) (forward-line -100) (buffer-substring-no-properties (point) (point-max)))))))) ;;; Timer (defcustom ess-idle-timer-interval 1 "Number of seconds to wait before running function in `ess-idle-timer-functions'." :type '(integer) :group 'ess) (defvar ess-idle-timer-functions nil "A list of functions to run each `ess-idle-timer-interval' idle seconds. If your function calls the process, you better use `ess-when-new-input' to wrap your call. If you call the subprocess please respect `ess-can-eval-in-background' variable. These functions are run with `run-hooks'. Use `add-hook' to add symbols to this variable. Most likely you will need a local hook. Then you should specify the LOCAL argument to `add-hook' and initialize it in `ess-mode-hook' or `ess-post-run-hook', or one of the more specialized hooks `ess-r-post-run-hook',`ess-stata-post-run-hook' etc.") (defun ess--idle-timer-function nil "Internal function executed by `ess--idle-timer'." (run-hooks 'ess-idle-timer-functions)) (require 'timer) (defvar ess--idle-timer (run-with-idle-timer ess-idle-timer-interval 'repeat #'ess--idle-timer-function) "Timer used to run `ess-idle-timer-functions'.") ;;; Dispatch on ess-dialect ;; Inspired by major-mode specializer in cl-generic.el ;; FIXME: Implement a notion of derived dialects. major-mode specializer cannot ;; be used here as we need same dialect in different major-modes. ;; Two parts: ;; 1) first define a specializer (ess-dialect= DIALECT) to match symbols ;; representing ess dialects. ;; 2) then define a context-rewriter so you can write ;; `&context (ess-dialect "R")` rather than ;; `&context (ess-dialect (ess-dialect= "R"))`. (cl-generic-define-generalizer ess--generic-dialect-generalizer 95 (lambda (name &rest _) `(if (stringp ,name) (intern ,name) (if (symbolp ,name) ,name))) (lambda (tag &rest _) `((ess-dialect= ,tag)))) (cl-defmethod cl-generic-generalizers ((_specializer (head ess-dialect=))) "Support for (ess-dialect DIALECT) context specializer." (list ess--generic-dialect-generalizer)) (cl-generic-define-context-rewriter ess-dialect (dialect) `(ess-dialect (ess-dialect= ,(if (stringp dialect) (intern dialect) dialect)))) ;; (cl-defgeneric ess-print-dialect () ;; (error "unknown dialect %s" ess-dialect)) ;; (cl-defmethod ess-print-dialect (&context (ess-dialect "R")) ;; (message "dialect: R")) ;; (cl-defmethod ess-print-dialect (&context (ess-dialect "julia")) ;; (message "dialect: julia")) (provide 'ess) ;;; ess.el ends here ESS-24.01.1/lisp/essd-els.el000066400000000000000000000152441455642170100153340ustar00rootroot00000000000000;;; essd-els.el --- S-PLUS 3.x at another location customization -*- lexical-binding: t; -*- ;; Copyright (C) 1998-2022 Free Software Foundation, Inc. ;; Author: Richard M. Heiberger ;; Created: December 1998 ;; Maintainer: ESS-core ;;; License: ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see ;; ;;; Commentary: ;; This file defines all the S-PLUS 3.x customizations for ess-mode. ;;; Code: (require 'ess-r-mode) (require 'ess-sp6-d) (require 'ess-sas-d) (require 'ess-trns) (require 'ess-utils) (defvar ess-julia-customize-alist) ;; Easily changeable in a user's .emacs (defvar S+elsewhere-dialect-name "S+6" "Name of `dialect' for S-PLUS at another location.") (defvar S+elsewhere-start-args "-i" "Arguments for `S+elsewhere-dialect-name'.") (defcustom inferior-ess-remote-pager nil "Remote pager to use for reporting help files and similar things. The default value is nil." :group 'ess-proc :type '(choice (const nil) string)) (defvar S+elsewhere-customize-alist (append '((ess-local-customize-alist . S+elsewhere-customize-alist) (ess-dialect . S+elsewhere-dialect-name) (ess-object-name-db-file . "ess-spelsewhere-namedb.el" ) (inferior-ess-program . inferior-S-elsewhere-program) (inferior-ess-help-command . "help(\"%s\", pager=\"cat\", window=F)\n") (ess-STERM . "iESS") ) S+common-cust-alist) "Variables to customize for S+elsewhere.") (defun S+elsewhere (&optional _proc-name) "Call 'S-PLUS 3.x', the 'Real Thing' from StatSci." ;; git commit 104c4d7c56bc239ea245562763caa317bc3a1a84 (declare (obsolete ess-remote "2000")) (ess-write-to-dribble-buffer (format "\n(S+elsewhere): ess-dialect=%s, buf=%s\n" ess-dialect (current-buffer))) (let ((inf-buf (inferior-ess nil S+elsewhere-customize-alist))) (when inferior-ess-language-start (ess-eval-linewise inferior-ess-language-start)) inf-buf)) (defun S+elsewhere-mode (&optional _proc-name) "Major mode for editing S+3 source. See `ess-mode' for more help." (declare (obsolete ess-remote "2000")) (setq-local ess-local-customize-alist S+elsewhere-customize-alist) (ess-mode)) ;; This REALLY shouldn't need an editing mode. Just a transcript and ;; an inferior process handler. (defun ess-select-alist-dialect (&optional dialect) "Query user for an ESS DIALECT and return the matching customize-alist." (interactive) (let* ((dialects '("R" "S+" "julia" "s3" "s4" "sp3" "sp4" "sqpe4" "sp5" "sqpe" "SAS")) (dialect (or dialect (ess-completing-read "Dialect" dialects nil t)))) (cond ((string= dialect "julia") (progn (require 'julia-mode) ess-julia-customize-alist)) ((string= dialect "R") ess-r-customize-alist) ((string= dialect "SAS") SAS-customize-alist) (t S+elsewhere-customize-alist)))) (defun ess-add-ess-process () "Execute this command from within a buffer running a process to add the process to `ess-process-name-alist' and to make it the `ess-current-process-name'. This command will normally be run in a telnet buffer connected to another computer or in a shell or comint buffer on the local computer." (interactive) (let ((proc (get-buffer-process (buffer-name)))) (if (not proc) (error "No process is associated with this buffer") (set-process-filter proc #'inferior-ess-output-filter) (setq ess-current-process-name (process-name proc)) (add-to-list 'ess-process-name-list (list ess-current-process-name))))) (defvar ess-remote nil "Indicator, t in remote buffers.") ;;;###autoload (defun ess-remote (&optional proc-name dialect) "Execute this command from within a buffer running a process. It runs `ess-add-ess-process' to add the PROC-NAME to `ess-process-name-alist' and to make it the `ess-current-process-name'. It then prompts the user for an ESS language and sets the editing characteristics appropriately. To use this command, first start a process on a remote computer by manual use of telnet, rlogin, ssh, or some other protocol. Start the relevant program (\"S\" or \"R\" or \"sas -stdio\") in that buffer. Once you are talking to S or R or SAS, then do \\[ess-remote] to make the current buffer an inferior-ess buffer with the right behavior for the language you are currently working with. With S and R, use C-c C-n to send lines over. With SAS, use C-c i `ess-eval-line-and-step-invisibly' to send lines over invisibly. DIALECT is the desired ess-dialect. If nil, ask for dialect" (interactive) (ess-add-ess-process) ;; Need to select a remote-customize-alist (let ((customize-alist (ess-select-alist-dialect dialect))) (ess-write-to-dribble-buffer (format "\n(ESS-remote): ess-dialect=%s, buf=%s\n" ess-dialect (current-buffer))) (ess-setq-vars-local customize-alist) (inferior-ess--set-major-mode ess-dialect) (setq-local ess-remote t) (setq ess-local-process-name (or proc-name ess-current-process-name)) (goto-char (point-max)) (when (equal ess-dialect "R") ;; ugly fix for evn variable. What can we do :( (ess-eval-linewise (format "options(pager='%s')\n" (or inferior-ess-remote-pager inferior-ess-pager)) nil nil nil 'wait) (ess-r-load-ESSR)) (when (equal ess-dialect "S+") (ess-command ess-S+--injected-code)) (when (equal ess-language "SAS") (font-lock-mode 0) (SAS-log-mode) (shell-mode) (setq buffer-read-only nil) (font-lock-mode 1)) (ess-process-put 'funargs-cache (make-hash-table :test 'equal)) (ess-process-put 'funargs-pre-cache nil) ;; auto-complete (ess--setup-auto-complete ess-r-ac-sources t) ;; company (ess--setup-company ess-r-company-backends t) (when inferior-ess-language-start (ess-eval-linewise inferior-ess-language-start nil nil nil 'wait-prompt)))) ; Provide package (provide 'essd-els) ;;; essd-els.el ends here ESS-24.01.1/lisp/obsolete/000077500000000000000000000000001455642170100151015ustar00rootroot00000000000000ESS-24.01.1/lisp/obsolete/ess-eldoc.el000066400000000000000000000141251455642170100173040ustar00rootroot00000000000000;;; ess-eldoc.el --- Use eldoc to report R function names. -*- lexical-binding: t; -*- ;; Copyright (C) 1997-2022 Free Software Foundation, Inc. ;; Author: Stephen Eglen ;; Created: 2007-06-30 ;; Maintainer: ESS-core ;; This file is part of GNU Emacs. ;;; License: ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see ;; ;;; Commentary: ;;;;; eldoc functionality has been moved into the core ;;;;; ;;;;; this file has no effect and is left in ESS in order not to break ;;;;; users configuration ;; This is an initial attempt to use the emacs facility ELDOC in R ;; buffers. Eldoc is used in Emacs lisp buffers to show the function ;; arglist and docstrings for variables. To try it, view an emacs ;; lisp buffer, and then do M-x turn-on-eldoc-mode, and move over ;; function and variable names. ;; This file extends eldoc to work in R buffers. It currently uses ;; Sven's ess-r-args.el file to retrieve args for a given R function ;; (via ess-r-args-get). Note that it works slightly different to ;; Sven's code, in that you just need to have the point over the name ;; of an R function, or inside its arguments list, for eldoc to show ;; the arg list. ;; To use this functionality, simply add ;; ;; (require 'ess-eldoc) ;; ;; to your .emacs file. When you visit a R mode, eldoc will be turned ;; on. However, you will first need to associate the R buffer with an ;; *R* process so that args can be looked up -- otherwise, eldoc will ;; silently not report anything. So, e.g. try: ;; C-x C-f somefile.R ;; M-x R (so that somefile.R is associated with *R*) ;; eldoc should then work. ;; e.g. put the following rnorm() command in an R buffer. The line ;; underneath shows a key of what arg list will be shown as you move ;; across the rnorm line. ;; rnorm(n=100, mean=sqrt(20), sd=10) ;; 1111111111111222223333333311444111 ;; 1: rnorm ;; 2: mean ;; 3: sqrt ;; 4: sd ;; ;; Note that the arg list for rnorm() should be shown either when you ;; are on the function name, or in the arg list. However, since the ;; 2nd and 3rd arguments are also function names, the arg lists of ;; those function names are reported instead. This might be seen as ;; undesirable behaviour, in which case a solution would be to only ;; look up the function name if it is followed by (. ;; If you want to use this feature in *R* buffers, add the following ;; to .emacs: ;; (add-hook 'inferior-ess-mode-hook 'ess-use-eldoc) ;; In the current version, I do not cache the arg list, but that was ;; done in an earlier version, to save repeated calls to ;; ess-r-args-get. ;; This code has been tested only in Emacs 22.1. It will not work on ;; Emacs 21, because it needs the variable ;; eldoc-documentation-function. ;;;; VS [25-02-2012]: all these issues were at least partially addressed in the ;;;; new implementation: ;; Bug (in eldoc?): the arg list for legend() is too long to fit in ;; minibuffer, and it seems that we see the last N lines of the arg ;; list, rather than the first N lines. It would be better to see the ;; first N lines since the more important args come first. ;; Doc issue: the eldoc vars (e.g. eldoc-echo-area-use-multiline-p) ;; work only for elisp mode. ;; Issue: You will probably see the message "Using process 'R'" flash; ;; this is generated by `ess-request-a-process', and I'd like to avoid ;; that appearing, non-interactively. ;; If *R* is currently busy (e.g. processing Sys.sleep(999)), then the ;; eldoc commands won't work; ess-command could be silenced in this ;; regard perhaps with a new SILENT arg for example to prevent the ;; call to (ess-error). ;;; Code: ;; ;; This could be done on buffer local basis. ;; (setq ess-r-args-noargsmsg "") ;; ;; following two defvars are not currently used. ;; (defvar ess-eldoc-last-name nil ;; "Name of the last function looked up in eldoc. ;; We remember this to see whether we need to look up documentation, or used ;; the cached value in `ess-eldoc-last-args'.") ;; (defvar ess-eldoc-last-args nil ;; "Args list last looked up for eldoc. Used as cache.") ;; (defun ess-eldoc-2 () ;; ;; simple, old version. ;; (interactive) ;; (ess-r-args-get (ess-read-object-name-default))) ;; (defun ess-eldoc-1 () ;; "Return the doc string, or nil. ;; This is the first version; works only on function name, not within arg list." ;; (interactive) ;; ;; Possible ways to get the function at point. ;; ;;(setq name (thing-at-point 'sexp)) ;; ;;(setq name (ess-read-object-name-default)) ;; ;;(setq name (find-tag-default)) ;; (if ess-current-process-name ;; (progn ;; (setq name (ess-guess-fun)) ;guess the word at point. ;; (if (equal (length name) 0) ;; nil ;; ;; else ;; (unless (equal name ess-eldoc-last-name) ;; ;; name is different to the last name we lookedup, so get ;; ;; new args from R and store them. ;; (setq ess-eldoc-last-args (ess-r-args-get name) ;; ess-eldoc-last-name name)) ;; ess-eldoc-last-args)) ;; ;; no ESS process current. ;; nil) ;; ) ;; (defsubst ess-guess-fun () ;; "Guess what the function at point is." ;; ;; Derived from Man-default-man-entry in man.el ;; (let (word) ;; (save-excursion ;; (skip-chars-backward "-a-zA-Z0-9._+:") ;; (let ((start (point))) ;; (skip-chars-forward "-a-zA-Z0-9._+:") ;; (setq word (buffer-substring-no-properties start (point))))) ;; word)) (defun ess-use-eldoc () "Does nothing. Defined not to break old users' code." (interactive)) (provide 'ess-eldoc) ;;; ess-eldoc.el ends here ESS-24.01.1/lisp/obsolete/ess-font-lock.el000077500000000000000000000142151455642170100201150ustar00rootroot00000000000000;;; ess-font-lock.el --- font-lock color options -*- lexical-binding: t; -*- ;; Copyright (C) 2000-2022 Free Software Foundation, Inc. ;; Author: Richard M. Heiberger ;; Created: 06 Feb 2000 ;; Keywords: languages, faces ;; This file is part of ESS ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; ;; This file 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. ;; ;; A copy of the GNU General Public License is available at ;; https://www.r-project.org/Licenses/ ;;; Commentary: ;; provides syntax highlighting support. ;;; Code: ; Requires and autoloads (require 'font-lock) (require 'paren) ;; FIXME: What is this doing here!? (if (fboundp 'show-paren-mode) (show-paren-mode 1)) ;;; Emacs 20.x notes: ;; font-lock faces are defined in /emacs/emacs-20.5/lisp/font-lock.el ;; The font-lock faces are applied to ESS buffers by ;; ess-mode.el ess-inf.el ess-trns.el ess-custom.el ;; The keywords for faces are defined in the ess[dl]*.el files. ;; All faces can be looked at, under Emacs 20.x, with ;; [menu-bar] [Edit] [Text Properties] [Display Faces} (defun ess-font-lock-rmh () "Set font-lock colors to Richard Heiberger's usual choice." ;; FIXME: Turn it into a Custom theme! (interactive) (set-foreground-color "Black") (set-background-color "lightcyan") (set-face-background 'mode-line "lightskyblue") (set-face-foreground 'mode-line "midnightblue") (set-face-foreground 'font-lock-comment-face "Firebrick") (set-face-foreground 'font-lock-function-name-face "Blue") (set-face-foreground 'font-lock-keyword-face "Purple") (set-face-foreground 'font-lock-constant-face "Brown") (set-face-foreground 'font-lock-string-face "VioletRed") (set-face-foreground 'font-lock-type-face "Sienna") (set-face-foreground 'font-lock-variable-name-face "Black")) (defun ess-font-lock-blue () "Set font-lock colors to Richard Heiberger's blue color scheme." ;; FIXME: Turn it into a Custom theme! (interactive) (set-foreground-color "Black") (set-background-color "LightBlue") (set-face-foreground 'mode-line "LightBlue") (set-face-background 'mode-line "DarkSlateBlue") (set-face-foreground 'font-lock-comment-face "Firebrick") (set-face-foreground 'font-lock-function-name-face "Blue") (set-face-foreground 'font-lock-keyword-face "Purple") (set-face-foreground 'font-lock-constant-face "Brown") (set-face-foreground 'font-lock-string-face "VioletRed") (set-face-foreground 'font-lock-type-face "Sienna") (set-face-foreground 'font-lock-variable-name-face "Black")) (defun ess-font-lock-wheat () "Set font-lock colors to Richard Heiberger's wheat color scheme." ;; FIXME: Turn it into a Custom theme! (interactive) (set-foreground-color "Black") (set-background-color "Wheat") (set-face-foreground 'mode-line "Wheat") (set-face-background 'mode-line "Sienna") (set-face-foreground 'font-lock-comment-face "Firebrick") (set-face-foreground 'font-lock-function-name-face "Blue") (set-face-foreground 'font-lock-keyword-face "Purple") (set-face-foreground 'font-lock-constant-face "Brown") (set-face-foreground 'font-lock-string-face "VioletRed") (set-face-foreground 'font-lock-type-face "Sienna") (set-face-foreground 'font-lock-variable-name-face "Black")) (defun ess-font-lock-bw () "Set font-lock colors to Richard Heiberger's black and white color scheme." ;; FIXME: Turn it into a Custom theme! (interactive) (set-foreground-color "Black") (set-background-color "white") (set-face-foreground 'mode-line "gray10") (set-face-background 'mode-line "gray90") ;; modify-face is an interactive compiled Lisp function in `faces'. ;; Sample usage: ;;(modify-face FACE FOREGROUND BACKGROUND STIPPLE BOLD-P ITALIC-P UNDERLINE-P &optional INVERSE-P FRAME) (modify-face 'mode-line "gray10" "gray90" nil nil t nil ) (modify-face 'font-lock-comment-face "black" "white" nil nil t nil ) (modify-face 'font-lock-function-name-face "black" "white" nil t nil nil ) (modify-face 'font-lock-keyword-face "black" "white" nil nil nil t ) (modify-face 'font-lock-constant-face "black" "white" nil t nil nil ) (modify-face 'font-lock-string-face "black" "white" nil nil t t ) (modify-face 'font-lock-type-face "black" "white" nil t t nil ) (modify-face 'font-lock-variable-name-face "black" "white" nil nil nil nil ) (modify-face 'font-lock-builtin-face "black" "white" nil t nil nil ) (modify-face 'font-lock-warning-face "black" "white" nil t nil nil ) (modify-face 'show-paren-match-face "gray20" "gray80" nil t nil nil ) (modify-face 'show-paren-mismatch-face "white" "gray40" nil t t nil )) (defun ess-font-lock-db () "Set font-lock colors (leave fore-/back-ground alone) courtesy David Brahm " ;; FIXME: Turn it into a Custom theme! (interactive) (set-face-foreground 'font-lock-comment-face "Firebrick") ; #... %... (set-face-foreground 'font-lock-string-face "SeaGreen") ; "..." "..." (set-face-foreground 'font-lock-keyword-face "MediumBlue") ; if \end (set-face-foreground 'font-lock-function-name-face "VioletRed") ; talk<- {center} (set-face-foreground 'font-lock-variable-name-face "Blue") ; xv (set-face-foreground 'font-lock-type-face "Goldenrod") ; T,F ? (set-face-foreground 'font-lock-constant-face "Magenta") ; <- {eq1} ) (provide 'ess-font-lock) ;;; ess-font-lock.el ends here ESS-24.01.1/lisp/obsolete/ess-mouse.el000066400000000000000000000212431455642170100173450ustar00rootroot00000000000000;;; ess-mouse.el --- Support for mouse- or cursor-sensitive actions -*- lexical-binding: t; -*- ;; Copyright (C) 2001-2022 Free Software Foundation, Inc. ;; Author: Richard M. Heiberger ;; Created: 25 Mar 2001 ;; Maintainer: ESS-core ;; This file is part of GNU Emacs. ;;; License: ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see ;; ;;; Commentary: ;; Support for mouse- or cursor-sensitive actions. This is based on ;; and uses mouseme.el. mouseme.el only does mouse sensitivity. ;; The new functions ess-mouse-me and ess-mouse-me-helper do similar ;; things based on the cursor, not the mouse, and can be bound to a ;; keystroke. ;;; Code: ; Requires and autoloads ;;*;; Requires (require 'mouseme) (require 'ess-trns) ;;(if (or (equal window-system 'w32) ;; (equal window-system 'win32) ;; (equal window-system 'mswindows)) ;; (require 'essiw32b)) (defun ess-mouse-me () "Popup a menu of functions to run on selected string or region." (interactive) (ess-mouse-me-helper (lambda (name) (or (x-popup-menu (list '(0 0) (get-buffer-window (get-buffer (buffer-name)))) (funcall mouse-me-build-menu-function name)) (error "No command to run"))))) (defun ess-mouse-me-helper (func) "Determine the string to use to process EVENT and call FUNC to get cmd." (let (name sp sm mouse beg end cmd mmtype) ;; temporarily goto where the event occurred, get the name clicked ;; on and enough info to figure out what to do with it (save-match-data (save-excursion (setq sp (point)) ; saved point (setq sm (mark t)) ; saved mark ;;; (set-buffer (window-buffer (posn-window (event-start event)))) ;;; (setq mouse (goto-char (posn-point (event-start event)))) (setq mouse (point)) ;; ess-mouse-me-helper ;; if there is a region and point is inside it ;; check for sm first incase (null (mark t)) ;; set name to either the thing they clicked on or region (if (and sm (or (and transient-mark-mode mark-active) (eq last-command 'mouse-drag-region)) (>= mouse (setq beg (min sp sm))) (<= mouse (setq end (max sp sm)))) (setq name (buffer-substring beg end)) (setq name (funcall mouse-me-get-string-function)) (if (listp name) (setq beg (nth 1 name) end (nth 2 name) name (car name)) (goto-char mouse) (while (not (looking-at (regexp-quote name))) (backward-char 1)) (setq beg (point)) (setq end (search-forward name)))))) ;; check if name is null, meaning they clicked on no word (if (or (null name) (and (stringp name) (string= name "" ))) (error "No string to pass to function")) ;; popup a menu to get a command to run (setq cmd (funcall func name)) ;; run the command, eval'ing if it was a list (if (listp cmd) (setq cmd (eval cmd t))) (setq mmtype (get cmd 'mouse-me-type)) (cond ((eq mmtype 'region) (funcall cmd beg end)) ((eq mmtype 'string) (funcall cmd name)) (t (funcall cmd name))))) (defcustom ess-S-mouse-me-menu-commands-alist '("S-Plus 4 and 6 GUI under Windows" ("Edit.data" . ess-mouse-me-Edit.data) "----" ("print" . ess-mouse-me-print) ("summary" . ess-mouse-me-summary) ("plot" . ess-mouse-me-plot) ("show" . ess-mouse-me-show) ("help" . ess-display-help-on-object) ("args" . ess-mouse-me-args) "----" ("Browser on" . ess-mouse-me-browser-on) ("Browser off" . ess-mouse-me-browser-off)) "Command menu used by `mouse-me-build-menu'. A alist of elements where each element is either a cons cell or a string. If a cons cell the car is a string to be displayed in the menu and the cdr is either a function to call passing a string to, or a list which evals to a function to call passing a string to. If the element is a string it makes a non-selectable element in the menu. To make a separator line use a string consisting solely of hyphens. The function returned from this menu will be called with one string argument. Or if the function has the symbol property `mouse-me-type' and if its value is the symbol `region' it will be called with the beginning and ending points of the selected string. If the value is the symbol `string' it will be called with one string argument." :type '(repeat sexp) :group 'mouseme) (defun ess-mouse-me-Edit.data (string) (ess-mouse-me-eval-expanded string "Edit.data(" ")" nil nil nil)) (defun ess-mouse-me-print (string) (ess-mouse-me-eval-expanded string "" "" nil nil t)) (defun ess-mouse-me-summary (string) (ess-mouse-me-eval-expanded string "summary(" ")" nil nil t)) (defun ess-mouse-me-plot (string) (ess-mouse-me-eval-expanded string "plot(" ")") nil nil nil) (defun ess-mouse-me-show (string) (ess-mouse-me-eval-expanded string "show(" ")") nil nil nil) (defun ess-mouse-me-args (string) (ess-mouse-me-eval-expanded string "args(" ")" nil nil t)) (defun ess-mouse-me-browser-on (string) (if (equal (substring ess-dialect 0 1) "R") (ess-eval-linewise (concat "debug(" string ")")) (ess-mouse-me-eval-expanded string "trace(" ", exit=browser)") nil nil nil)) (defun ess-mouse-me-browser-off (string) (if (equal (substring ess-dialect 0 1) "R") (ess-eval-linewise (concat "undebug(" string ")")) (ess-mouse-me-eval-expanded string "untrace(" ")") nil nil nil)) (defun ess-mouse-me-eval-expanded (string &optional head tail commands-buffer _page value-returned) "Send the expanded STRING to the inferior-ess process using `ess-command' after first concating the HEAD and TAIL. Put answer in COMMANDS-BUFFER if specified, otherwise in \"tmp-buffer\". In either case the buffer containing the answer is renamed to the value of the constructed command. If PAGE is non-nil, expand the string one more time by embedding it in a \"page()\" command." (interactive) (let* (scommand ;; page-scommand (lproc-name ess-local-process-name) (ess-mouse-customize-alist ess-local-customize-alist)) (if (not head) (setq head "summary(")) (if (not tail) (setq tail ")")) (if (not commands-buffer) (setq commands-buffer (get-buffer-create "tmp-buffer"))) (setq scommand (concat head string tail)) (ess-make-buffer-current) (pop-to-buffer-same-window commands-buffer) (ess-setq-vars-local (eval ess-mouse-customize-alist t) (current-buffer)) (setq ess-local-process-name lproc-name) (ess-command (concat scommand "\n") commands-buffer) (if (not value-returned) (pop-to-buffer-same-window (nth 1 (buffer-list)))) (if (not value-returned) nil (if ess-microsoft-p ;; there ought to be a filter (while (search-forward "\r" nil t) ;; function to keep the ^M (replace-match "" nil t))) ;; from showing up at all (ess-transcript-mode) (setq ess-local-process-name lproc-name) (rename-buffer scommand)))) ; Provide package (provide 'ess-mouse) ;;;;;;;; STARTUP STUFF ;;;;;;;;;;;; (make-variable-buffer-local 'mouse-me-menu-commands) (defun ess-S-mouse-me-menu-commands () (if (equal ess-language "S") (setq mouse-me-menu-commands ess-S-mouse-me-menu-commands-alist))) ;; (define-key ess-mode-map [S-mouse-3] 'ess-mouse-me) ;; (define-key inferior-ess-mode-map [S-mouse-3] 'ess-mouse-me) ;; (defun ess-S-mouse-me-ess-transcript-mode () ;; (define-key ess-transcript-mode-map [S-mouse-3] 'ess-mouse-me)) ;; (add-hook 'ess-mode-hook #'ess-S-mouse-me-menu-commands) (add-hook 'inferior-ess-mode-hook #'ess-S-mouse-me-menu-commands) (add-hook 'ess-transcript-mode-hook #'ess-S-mouse-me-menu-commands) ;; (add-hook 'ess-transcript-mode-hook 'ess-S-mouse-me-ess-transcript-mode) ;;; ess-mouse.el ends here ESS-24.01.1/lisp/obsolete/ess-r-a.el000066400000000000000000000114711455642170100166760ustar00rootroot00000000000000;;; ess-r-a.el -- Possible local customizations for R with ESS. -*- lexical-binding: t; -*- ;; Copyright (C) 1997-2022 Free Software Foundation, Inc. ;; Author: A.J. Rossini ;; Created: 17 November 1999 ;; Maintainer: ESS-core ;; This file is part of GNU Emacs. ;;; License: ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see ;; ;;; Commentary: ;; The purpose of this file is to demonstrate some of the extras that ;; have been constructed for the ESS R mode; if they prove ;; interesting, then they might be migrated to ess-r-mode, the primary ;; ESS R mode tools. ;;; Code: (require 'ess-inf) (require 'ess-r-mode) ;; you can invoke ESS/R from emacs by typing ;; C-u M-x essr ;; with vsize set to (for example) 40M, and nsize set to 600000. ;; Undefined on non-apple devices (declare-function ns-do-applescript "nsfns.m" (script)) (declare-function do-applescript "ess-r-a" (script)) (unless (fboundp 'do-applescript) (defalias 'do-applescript #'ns-do-applescript)) (defalias 'essr (read-kbd-macro "C-u M-x R RET - - vsize = 40M SPC - - nsize = 600000 2*RET")) (defun ess-r-do-region (start end) "Send from START to END to R via AppleScript." (interactive "r\nP") (message "Starting evaluation...") (do-applescript (concat "try\n" "tell application \"R\"\n" "activate\n" "with timeout of 0 seconds\n" "cmd \"" (buffer-substring start end) "\"\n" "end timeout\n" "end tell\n" "end try\n")) (message "Finished evaluation")) (defun ess-r-do-line () "Send the current line to R via AppleScript." (interactive) ;; "r\nP") (message "Starting evaluation...") (save-excursion (let ((end (point))) (move-to-column 0) (do-applescript (concat "try\n" "tell application \"R\"\n" "activate\n" "with timeout of 0 seconds\n" "cmd \"" (buffer-substring (point) end) "\"\n" "end timeout\n" "end tell\n" "end try\n")))) (message "Finished evaluation")) (defun ess-r-var (beg end) "Load the current region of numbers into an R variable. Prompts for a variable name. If none is given, it uses a default variable name, e. BEG and END denote the region in the current buffer to be sent." (interactive "r") (save-window-excursion (let ((tmp-file (make-temp-file "ess-r-var")) cmd var) (write-region beg end tmp-file) ;; Decide on the variable name to use in R; could use completion. (setq var (read-string "R Variable name (default e): ")) (if (equal var "") (setq var "e")) ;; Command to send to the R process. Get R to delete the file ;; rather than Emacs in case it takes R a long time to run the ;; scan command. (setq cmd (concat var " <- scan(\"" tmp-file "\"); " "unlink(\"" tmp-file "\")" )) ;; Put the output from the scan command into the process buffer so ;; the user has a record of it. (ess-execute cmd 'buffer)))) ;;; Peter Dalgaard's code. ;;; This needs to be cleaned and validated! (defun pd::set-up-demo () (run-ess-r) (split-window-vertically 6) (find-file "demos.R") ;; Don't need to run this as a function -- ought to be fine if set ;; just once. (defun ajr::scroll-to-end::peterD (emacs) "Goal: map prompt to bottom of the screen after every command. Alternatively, use the scroll-in-place package, not sure where that is)." (interactive) (other-buffer 1) (if (= emacs "emacs") (setq scroll-up-aggressively t) (setq scroll-conservatively -4)) ;; <- change this (other-buffer -1)) (defun show-max-other-window () (interactive) (other-window 1) (comint-show-maximum-output) (other-window -1)) ;; call this once ;; (ajr::scroll-to-end::peterD "emacs") (global-set-key [f11] #'show-max-other-window) (global-set-key [f12] #'ess-eval-line-visibly-and-step)) ; Provide package (provide 'ess-r-a) ;;; ess-r-a.el ends here ESS-24.01.1/lisp/obsolete/mouseme.el000066400000000000000000000327271455642170100171100ustar00rootroot00000000000000;;; mouseme.el --- mouse menu with commands that operate on strings -*- lexical-binding: t; -*- ;; Copyright (C) 1997-2022 by Free Software Foundation, Inc. ;; Author: Howard Melman ;; Keywords: mouse, menu ;; This file is part of GNU Emacs. ;;; License: ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see ;; ;;; Commentary: ;; This package provides a command `mouse-me' to be bound to a mouse ;; button. It pops up a menu of commands that operate on strings or a ;; region. The string passed to the selected command is the word or ;; symbol clicked on (with surrounding quotes or other punctuation ;; removed), or the region (if either it was just selected with the ;; mouse or if it was active with `transient-mark-mode' on). If the ;; command accepts a region, the selected region (or the region of the ;; word or symbol clicked on) will be passed to the command. ;; The idea is that for any given string in a buffer you may want to ;; do different things regardless of the mode of the buffer. URLs ;; now appear in email, news articles, comments in code, and in plain ;; text. You may want to visit that URL in a browser or you may just ;; want to copy it to the kill-ring. For an email address you might ;; want to compose mail to it, finger it, look it up in bbdb, copy it to ;; the kill ring. For a word you may want to spell check it, copy it, ;; change its case, grep for it, etc. Mouse-me provides a menu to ;; make this easy. ;; The menu popped up is generated by calling the function in the ;; variable `mouse-me-build-menu-function' which defaults to calling ;; `mouse-me-build-menu' which builds the menu from the variable ;; `mouse-me-menu-commands'. See the documentation for these ;; functions and variables for details. ;; To install, add something like the following to your ~/.emacs: ;; (require 'mouseme) ;; (global-set-key [S-mouse-2] 'mouse-me) ;;; Code: (require 'browse-url) (require 'thingatpt) (eval-when-compile (require 'compile)) ;;;; Variables (defgroup mouseme nil "Popup menu of commands that work on strings." :prefix "mouse-me-" :group 'hypermedia) (defcustom mouse-me-get-string-function 'mouse-me-get-string "Function used by `mouse-me' to get string when no region selected. The default is `mouse-me-get-string' but this variable may commonly be made buffer local and set to something more appropriate for a specific mode (e.g., `word-at-point'). The function will be called with no arguments and with point at where the mouse was clicked. It can return either the string or to be most efficient, a list of three elements: the string and the beginning and ending points of the string in the buffer." :type 'function :options '(mouse-me-get-string)) (defcustom mouse-me-build-menu-function 'mouse-me-build-menu "Function used by `mouse-me' to build the popup menu. The default is `mouse-me-build-menu' but this variable may commonly be made buffer local and set to something more appropriate for a specific mode. The function will be called with one argument, the string selected, as returned by `mouse-me-get-string-function'." :type 'function :options '(mouse-me-build-menu)) (defvar mouse-me-grep-use-extension 't "If non-nil `mouse-me-grep' grep's in files with current file's extension.") (defcustom mouse-me-menu-commands '(("Copy" . kill-new) ("Kill" . kill-region) ("Capitalize" . capitalize-region) ("Lowercase" . downcase-region) ("Uppercase" . upcase-region) ("ISpell" . ispell-region) "----" ("Browse URL" . browse-url) ("Dired" . dired) ("Execute File" . mouse-me-execute) ("Mail to" . compose-mail) ("Finger" . mouse-me-finger) ("BBDB Lookup" . mouse-me-bbdb) "----" ("Imenu" . imenu) ("Find Tag" . find-tag) ("Grep" . mouse-me-grep) ("Find-Grep" . mouse-me-find-grep) "----" ("Apropos" . apropos) ("Describe Function" . mouse-me-describe-function) ("Describe Variable" . mouse-me-describe-variable) ("Command Info" . mouse-me-emacs-command-info) ("Man Page" . (if (fboundp 'woman) 'woman 'man)) ("Profile Function" . mouse-me-elp-instrument-function)) "Command menu used by `mouse-me-build-menu'. A list of elements where each element is either a cons cell or a string. If a cons cell the car is a string to be displayed in the menu and the cdr is either a function to call passing a string to, or a list which evals to a function to call passing a string to. If the element is a string it makes a non-selectable element in the menu. To make a separator line use a string consisting solely of hyphens. The function returned from this menu will be called with one string argument. Or if the function has the symbol property `mouse-me-type' and if its value is the symbol `region' it will be called with the beginning and ending points of the selected string. If the value is the symbol `string' it will be called with one string argument." :type '(repeat sexp)) (put 'kill-region 'mouse-me-type 'region) (put 'ispell-region 'mouse-me-type 'region) (put 'capitalize-region 'mouse-me-type 'region) (put 'downcase-region 'mouse-me-type 'region) (put 'upcase-region 'mouse-me-type 'region) ;;;; Commands ;;;###autoload (defun mouse-me (event) "Popup a menu of functions to run on selected string or region." (interactive "e") (mouse-me-helper event (lambda (name) (or (x-popup-menu event (funcall mouse-me-build-menu-function name)) (error "No command to run"))))) ;;;; Exposed Functions ;; Some tests: ;; ;; ;; http://foo.bar.com/sss/ss.html ;; http://www.ditherdog.com/howard/ ;; mailto:howard@silverstream.com ;; howard@silverstream.com ;; ;; import com.sssw.srv.agents.AgentsRsrc; ;; public AgoHttpRequestEvent(Object o, String db, Request r) ;;
;; d:\howard\elisp\spoon ;; \howard\elisp\spoon ;; \\absolut\howard\elisp\spoon ;; //absolut/d/Howard/Specs/servlet-2.1.pdf ;; \\absolut\d\Howard\Specs\servlet-2.1.pdf ;; gnuserv-frame. (defun mouse-me-get-string () "Return a string from the buffer of text surrounding point. Returns a list of three elements, the string and the beginning and ending positions of the string in the buffer in that order." (save-match-data (save-excursion (let ((start (point)) beg end str) (skip-syntax-forward "^ >()\"") (setq end (point)) (goto-char start) (skip-syntax-backward "^ >()\"") (setq beg (point)) (setq str (buffer-substring-no-properties beg end)) ;; remove junk from the beginning (if (string-match "^\\([][\"'`.,?:;!@#$%^&*()_+={}|<>-]+\\)" str) (setq str (substring str (match-end 1)) beg (+ beg (match-end 1)))) ;; remove URL: from the front, it's common in email (if (string-match "^\\(URL:\\)" str) (setq str (substring str (match-end 1)) beg (+ beg (match-end 1)))) ;; remove junk from the end (if (string-match "\\([][\"'.,?:;!@#$%^&*()_+={}|<>-]+\\)$" str) (setq end (- end (length (match-string 1 str))) ; must set end first str (substring str 0 (match-beginning 1)))) (list str beg end))))) (defun mouse-me-build-menu (name) "Return a menu tailored for NAME for `mouse-me' from `mouse-me-menu-commands'." (list "Mouse Me" (cons "Mouse Me" (append (list (cons (if (< (length name) 65) name "...Long String...") 'kill-new) "---") mouse-me-menu-commands)))) ;;;; Commands for the menu (defun mouse-me-emacs-command-info (string) "Look in Emacs info for command named STRING." (interactive "sCommand: ") (let ((s (intern-soft string))) (if (and s (commandp s)) (Info-goto-emacs-command-node s) (error "No command named `%s'" string)))) (defun mouse-me-describe-function (string) "Describe function named STRING." (interactive "sFunction: ") (let ((s (intern-soft string))) (if (and s (fboundp s)) (describe-function s) (error "No function named `%s'" string)))) (defun mouse-me-describe-variable (string) "Desribe variable named STRING." (interactive "sVariable: ") (let ((s (intern-soft string))) (if (and s (boundp s)) (describe-variable s) (error "No variable named `%s'" string)))) (defun mouse-me-elp-instrument-function (string) "Instrument Lisp function named STRING." (interactive "sFunction: ") (let ((s (intern-soft string))) (if (and s (fboundp s)) (elp-instrument-function s) (error "Must be the name of an existing Lisp function")))) (defun mouse-me-execute (string) "Execute STRING as a filename." (interactive "sFile: ") (if (fboundp 'w32-shell-execute) (w32-shell-execute "open" (convert-standard-filename string)) (message "This function currently working only in W32."))) (defun mouse-me-bbdb (string) "Lookup STRING in bbdb." (interactive "sBBDB Lookup: ") (if (fboundp 'bbdb) (bbdb string nil) (error "BBDB not loaded"))) (defun mouse-me-finger (string) "Finger a STRING mail address." (interactive "sFinger: ") (save-match-data (if (string-match "\\(.*\\)@\\([-.a-zA-Z0-9]+\\)$" string) (finger (match-string 1 string) (match-string 2 string)) (error "Not in user@host form: %s" string)))) (defun mouse-me-grep (string) "Grep for a STRING." (interactive "sGrep: ") (require 'compile) (grep-compute-defaults) (let ((ext (mouse-me-buffer-file-extension))) (grep (concat grep-command string (if mouse-me-grep-use-extension (if ext (concat " *" ext) " *")))))) (defun mouse-me-find-grep (string) "Grep for a STRING." (interactive "sGrep: ") (grep-compute-defaults) (let ((reg grep-find-command) (ext (mouse-me-buffer-file-extension))) (if (string-match "\\(^.+-type f \\)\\(.+$\\)" reg) (setq reg (concat (match-string 1 reg) (if mouse-me-grep-use-extension (concat "-name \"*" ext "\" ")) (match-string 2 reg)))) (grep-find (concat reg string)))) ;;;; Internal Functions (defun mouse-me-buffer-file-extension () "Return the extension of the current buffer's filename or nil. Returned extension is a string beginning with a period." (let* ((bfn (buffer-file-name)) (filename (and bfn (file-name-sans-versions bfn))) (index (and filename (string-match "\\.[^.]*$" filename)))) (if index (substring filename index) ""))) (defun mouse-me-helper (event func) "Determine the string to use to process EVENT and call FUNC to get cmd." (let (name sp sm mouse beg end cmd mmtype) ;; temporarily goto where the event occurred, get the name clicked ;; on and enough info to figure out what to do with it (save-match-data (save-excursion (setq sp (point)) ; saved point (setq sm (mark t)) ; saved mark (set-buffer (window-buffer (posn-window (event-start event)))) (setq mouse (goto-char (posn-point (event-start event)))) ;; if there is a region and point is inside it ;; check for sm first incase (null (mark t)) ;; set name to either the thing they clicked on or region (if (and sm (or (and transient-mark-mode mark-active) (eq last-command 'mouse-drag-region)) (>= mouse (setq beg (min sp sm))) (<= mouse (setq end (max sp sm)))) (setq name (buffer-substring beg end)) (setq name (funcall mouse-me-get-string-function)) (if (listp name) (setq beg (nth 1 name) end (nth 2 name) name (car name)) (goto-char mouse) (while (not (looking-at (regexp-quote name))) (backward-char 1)) (setq beg (point)) (setq end (search-forward name)))))) ;; check if name is null, meaning they clicked on no word (if (or (null name) (and (stringp name) (string= name "" ))) (error "No string to pass to function")) ;; popup a menu to get a command to run (setq cmd (funcall func)) ;; run the command, eval'ing if it was a list (if (listp cmd) (setq cmd (eval cmd t))) (setq mmtype (get cmd 'mouse-me-type)) (cond ((eq mmtype 'region) (funcall cmd beg end)) ((eq mmtype 'string) (funcall cmd name)) (t (funcall cmd name))))) (provide 'mouseme) ;;; mouseme.el ends here ESS-24.01.1/lisp/obsolete/msdos.el000066400000000000000000000143061455642170100165540ustar00rootroot00000000000000;;; msdos.el --- Run an MS-DOS shell in an NTemacs buffer with bash as the shell -*- lexical-binding: t; -*- ;; Copyright (C) 1999-2022 Free Software Foundation, Inc. ;; Author: Richard M. Heiberger ;; Created: February 1999 ;; Maintainer: ESS-core ;; This file is part of GNU Emacs. ;;; License: ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see ;; ;;; Commentary: ;; The file msdos.el in the next mail message opens an *msdos* buffer ;; in shell-mode and msdos-minor-mode. When cmdproxy.exe/command.com ;; is the Emacs shell, then this gets various setting right that M-x ;; shell currently misses. The function M-x msdos-minor-mode could be ;; automatically run by Emacs in shell-mode in that case. ;; When bash is the Emacs shell, msdos.el still opens a ;; cmdproxy.exe/command.com shell in the buffer *msdos*. There are ;; occasions when it is necessary to run DOS character-based programs ;; in an Emacs window. ;; I followed the suggestion by AndrewI to look at M-x shell and modify ;; it. It turns out not to have been trivial. ;;; Code: (require 'shell); and hence 'comint ;;; Customization and Buffer Variables (defcustom explicit-msdos-shell-file-name "cmdproxy.exe" "*If non-nil, is file name to use for explicitly requested msdos inferior shell." :type '(choice (const :tag "None" nil) file) :group 'shell) (defcustom explicit-msdos-comspec-file-name (if (w32-using-nt) "cmd.exe" "command.com") "*If non-nil, is file name to use for explicitly requested COMSPEC environment variable." :type '(choice (const :tag "None" nil) file) :group 'shell) (defvar-local msdos-minor-mode nil "Non-nil if using msdos-minor mode as a minor mode of some other mode.") (defun msdos () "Run an inferior msdos shell, with I/O through buffer *msdos*. This function is intended to be used in an Ntemacs session in which bash is the primary shell. But sometimes an MSDOS window, within emacs, is also needed. If buffer exists but shell process is not running, make new shell. If buffer exists and shell process is running, just switch to buffer `*msdos*'. Program used comes from variable `explicit-msdos-shell-file-name'. If a file `~/.emacs_SHELLNAME' exists, it is given as initial input (Note that this may lose due to a timing error if the shell discards input when it starts up.) The buffer is put in Shell mode, giving commands for sending input and controlling the subjobs of the shell. See `shell-mode'. See also the variable `shell-prompt-pattern'. The buffer is put into \\[msdos-minor-mode]. See `msdos-minor-mode'. The COMSPEC environment variable in the inferior shell, but not in the emacs process, is set to `explicit-msdos-comspec-file-name'. The SHELL environment variable in the inferior shell, but not in the emacs process, is set to `explicit-msdos-shell-file-name'. The shell file name (sans directories) is used to make a symbol name such as `explicit-csh-args'. If that symbol is a variable, its value is used as a list of arguments when invoking the shell. \(Type \\[describe-mode] in the shell buffer for a list of commands.)" (interactive) (if (not (comint-check-proc "*msdos*")) (let* ((prog explicit-msdos-shell-file-name) (name (file-name-nondirectory prog)) (startfile (concat "~/.emacs_" name)) (xargs-name (intern-soft (concat "explicit-" name "-args"))) shell-buffer (comspec (getenv "COMSPEC")) (shell (getenv "SHELL")) ) (save-excursion (setenv "COMSPEC" explicit-msdos-comspec-file-name) (setenv "SHELL" explicit-msdos-shell-file-name) (set-buffer (apply #'make-comint "msdos" prog (if (and xargs-name (boundp xargs-name)) (symbol-value xargs-name)) (if (file-exists-p startfile) (concat "/k " startfile)))) (setenv "COMSPEC" comspec) (setenv "SHELL" shell) (setq shell-buffer (current-buffer)) (shell-mode) (msdos-minor-mode) (sleep-for 4) ; need to wait, else working too fast! ;;; The `exit' warning should precede the "c:\" prompt. ;;; If not, then increase the sleep-for time! (goto-char (point-min)) (insert "Remember to exit this buffer with `exit'. If you kill the buffer without exiting, you may not be able to shut down Windows cleanly.") (goto-char (point-max))) (pop-to-buffer shell-buffer)) (pop-to-buffer "*msdos*"))) (defun msdos-minor-mode () "Minor mode for running msdos in a shell-mode buffer: a. Uses \\[set-buffer-process-coding-system] to set the coding system to `'raw-text-dos'. The DOS C-m C-l end-of-line is critical. The shell freezes without it. b. The variable `comint-completion-addsuffix' is set to `\\' for directories. c. Prevents echoing of commands. d. strips ctrl-m from output. " (interactive) (setq msdos-minor-mode t) (set (make-local-variable 'comint-completion-addsuffix) '("\\" . " ")) (setq comint-process-echoes t) (add-hook 'comint-output-filter-functions #'shell-strip-ctrl-m nil t) (set-process-coding-system (get-buffer-process (current-buffer)) 'raw-text-dos 'raw-text-dos) ;; buffer-process-coding-system is critical. ) ;; Install ourselves: (put 'msdos-minor-mode 'permanent-local t) (or (assq 'msdos-minor-mode minor-mode-alist) (setq minor-mode-alist (append minor-mode-alist (list '(msdos-minor-mode " msdos"))))) ;; Provide ourselves: (provide 'msdos) ;;; msdos.el ends here ESS-24.01.1/targets/000077500000000000000000000000001455642170100137675ustar00rootroot00000000000000ESS-24.01.1/targets/create-pkg-file.el000066400000000000000000000012441455642170100172510ustar00rootroot00000000000000;;; create-pkg-file.el --- Create ess-pkg.el -*- lexical-binding: t; -*- ;; Copyright (C) 2018-2022 Free Software Foundation, Inc. ;;; Commentary: ;; Creates ess-pkg.el (require 'package) ;; This script is called from one directory up ;; Copy lisp into top-level (copy-directory "lisp" "." t t t) (delete-directory "lisp" t nil) ;; Make documentation (shell-command "make -C doc info/ess.info") (dolist (file '("doc/info/ess.info" "doc/info/dir")) (copy-file file (file-name-nondirectory file)) (delete-file file)) ;; Generate ess-pkg.el (find-file "ess.el") (package-generate-description-file (package-buffer-info) "ess-pkg.el") ;;; create-pkg-file.el ends here ESS-24.01.1/targets/travis-install-package.el000066400000000000000000000014141455642170100206560ustar00rootroot00000000000000;;; travis-install-package.el -*- lexical-binding: t; -*- ;; Copyright (C) 2018-2022 Free Software Foundation, Inc. ;;; Commentary: ;; This file simulates a user installing the ess-$VERSION.tar file and ;; then loading ess. It's meant to be used for testing purposes only. ;;; Code: (require 'package) (require 'subr-x) (add-to-list 'package-archives (cons "melpa" "https://melpa.org/packages/") t) (package-initialize) ;; Get julia-mode and install (package-refresh-contents) (package-install 'julia-mode) ;; This file gets called from one directory up (when-let ((file (directory-files default-directory t ".tar$"))) (package-install-file (car file))) (require 'ess-site) ;;; travis-install-package.el ends here ;; Local Variables: ;; no-byte-compile: t ;; End: ESS-24.01.1/test/000077500000000000000000000000001455642170100132755ustar00rootroot00000000000000ESS-24.01.1/test/Makefile000066400000000000000000000014771455642170100147460ustar00rootroot00000000000000 include ../Makeconf .PHONY: literate all julia lisp ess inf org r r-indent literate cases indent-cases literate-cases all: compile lisp julia: @$(MAKE) -C .. julia lisp: julia ${EMACS} -Q --script run-tests ess: ${EMACS} -Q --script run-tests --ess inf: ${EMACS} -Q --script run-tests --inf org: ${EMACS} -Q --script run-tests --org r r-core: ${EMACS} -Q --script run-tests --r-core r-indent: ${EMACS} -Q --script run-tests --r-indent r-pkg: ${EMACS} -Q --script run-tests --r-pkg literate: ${EMACS} -Q --script run-tests --literate cases: indent-cases literate-cases indent-cases: ${EMACS} -Q --script generate-indent-cases literate-cases: ${EMACS} -Q --script generate-literate-cases .PHONY: compile compile: @cd .. && make -k lisp \ "COMPILE-FLAGS = --eval \"(setq byte-compile-error-on-warn t)\"" ESS-24.01.1/test/dummy-pkg/000077500000000000000000000000001455642170100152075ustar00rootroot00000000000000ESS-24.01.1/test/dummy-pkg/DESCRIPTION000066400000000000000000000002501455642170100167120ustar00rootroot00000000000000Package: foo Title: title License: GPL-2 Description: Package description. Author: author Maintainer: maintainer Version: 0.1 ESS-24.01.1/test/dummy-pkg/R/000077500000000000000000000000001455642170100154105ustar00rootroot00000000000000ESS-24.01.1/test/dummy-pkg/R/test.R000066400000000000000000000000241455642170100165060ustar00rootroot00000000000000 ## Test file NULL ESS-24.01.1/test/dummy-pkg/man/000077500000000000000000000000001455642170100157625ustar00rootroot00000000000000ESS-24.01.1/test/dummy-pkg/man/doc.Rd000066400000000000000000000000411455642170100170110ustar00rootroot00000000000000\name{doc} \examples{ letters } ESS-24.01.1/test/dummy-pkg/src/000077500000000000000000000000001455642170100157765ustar00rootroot00000000000000ESS-24.01.1/test/dummy-pkg/src/test.c000066400000000000000000000000001455642170100171070ustar00rootroot00000000000000ESS-24.01.1/test/ess-test-indentation.el000066400000000000000000000123551455642170100177060ustar00rootroot00000000000000;; ess-test-indentation.el --- Tests for ESS indentation -*- lexical-binding: t; -*- ;; ;; Filename: ess-tests.el ;; Created: 07-05-2015 (ESS 15.09) ;; Keywords: tests, indentation ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; This file is *NOT* part of GNU Emacs. ;; This file is part of ESS ;; ;; This program is free software; you can redistribute it and/or ;; modify it under the terms of the GNU General Public License as ;; published by the Free Software Foundation; either version 3, or ;; (at your option) any later version. ;; ;; This file 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. ;; ;; A copy of the GNU General Public License is available at ;; https://www.r-project.org/Licenses/ ;; ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;;; Commentary: ;; ;; To run these tests: ;; All tests: M-x ert t ;; ;; To apply styles for manual testing: ;; M-: (let ((ess-style-alist ess-test-style-alist)) ;; (ess-set-style 'misc1)) ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;;; Code: (require 'ert) (require 'etest "etest/etest") (require 'ess-r-mode) (require 'ess-test-r-utils) ;;; Indentation tests (defvar ess-test-style-alist `((RRR ,@(cdr (assq 'RRR ess-style-alist))) (RRR+ ,@(cdr (assq 'RRR+ ess-style-alist))) (RStudio- ,@(cdr (assq 'RStudio- ess-style-alist))) (C++ ,@(cdr (assq 'C++ ess-style-alist))) (DEFAULT ,@(cdr (assq 'DEFAULT ess-style-alist))) (misc1 (ess-indent-offset . 3) (ess-offset-block . open-delim) (ess-offset-arguments . (prev-call 5)) (ess-offset-arguments-newline . open-delim) (ess-offset-continued . cascade) (ess-align-nested-calls . ("ifelse")) (ess-align-arguments-in-calls . nil) (ess-align-continuations-in-calls . nil) (ess-align-blocks . (fun-decl bare-blocks)) (ess-indent-from-lhs . nil) (ess-indent-from-chain-start . nil) (ess-indent-with-fancy-comments . t)))) (defun ess-test-get-pos-from-undo-elt (e) "If E represents an edit, return a position value in E, the position where the edit took place. Return nil if E represents no real change. \nE is an entry in the buffer-undo-list." ;; stolen from goto-chg.el (cond ;; ((numberp e) e) ; num==changed position ;; ((atom e) nil) ; nil==command boundary ((numberp (car e)) (cdr e)) ; (beg . end)==insertion ((stringp (car e)) (abs (cdr e))) ; (string . pos)==deletion ;; ((null (car e)) (nthcdr 4 e)) ; (nil ...)==text property change ;; ((atom (car e)) nil) ; (t ...)==file modification time (t nil))) ; (marker ...)==marker moved (defun not-change-on-indent (buffer) "Return t if BUFFER wasn't modified on indent." (with-current-buffer buffer (setq buffer-undo-list nil) (indent-region (point-min) (point-max)) (if (buffer-modified-p buffer) (progn (switch-to-buffer buffer) nil) t))) (defun ess-test-explain-change-on-indent (buffer) "Explainer function for `not-change-on-indent'." (when (buffer-modified-p buffer) (with-current-buffer buffer (let ((bul buffer-undo-list) (change-pos (point-min))) (while (and bul (null (setq change-pos (ess-test-get-pos-from-undo-elt (car bul))))) (pop bul)) (let ((diff-file (concat (buffer-name) ".diff"))) (diff-buffer-with-file buffer) (with-current-buffer "*Diff*" (write-region (point-min) (point-max) diff-file)) `(,(buffer-name buffer) was modified on line ,(count-lines 1 change-pos) (diff was written to ,diff-file))))))) (put 'not-change-on-indent 'ert-explainer 'ess-test-explain-change-on-indent) ;; Don't overwrite user settings (#911). (ert-deftest ess-r-no-user-style-overwrite-test () (let ((ess-style 'RRR) (ess-r-mode-hook '((lambda () (setq-local ess-indent-offset 1))))) (with-temp-buffer (ess-r-mode) (should (eq ess-indent-offset 1)) (ess-set-style) (should (eq ess-indent-offset 1)) (ess-set-style 'C++) (should (eq ess-indent-offset 4))))) (ert-deftest test-ess-R-indentation-RRR () (ess-test-R-indentation "styles/RRR.R" 'RRR)) (ert-deftest test-ess-R-indentation-RRR+ () (ess-test-R-indentation "styles/RRR+.R" 'RRR+)) (ert-deftest test-ess-R-indentation-RStudio- () (ess-test-R-indentation "styles/RStudio-.R" 'RStudio-)) (ert-deftest test-ess-R-indentation-C++ () (ess-test-R-indentation "styles/C++.R" 'C++)) (ert-deftest test-ess-R-indentation-misc1 () (ess-test-R-indentation "styles/misc1.R" 'misc1)) (etest-deftest test-ess-indent-exp () :case " { fun¶_call( argument ) + stuff1 } + stuff2 " ;; Bound to `ess-indent-exp' "C-M-q" :result " { fun¶_call( argument ) + stuff1 } + stuff2 " :case reset "C-u" "C-M-q" :result " { fun¶_call( argument ) + stuff1 } + stuff2 ") (provide 'ess-test-indentation) ;; Local Variables: ;; etest-local-config: etest-r-config ;; End: ;;; ess-test-indentation.el ends here ESS-24.01.1/test/ess-test-inf.el000066400000000000000000000604101455642170100161410ustar00rootroot00000000000000;;; ess-test-inf.el --- ESS tests for inferiors -*- lexical-binding: t; -*- ;; ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; ;; This file 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. ;; ;; A copy of the GNU General Public License is available at ;; https://www.r-project.org/Licenses/ ;; ;;; Commentary: ;; Tests for inferior processes. (require 'ert) (require 'etest "etest/etest") (require 'cl-lib) ;; As we use the R inferior for the generic tests (require 'ess-test-r-utils) ;;*;; Startup (defun ess-r-tests-startup-output () (let ((inf-buf (run-ess-test-r-vanilla))) (ess-test-unwind-protect inf-buf (with-current-buffer inf-buf (buffer-string))))) (ert-deftest ess-startup-verbose-setwd-test () (should (string-match "to quit R.\n\n> setwd(.*)$" (ess-r-tests-startup-output)))) (ert-deftest ess-startup-default-directory-preserved-test () (let ((default-directory user-emacs-directory) (ess-startup-directory temporary-file-directory) ess-ask-for-ess-directory) (ess-test-with-r-running nil (should (string= default-directory user-emacs-directory)) (should (string= (inferior-ess-default-directory) temporary-file-directory))) (should (string= default-directory user-emacs-directory)))) (ert-deftest ess-test-inferior-live-process-error () (let* ((ess-gen-proc-buffer-name-function ;; Generate same inferior name each time (lambda (&rest _) "" "foo")) (error-msg "Can't start a new session in buffer `foo` because one already exists") (inf-buf (run-ess-test-r-vanilla))) (ess-test-unwind-protect inf-buf (should (string= (cadr (should-error (run-ess-test-r-vanilla))) (format-message error-msg)))))) (ert-deftest ess-test-inferior-local-start-args () (ess-test-with-r-running nil (let ((inf-data (buffer-local-value 'inferior-ess--local-data (process-buffer *proc*)))) (should (equal (car inf-data) "R")) (should (equal (cdr inf-data) "--no-readline --no-init-file --no-site-file"))))) (ert-deftest ess-test-inferior-reload-start-data () (let* ((r-path (executable-find "R")) (inferior-ess-r-program r-path) (inf-buf (run-ess-test-r-vanilla))) (ess-test-unwind-protect inf-buf (let ((inf-data (buffer-local-value 'inferior-ess--local-data inf-buf))) (should (equal (car inf-data) r-path)) (should (equal (cdr inf-data) "--no-readline --no-init-file --no-site-file")))))) ;;*;; Evaluation (etest-deftest ess-command-test () "`ess-command' saves output in specified buffer." (let ((output-buffer (get-buffer-create " *ess-test-command-output*"))) (ess-command "identity(TRUE)\n" output-buffer) (should (string= (with-current-buffer output-buffer (ess-kill-last-line) (buffer-string)) "[1] TRUE"))) ;; No impact on inferior output :inf-result "") (ert-deftest ess-async-command-test () ;; (ess-async-command "{cat(1:5);Sys.sleep(5);cat(2:6)}\n" nil (get-process "R") ;; (lambda (proc) (message "done"))) ;; (ess-async-command "{cat(1:5);Sys.sleep(5);cat(2:6)}\n" nil (get-process "R") ;; (lambda (proc) (message "done")) ;; t) ;; (ess-async-command "{cat(1:5);Sys.sleep(5);cat(2:6)}\n" nil (get-process "R") ;; (lambda (proc) (message "done")) (ess-test-with-r-running nil (let ((inf-proc *proc*) semaphore) (ess-async-command "{cat(1:5);Sys.sleep(0.5);cat(2:6, '\n')}\n" (get-buffer-create " *ess-async-text-command-output*") inf-proc (lambda (&rest _) (setq semaphore t))) (should (process-get inf-proc 'callbacks)) (cl-loop repeat 3 until (and semaphore (null (process-get inf-proc 'callbacks))) do (sleep-for 0 600) finally (should-not (process-get inf-proc 'callbacks)))))) (ert-deftest ess-run-presend-hooks-test () (ess-test-with-r-running nil (let ((ess-presend-filter-functions (list (lambda (_string) "\"bar\"")))) (should (ess-test-output= (ess-send-string (ess-get-process) "\"foo\"") "[1] \"bar\""))))) (ert-deftest ess-load-file-test () (ess-test-with-r-running nil (should (string-match "^\\[1\\] \"foo\"\nSourced file" (ess-test-output nil (ess-load-file (expand-file-name "file.R" ess-test-fixtures-directory))))))) (etest-deftest ess-command-incomplete-test () "`ess-command' fails with incomplete input." (should-error (ess-command "list(" nil nil nil nil nil nil 0.01)) ;; No impact on inferior output :inf-result "" ;; Process has been interrupted, is no longer busy, and we can run a ;; command again (should (inferior-ess-available-p)) (should-error (ess-command "list(" nil nil nil nil nil nil 0.01)) :inf-result "") (etest-deftest ess-command-hanging-test () "`ess-command' fails with hanging command." (should-error (ess-command "Sys.sleep(2)\n" nil nil nil nil nil nil 0.01)) :inf-result "" (should (inferior-ess-available-p))) (defun ess-test--browser () (ess-send-string (ess-get-process) "{ browser(); NULL }\n") (ess-wait-for-process)) (defun ess-test--browser-cleanup () (ess-debug-command-quit) (ess-wait-for-process) (etest-clear-inferior-buffer)) (etest-deftest ess--command-browser-timeout-test () "`ess-command' fails with hanging command within browser (#1081)." :cleanup (ess-test--browser-cleanup) (ess-test--browser) :inf-result "Called from: top level Browse[1]> debug at #1: NULL Browse[1]> " (should-error (ess-command "Sys.sleep(2)\n" nil nil nil nil nil nil 0.01)) ;; No impact on inferior :inf-result "" (should (inferior-ess-available-p)) ;; We're still in the browser (ess-send-string (ess-get-process) "NULL\n") (ess-wait-for-process) :inf-result "NULL Browse[1]> ") (etest-deftest ess--command-browser-unscoped-essr () "`ess-command' when ESSR is not in scope." :cleanup (ess-test--browser-cleanup) (ess-send-string (ess-get-process) "evalq({ browser(); NULL }, baseenv())\n") (ess-test--browser) :inf-result "Called from: evalq({ browser() NULL }, baseenv()) Browse[1]> debug at #1: browser() Browse[3]> Browse[3]> " (should (equal (ess-get-words-from-vector "'foo'\n") '("foo"))) ;; No impact on inferior :inf-result "" (should (inferior-ess-available-p)) ;; We're still in the browser (ess-send-string (ess-get-process) "NULL\n") (ess-wait-for-process) :inf-result "NULL Browse[3]> ") (etest-deftest ess-command-browser-curly-braces () "`{` expressions when debugger is active do not interrupt command." :cleanup (ess-test--browser-cleanup) (ess-test--browser) :inf-result "Called from: top level Browse[1]> debug at #1: NULL Browse[1]> " (should (string= (ess-string-command "{ 1; 2 }\n") "[1] 2")) :inf-result "" (should (inferior-ess-available-p))) (etest-deftest ess-command-environment () "Can access current env with `.ess.environment()`" :cleanup (ess-test--browser-cleanup) (ess-send-string (ess-get-process) "local({ foo <- 1; browser(); NULL })\n") (ess-wait-for-process) (should (string= (ess-string-command "ls(envir = .ess.environment())\n") "[1] \"foo\""))) (etest-deftest ess-command-quit-test () "`ess-command' does not leak output on quit (#794, #842). This is especially important within `while-no-input' used by packages like eldoc and company-quickhelp. `throw-on-input' sets `quit-flag'." ;; Simulate a quit by throwing from a timer (run-at-time 0.1 nil (lambda () (throw 'my-quit 'thrown))) (should (eq (catch 'my-quit (ess-command "{ cat('output\n'); Sys.sleep(10) }\n" nil nil nil nil nil nil 0.5)) 'thrown)) ;; There should be no output after the early exit :inf-result "" (should (inferior-ess-available-p))) (etest-deftest ess-command-quit-async-interrupt-test () "`ess-command' interrupts asynchronously on quits (#1091, #1102). Needed with slow-responding processes." (should (eq (identity (marker-buffer (process-mark (ess-get-process)))) (ess-get-process-buffer))) (run-at-time 0.1 nil (lambda () (throw 'my-quit 'thrown))) (should (eq (catch 'my-quit (ess-command "{ cat('output\n') withCallingHandlers( interrupt = function(...) Sys.sleep(0.2), Sys.sleep(10) ) } " nil nil nil nil nil nil 0.5)) 'thrown)) ;; Wait for the async interrupt (should (ess-wait-for-process (ess-get-process) nil nil 0.5)) ;; Check that marker buffer was properly restored (should (eq (marker-buffer (process-mark (ess-get-process))) (ess-get-process-buffer))) ;; There should be no output after the early exit or async restoration :inf-result "") (etest-deftest ess-command-newlines-test () "`ess-command' doesn't garble new lines (#1110)." (should (string= (ess--strip-final-newlines "1\n2") "1\n2")) (should (equal (ess-get-words-from-vector "{ 'foo'\n'bar'\n }\n") (list "bar")))) (etest-deftest ess-command-multiline-test () "`ess-command' output doesn't include continuation prompts (#1116)." (let ((buf (generate-new-buffer "ess-command-multiline-test"))) (ess-command "{ 1\n 2 }\n" buf) (should (string= (with-current-buffer buf (buffer-string)) "[1] 2")))) (ert-deftest ess--command-output-info-test () ;; No output (with-temp-buffer (insert "baz> ") (should (equal (ess--command-output-info (current-buffer)) (list 1 1 nil)))) ;; Command output and no new output (with-temp-buffer (insert " foo bar baz> ") (should (equal (ess--command-output-info (current-buffer)) (list 1 9 nil)))) ;; Command output and new output (with-temp-buffer (insert " foo bar baz> new output") (should (equal (ess--command-output-info (current-buffer)) (list 1 9 16))))) (ert-deftest ess--command-delimited-output-info-test () ;; No output (with-temp-buffer (insert " my-sentinel-START my-sentinel-END baz> ") (should (equal (ess--command-delimited-output-info (current-buffer) "my-sentinel") (list 20 20 nil)))) ;; Command output and no new output (with-temp-buffer (insert " my-sentinel-START foo bar my-sentinel-END baz> ") (should (equal (ess--command-delimited-output-info (current-buffer) "my-sentinel") (list 20 27 nil)))) ;; Command output and new output (with-temp-buffer (insert " my-sentinel-START foo bar my-sentinel-END baz> new output") (should (equal (ess--command-delimited-output-info (current-buffer) "my-sentinel") (list 20 27 49))))) (etest-deftest command-without-trailing-newline-test () "It is a bug when a command doesn't output a trailing newline. With delimiters it might be possible to figure out the output. However if they are not available then the output is indistinguishable from the prompt." (should-error (ess-command "cat(1)\n")) (ess-wait-for-process) ;; Leaks output after the error but that seems fine since errors in ;; filters are bugs :inf-result " > ") (etest-deftest ess-command-intervening-input-test () "Test that user can send input while command is interrupting (#1119)." (run-at-time 0.1 nil (lambda () (throw 'my-quit 'thrown))) (should (eq (catch 'my-quit (ess-command "{ cat('output\n') withCallingHandlers( interrupt = function(...) Sys.sleep(0.2), Sys.sleep(10) ) } " nil nil nil nil nil nil 0.5)) 'thrown)) ;; Send intervening input right away. Since we wait on the R side ;; on interrupt, the process hasn't been restored yet (ess-send-string (ess-get-process) "cat('foobar\\n')\n") ;; Wait for the async interrupt (should (ess-wait-for-process nil nil nil 0.5)) ;; The output for the intervening input should be shown in the ;; process buffer :inf-result "foobar > ") ;;*;; Inferior interaction (defmacro ess-test-interactive-eval (out-string &rest body) "Evaluate BODY in a temp buffer with `R-mode' on. OUT-STRING is the content of the region captured by `ess-send-region' function." (declare (indent 1) (debug (form body))) `(cl-letf (((symbol-function 'ess-force-buffer-current) #'ignore) ((symbol-function 'ess-get-process) #'ignore) ((symbol-function 'ess-process-get) #'ignore) ((symbol-function 'ess-send-region) (lambda (_ start end &rest _ignore) (should (string= (buffer-substring-no-properties start end) ,out-string))))) (with-temp-buffer (R-mode) ,@body))) (ert-deftest ess-eval-paragraph-test () (let ((inhibit-message ess-inhibit-message-in-tests)) (let ((output "library(bbb)")) (ess-test-interactive-eval output (insert (format "## a comment\n\n%s\n\nmore_code4" output)) (goto-char (point-min)) (search-forward "lib") (ess-eval-paragraph) (should (looking-at-p "rary")) (ess-eval-region-or-function-or-paragraph) (should (looking-at-p "rary")))))) (ert-deftest ess-eval-and-step-test () (let ((inhibit-message ess-inhibit-message-in-tests)) (let ((output "real <- code")) (ess-test-interactive-eval output (insert (format "## comment\n\n%s" output)) (forward-line -1) (ess-eval-region-or-function-or-paragraph-and-step))) (let ((output "xyz <- function () {\n}")) (ess-test-interactive-eval output (insert (format "## comment\n\n%s" output)) (goto-char (point-min)) (forward-line 1) (ess-eval-region-or-function-or-paragraph-and-step))) (let ((output "xyz <- function () {\n}")) (ess-test-interactive-eval output (insert (format "## comment\n%s\nsome_code\n\nmore_code" output)) (goto-char (point-min)) (forward-line 1) (ess-eval-region-or-function-or-paragraph-and-step) (should (looking-at-p "some_code")))) (let ((output "a <- 1\nb <- 2")) (ess-test-interactive-eval output (insert (format "%s\n\nmore_code1()" output)) (goto-char (point-min)) (ess-eval-region-or-function-or-paragraph-and-step) (should (looking-at-p "more_code1")))) (let ((output "a <- 1\nb <- 2")) (ess-test-interactive-eval output (insert (format "%s\n\nmore_code2()" output)) (goto-char (point-min)) (ess-eval-region-or-function-or-paragraph-and-step) (should (looking-at-p "more_code2")))) (let ((output "library(aaaa)")) (ess-test-interactive-eval output (insert (format "%s\n\nmore_code3\n" output)) (goto-char (point-min)) (ess-eval-region-or-function-or-paragraph-and-step) (should (looking-at-p "more_code3")))) (let ((output "library(bbb)")) (ess-test-interactive-eval output (insert (format "## a comment\n\n%s\n\nmore_code4" output)) (goto-char (point-min)) (ess-eval-region-or-function-or-paragraph-and-step) (should (looking-at-p "more_code4")))) )) (ert-deftest ess-setwd-test () (ess-test-with-r-running nil ;; Working directory is set verbosely (should (ess-test-output= (ess-set-working-directory temporary-file-directory) (format "setwd('%s')" temporary-file-directory))) ;; Update process default-directory but not caller's buffer (let* ((cur-dir default-directory) (temp-dir (file-name-as-directory (make-temp-file "setwd-dir" t)))) (unwind-protect (progn (setq default-directory temp-dir) (ess-set-working-directory temporary-file-directory) (should (equal default-directory temp-dir)) (should (equal (ess-get-process-variable 'default-directory) temporary-file-directory)) (ess-set-working-directory temp-dir) (should (equal (ess-get-process-variable 'default-directory) temp-dir))) (setq default-directory cur-dir))))) ;;*;; Sending input (ert-deftest ess-inf-send-input-invisible-test () (let ((ess-eval-visibly nil)) (should (string= "> " (ess-send-input-to-R "\n\n"))) (should (string= "> " (ess-send-input-to-R "invisible(0)"))) (should (string= "invisible(0)\n> " (ess-send-input-to-R "invisible(0)" 'repl))))) (ert-deftest ess-inf-send-complex-input-test () (let ((ess-eval-visibly nil) (inferior-ess-fix-misaligned-output t) (input "identity( identity( identity( head(mtcars[, c('wt', 'vs')], 3)))) '+ + + + > some-output >' cat('+ + + + > cleaned-prompts >\n') ") (output "> wt vs Mazda RX4 2.620 0 Mazda RX4 Wag 2.875 0 Datsun 710 2.320 1 > [1] \"+ + + + > some-output >\" > cleaned-prompts > > ")) (let ((inferior-ess-replace-long+ t)) (should (string= output (ess-send-input-to-R input)))))) (ert-deftest ess-inf-send-fn-test () (let ((input "fn <- function() { } ") (output "> ") ;; (output-nowait "> fn <- function() { ;; + } ;; > ") ) (let ((inferior-ess-replace-long+ t)) (let ((ess-eval-visibly nil)) (should (string= output (ess-send-input-to-R input 'c-c)))) ;;; this fails randomly in batch ;; (let ((ess-eval-visibly 'nowait)) ;; (should (string= output-nowait ;; (ess-send-input-to-R input 'c-c)))) ))) (ert-deftest ess-inf-send-cat-some.text-test () (let ((inferior-ess-fix-misaligned-output t) (input "cat(\"some. text\\n\") head(cars, 2) ") (output "some. text > speed dist 1 4 2 2 4 10 > ") ;; (output-nowait "cat(\"some. text\\n\") ;; + head(cars, 2) ;; some. text ;; > ;; speed dist ;; 1 4 2 ;; 2 4 10 ;; > ") ) (let ((inferior-ess-replace-long+ t)) ;; Can't figure out why this has changed ;; (let ((ess-eval-visibly nil)) ;; (should (string= output ;; (ess-send-input-to-R input 'c-c)))) ;; these test fails randomly in batch ;; (let ((ess-eval-visibly 'nowait)) ;; (should (string= output-nowait ;; (ess-send-input-to-R input 'c-c)))) ))) ;;*;; Help (etest-deftest ess-help-aliases-test () (let ((aliases (ess-get-help-aliases-list))) (should (member "list" aliases))) :inf-result "" (ess-help--reset-cache) (let ((aliases (ess-get-help-aliases-list))) (should (member "list" aliases)))) ;;*;; Inferior utils (ert-deftest ess-build-eval-command-test () (should (not (ess-build-eval-command "command()"))) (let ((ess-eval-command "%s - %f")) (should (string= (ess-build-eval-command "command(\"string\")" nil nil "file") "command(\\\"string\\\") - file")))) (ert-deftest ess-build-load-command-test () (let ((ess-dialect nil)) (should (string= (ess-build-load-command "file") "source('file')\n")))) (ert-deftest ess-get-words-from-vector-test () (ess-test-with-r-running nil (should (cl-every #'string= (ess-get-words-from-vector "c('1')\n") '("1"))) (should (cl-every #'string= (ess-get-words-from-vector "c('1', \"2\")\n") '("1" "2"))) (should (cl-every #'string= (ess-get-words-from-vector "c('aaa','bbb\"ccc', 'dddd')\n") '("aaa" "bbb\\\"ccc" "dddd"))))) (ert-deftest ess--derive-connection-path () (let* ((old-localname "/path/to/file") (new-localname "/home/username/projects") (connection-basic "/ssh:melancholia.danann.net:") (connection-ip4 "/ssh:10.0.1.213:") (connection-ip6 "/ssh:[::1]:") (connection-user "/scp:user@host:") (connection-port "/ssh:daniel@melancholia#42:") (connection-domain "/smb:daniel%BIZARRE@melancholia:") (connection-hop "/ssh:bird@bastion|ssh:news.my.domain:") (make-check-replacement (lambda (new-connection) (lambda (old-connection) (let ((old-path (concat old-connection old-localname)) (new-path (concat new-connection new-localname))) (string= (ess--derive-connection-path old-path new-path) (concat old-connection new-localname)))))) (check-new-localpath (funcall make-check-replacement "")) (check-new-remotepath (funcall make-check-replacement connection-basic))) (should (funcall check-new-localpath "")) (should (funcall check-new-localpath connection-basic)) (should (funcall check-new-localpath connection-ip4)) (should (funcall check-new-localpath connection-ip6)) (should (funcall check-new-localpath connection-user)) (should (funcall check-new-localpath connection-port)) (should (funcall check-new-localpath connection-domain)) (should (funcall check-new-localpath connection-hop)) (should (funcall check-new-remotepath "")) (should (funcall check-new-remotepath connection-basic)))) ;; Test runners ;; Note that we add R-3.2.1 to continuous integration via a symlink to ;; the actual R binary. These tests will likely fail locally for you ;; unless you have R-3.2.1 somewhere on `exec-path' when ESS was first ;; loaded. They're skipped unless you've defined the environment ;; variable CONTINUOUS_INTEGRATION or R-3.2.1 is found by ;; `executable-find'. (ert-deftest runner-R-3.2.1-defined-test () (skip-unless (or (executable-find "R-3.2.1") (getenv "CONTINUOUS_INTEGRATION"))) (should (fboundp 'R-3.2.1))) (ert-deftest runner-R-3.2.1-buffer-name-test () (skip-unless (and (or (executable-find "R-3.2.1") (getenv "CONTINUOUS_INTEGRATION")) (> emacs-major-version 25))) (let ((ess-use-inferior-program-in-buffer-name t) (ess-plain-first-buffername nil) (ess-gen-proc-buffer-name-function #'ess-gen-proc-buffer-name:simple) (ess-ask-for-ess-directory nil) (inhibit-message ess-inhibit-message-in-tests)) (let ((inf-buf (R-3.2.1))) (ess-test-unwind-protect inf-buf (with-current-buffer inf-buf (should (string= (buffer-name) "*R-3.2.1:1*"))) (let ((other-inf-buf (R-3.2.1))) (ess-test-unwind-protect other-inf-buf (with-current-buffer other-inf-buf (should (string= (buffer-name) "*R-3.2.1:2*"))))))))) (ert-deftest ess-switch-to-inferior-or-script-buffer-test () (ess-test-with-r-running nil (should (derived-mode-p 'ess-mode)) (ess-switch-to-inferior-or-script-buffer nil) (should (derived-mode-p 'inferior-ess-mode)))) (ert-deftest ess-debugger-init-test () (let ((inhibit-message t) ess-ask-for-ess-directory) (when-let* ((cmd (or (executable-find "lldb") (executable-find "gdb"))) (inf-buf (run-ess-r (format "-d %s" cmd)))) (with-current-buffer inf-buf (should (ess-wait-for-process (ess-get-process) nil 5)) (when (eq system-type 'darwin) ;; `ess-get-words-from-vectors' doesn't work with echoes ;; https://github.com/Homebrew/homebrew-core/issues/127339 (ert-skip "Skipping on macOS because lldb causes echo")) (should (equal (ess-get-words-from-vector "'a'\n") (list "a"))))))) (provide 'ess-test-inf) ;; Local Variables: ;; etest-local-config: etest-r-config ;; End: ;;; ess-test-inf.el ends here ESS-24.01.1/test/ess-test-org.el000066400000000000000000000047301455642170100161570ustar00rootroot00000000000000;; ess-test-org.el --- Test for org-babel integration -*- lexical-binding: t -*- ;; ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; ;; This file 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. ;; ;; A copy of the GNU General Public License is available at ;; https://www.r-project.org/Licenses/ ;; ;;; Commentary: ;; Tests for org babel functionality. ;;; Code: (require 'ert) (require 'ess-r-mode) (require 'ess-test-r-utils) (require 'ob-R) ;; ob-R let-binds `ess-local-process-name' to the process of the ;; session buffer. This session buffer is set to `*R*` by default. It ;; is safer to pass a dedicated inferior buffer as `:session' keyword (defun test-org-R-output (expect input) (declare (indent 1)) (let* ((inf-buf (run-ess-test-r-vanilla))) (setq input (format input (buffer-name inf-buf))) (ess-test-unwind-protect inf-buf (with-current-buffer (get-buffer-create "*ess-org-test*") (let ((org-confirm-babel-evaluate nil) (ess-ask-for-ess-directory nil) (inhibit-message ess-inhibit-message-in-tests)) (erase-buffer) (insert input) (org-mode) (goto-char (point-min)) (forward-line 1) (org-ctrl-c-ctrl-c) (goto-char (point-max)) (should (re-search-backward expect nil t))))))) (ert-deftest test-org-ob-R-output-test () (test-org-R-output "hello" "#+BEGIN_SRC R :results output\n \"hello\"\n#+END_SRC")) (ert-deftest test-org-ob-R-session-output-test () (test-org-R-output "hello" "#+BEGIN_SRC R :session %s :results output\n \"hello\"\n#+END_SRC")) (ert-deftest test-org-ob-R-value-test () (test-org-R-output "hello" "#+BEGIN_SRC R :results value\n \"hello\"\n#+END_SRC")) (ert-deftest test-org-ob-R-session-value-test () (test-org-R-output "hello" "#+BEGIN_SRC R :session %s :results value\n \"hello\"\n#+END_SRC")) (ert-deftest test-org-ob-R-data-frame-test () (test-org-R-output "| 3 | c |" "#+BEGIN_SRC R :session :results value :colnames yes\n data.frame(x=1:3, y=c(\"a\",\"b\",\"c\"))\n#+END_SRC")) (provide 'ess-test-org) ;;; ess-test-org.el ends here ESS-24.01.1/test/ess-test-r-edit.el000066400000000000000000000136001455642170100165500ustar00rootroot00000000000000;;; ess-test-r-edit.el --- ESS tests for R editing -*- lexical-binding: t; -*- ;; ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; ;; This file 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. ;; ;; A copy of the GNU General Public License is available at ;; https://www.r-project.org/Licenses/ ;; ;;; Commentary: ;; (require 'ert) (require 'etest "etest/etest") (require 'ess-r-mode) (require 'ess-test-r-utils) (defun ess-test-init-insert-assign () (let ((map (make-sparse-keymap))) (define-key map "_" #'ess-insert-assign) (use-local-map map))) (etest-deftest test-ess-r-edit-keybindings-smart-assign () (define-key ess-mode-map "_" #'ess-insert-assign) :case "foo¶" "_" :result "foo <- ¶" "_" :result "foo_¶" "_" :result "foo_ <- ¶" (define-key ess-mode-map ";" #'ess-insert-assign) :case "foo¶" ";" :result "foo <- ¶" ";" :result "foo;¶" ";" :result "foo; <- ¶" ;; With `nil` smart key (setq ess-smart-S-assign-key nil) :case "foo¶" ";" :result "foo <- ¶" ";" :result "foo;¶" (define-key ess-mode-map ";" nil) ; Reset (setq ess-smart-S-assign-key "_") ; Reset ";" :result "foo;;¶" ;; With complex key (let ((map (make-sparse-keymap))) (define-key map (kbd "M--") #'ess-insert-assign) (use-local-map map)) :case "foo¶" "M--" :result "foo <- ¶" "M--" :result "foo-¶") (etest-deftest test-ess-r-edit-keybindings-assign-list () "`ess-insert-assign` uses `ess-assign-list`." (local-set-key "_" #'ess-insert-assign) (setq-local ess-assign-list '(" <~ ")) :case "foo¶" "_" :result "foo <~ ¶" "_" :result "foo_¶" "_" :result "foo_ <~ ¶") (etest-deftest test-ess-r-edit-insert-assign () "Repeated calls cycle between assignment and self-insert." :init ((eval . (ess-test-init-insert-assign))) :case "foo¶" "_" :result "foo <- ¶" "_" :result "foo_¶" "_" :result "foo_ <- ¶") (etest-deftest test-ess-r-edit-insert-assign-whitespace () "Whitespace is cleaned up before insertion." :init ((eval . (ess-test-init-insert-assign))) :case "foo ¶" "_" :result "foo <- ¶" :case "foo ¶" "_" :result "foo <- ¶") (etest-deftest test-ess-r-edit-cycle-assign-test () "Repeated calls cycle trough assignment operators." :case "foo¶" "C-c C-=" :result "foo <- ¶" "C-c C-=" :result "foo <<- ¶" "C-c C-=" :result "foo = ¶" "C-c C-=" :result "foo -> ¶" "C-c C-=" :result "foo ->> ¶" "C-c C-=" :result "foo <- ¶" "C-c C-=" :result "foo <<- ¶") (etest-deftest test-ess-r-edit-cycle-assign-whitespace-test () "Whitespace is cleaned up before insertion" :case "foo ¶" "C-c C-=" :result "foo <- ¶" "C-c C-=" :result "foo <<- ¶" :case "foo ¶" "C-c C-=" :result "foo <- ¶" "C-c C-=" :result "foo <<- ¶") "\nfun_call(¶argument1,\n argument2,\n argument3,\n argument4,\n argument5)" "\nfun_call(¶\n argument1,\n argument2,\n argument3,\n argument4,\n argument5\n)" (etest-deftest test-ess-r-edit-call-filling () "With point in front of parentheses." (setq-local fill-column 40) :case " fun_call(¶argument1, argument2, argument3, argument4, argument5)" "M-q" :result " fun_call(¶argument1, argument2, argument3, argument4, argument5)" "M-q" :result " fun_call(¶argument1, argument2, argument3, argument4, argument5)" "M-q" :result " fun_call(¶argument1, argument2, argument3, argument4, argument5)" "M-q" :result " fun_call(¶argument1, argument2, argument3, argument4, argument5)") (etest-deftest test-ess-r-edit-call-filling-middle () "With point in the middle of the function symbol." (setq-local fill-column 40) :case " fun¶_call(argument1, argument2, argument3, argument4, argument5)" "M-q" :result " fun¶_call(argument1, argument2, argument3, argument4, argument5)") (etest-deftest test-ess-r-edit-call-filling-before-comment () "If a comment is in the way we can't do anything." :case " fun_call(¶ ## comment argument1, ## comment argument2)" "M-q" :result " fun_call(¶ ## comment argument1, ## comment argument2)") (etest-deftest test-ess-r-edit-call-filling-multiline-param () :case " ¶fun_call(parameter = 'string')" "M-q" :result " ¶fun_call(parameter = 'string')") (etest-deftest test-ess-r-edit-call-filling-john-doe () "Not sure what this is testing." :case " `fun_call`(¶argument1, argument2)" "M-q" "M-q" :result " `fun_call`(¶argument1, argument2)") (etest-deftest test-ess-r-edit-call-filling-empty-arguments () (setq-local fill-column 42) :case " fun_call¶(argument1, , arg2, , argument3, , argument4)" "M-q" :result " fun_call¶(argument1, , arg2, , argument3, , argument4)" "M-q" :result " fun_call¶(argument1, , arg2, , argument3, , argument4)") (etest-deftest test-ess-r-edit-ops-filling () :case " lm(outcome¶ ~ pred1 + pred2 + pred3 + pred4, data)" "M-q" :result " lm(outcome¶ ~ pred1 + pred2 + pred3 + pred4, data)" "M-q" :result " lm(outcome¶ ~ pred1 + pred2 + pred3 + pred4, data)" "M-q" :result " lm(outcome¶ ~ pred1 + pred2 + pred3 + pred4, data)") (etest-deftest test-ess-r-edit-ops-filling-no-rhs () :case "fun_call(¶argument +)" "M-q" :result "fun_call(¶argument +)") ;; Local Variables: ;; etest-local-config: etest-r-config ;; End: ESS-24.01.1/test/ess-test-r-eval.el000066400000000000000000000127141455642170100165570ustar00rootroot00000000000000;;; ess-test-rd.el --- ESS tests for Rd-mode -*- lexical-binding: t; -*- ;; ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; ;; This file 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. ;; ;; A copy of the GNU General Public License is available at ;; https://www.r-project.org/Licenses/ ;; ;;; Commentary: ;; (require 'ert) (require 'etest "etest/etest") (require 'ess-r-mode) (require 'ess-test-r-utils) ;; Make sure inferiors have been loaded so that messages etc. do not ;; interfere with the tests (ess-r-test-proc-buf 'output) (ess-r-test-proc-buf 'tracebug) (etest-deftest ess-r-eval-visibility-eval-standard-filter-test () "`ess-eval-region' respects `ess-eval-visibly'. Standard filter." :init ((mode . r) (ess-eval-deactivate-mark . nil) (eval . (ess-test-r-set-local-process 'output))) :case " ¶1 2 { 3 4 } 5; 6Ă— " (setq-local ess-eval-visibly t) "C-c C-r" :inf-result "1 [1] 1 > 2 [1] 2 > { + 3 + 4 + } [1] 4 > 5; 6 [1] 5 [1] 6 > " (setq-local ess-eval-visibly 'nowait) "C-c C-r" :inf-result "1 + 2 + { + 3 + 4 + } + 5; 6 [1] 1 > [1] 2 > + + + [1] 4 > [1] 5 [1] 6 > " (setq-local ess-eval-visibly nil) "C-c C-r" :inf-result "[1] 1 > [1] 2 > + + + [1] 4 > [1] 5 [1] 6 > ") (etest-deftest ess-r-eval-visibility-eval-test () "`ess-eval-region' respects `ess-eval-visibly'. Default filter" :init ((mode . r) (eval . (ess-test-r-set-local-process 'tracebug)) (ess-eval-deactivate-mark . nil)) :case " ¶1 2 { 3 4 } 5; 6Ă— " ;; 'nowait curiously causes sporadic failures with the { block ;; output. The number of continuation `+` varies. The chance of ;; failure increases when input has already been sent to the ;; process. Probably because of the special `nowait` handling in the ;; tracebug filter. ;; (setq-local ess-eval-visibly 'nowait) ;; "C-c C-r" ;; :inf-result "1 ;; + 2 ;; + { ;; + 3 ;; + 4 ;; + } ;; + 5; 6 ;; [1] 1 ;; > [1] 2 ;; > + + + [1] 4 ;; > [1] 5 ;; [1] 6 ;; > " (setq-local ess-eval-visibly t) "C-c C-r" :inf-result "1 [1] 1 > 2 [1] 2 > { + 3 + 4 + } [1] 4 > 5; 6 [1] 5 [1] 6 > " (setq-local ess-eval-visibly nil) "C-c C-r" :inf-result "[1] 1 > [1] 2 > + + + [1] 4 > [1] 5 [1] 6 > ") (etest-deftest ess-r-eval-ns-env-roxy-standard-test () "Roxygen blocks are not evaluated in current eval-env (#1026). Standard filter." :init ((mode . r) (ess-r-evaluation-env . "base") (eval . (ess-test-r-set-local-process 'output))) :case "#' ¶identical(environment(), globalenv())" "C-c C-j" :inf-result "identical(environment(), globalenv()) [1] TRUE > " ;; Shouldn't mention "[base]" :messages "Starting evaluation... Loading line: #' identical(environment(), globalenv())" :case " #' ¶identical(environment(), globalenv()) NULLĂ—" "C-c C-r" :inf-result "+ > identical(environment(), globalenv()) [1] FALSE > NULL NULL > " ;; Mentions "[base]" :messages "Starting evaluation... [base] Eval region") (etest-deftest ess-r-eval-ns-env-roxy-tracebug-test () "Roxygen blocks are not evaluated in current eval-env (#1026). Tracebug filter." :init ((mode . r) (eval . (ess-test-r-set-local-process 'tracebug)) (ess-r-evaluation-env . "base") (ess-eval-visibly . nil)) :case "#' ¶identical(environment(), globalenv())" "C-c C-j" :inf-result "[1] TRUE > " ;; Shouldn't mention "[base]" :messages "Starting evaluation... Loading line: #' identical(environment(), globalenv())" :case " #' ¶identical(environment(), globalenv()) NULLĂ—" "C-c C-r" :inf-result "+ [1] FALSE NULL > " ;; Mentions "[base]" :messages "Starting evaluation... [base] Eval region") (ert-deftest ess-rd-eval-ns-env-test () "Namespaced eval is disabled in doc files (#1026)." (with-temp-buffer (find-file-noselect "dummy-pkg/man/doc.Rd") (Rd-mode) (should (not ess-r-evaluation-env)))) (etest-deftest ess-r-eval-sink-freeze-test () "Completions don't freeze Emacs when output is sinked. TODO: Install company-mode dependency in CI." :init ((mode . r) (eval ess-test-r-set-local-process)) :inf-cleanup (process-send-string ess-local-process-name "if (sink.number() != 0) sink(NULL)\n") :case " ¶file <- tempfile() sink(file)Ă—" (setq-local ess-eval-visibly t) "C-c C-r" :inf-result "file <- tempfile() > sink(file) > " (should (equal (ess-get-words-from-vector "letters[1:3]\n") '("a" "b" "c"))) :inf-result "" :case "si¶" (when (require 'company nil 'noerror) (company-complete-common)) :inf-result "" :case "¶{ sink(NULL) if (length(readLines(file))) stop('sinked output should be empty') unlink(file) rm(file) }Ă—" (setq-local ess-eval-visibly nil) "C-c C-r" :inf-result "+ + + + + + > ") (etest-deftest ess-string-command-test () "`ess-string-command` handles multiline outputs (#922)." (should (string= (ess-string-command "quote({ 1 })\n") "{\n 1\n}")) (should (string= (ess-string-command "list(1)\n") "[[1]]\n[1] 1\n"))) ;; Local Variables: ;; etest-local-config: etest-r-config ;; End: ESS-24.01.1/test/ess-test-r-fontification.el000066400000000000000000000200471455642170100204620ustar00rootroot00000000000000;;; ess-test-r-fontification.el --- ESS tests for R fontification -*- lexical-binding: t; -*- ;; ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; ;; This file 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. ;; ;; A copy of the GNU General Public License is available at ;; https://www.r-project.org/Licenses/ ;; ;;; Commentary: ;; (require 'ert) (require 'etest "etest/etest") (require 'ess-r-mode) (require 'ess-test-r-utils) (defmacro with-ess-toggled-font-lock-keyword (enable keywords &rest body) (declare (indent 2) (debug (&rest form))) `(progn (let* ((enable ,enable) (keywords ,keywords) (keywords (if (listp keywords) keywords (list keywords))) toggled) (mapc (lambda (kw) (if (not (eq enable (cdr (assq kw ess-R-font-lock-keywords)))) (progn (ess-font-lock-toggle-keyword kw) (push kw toggled)))) keywords) ,@body (mapc #'ess-font-lock-toggle-keyword toggled)))) (defmacro with-ess-disabled-font-lock-keyword (keywords &rest body) (declare (indent 1) (debug (&rest form))) `(with-ess-toggled-font-lock-keyword nil ,keywords ,@body)) (defmacro with-ess-enabled-font-lock-keyword (keywords &rest body) (declare (indent 1) (debug (&rest form))) `(with-ess-toggled-font-lock-keyword t ,keywords ,@body)) (etest-deftest ess-test-r-fontification-keywords-bare-fn-test () "Function-like keywords without parentheses are not fontified." :case " ¶while ¶for ¶if ¶switch ¶function ¶return ¶on.exit ¶stop ¶tryCatch ¶withRestarts ¶invokeRestart ¶recover ¶browser ¶message ¶warning ¶signalCondition ¶withCallingHandlers " (should (not (face-at-point)))) (etest-deftest ess-test-r-fontification-keywords-fn-test () "Function-like keywords with parentheses are fontified." :case " ¶while() ¶for() ¶if() ¶function() ¶switch() ¶return() ¶on.exit() ¶stop() ¶tryCatch() ¶withRestarts() ¶invokeRestart() ¶recover() ¶browser() ¶.Defunct() " (should (eq (face-at-point) 'ess-keyword-face)) (ess-forward-sexp) :result " while¶() for¶() if¶() function¶() switch¶() return¶() on.exit¶() stop¶() tryCatch¶() withRestarts¶() invokeRestart¶() recover¶() browser¶() .Defunct¶() " (should (not (face-at-point))) ;; Weak keywords :case " ¶message() ¶warning() ¶signalCondition() ¶withCallingHandlers() ¶.Deprecated() " (should (eq (face-at-point) 'ess-modifiers-face)) (ess-forward-sexp) :result " message¶() warning¶() signalCondition¶() withCallingHandlers¶() .Deprecated¶() " (should (not (face-at-point)))) (etest-deftest ess-test-r-fontification-keywords-simple-test () "Simple keywords are always fontified." :case "¶else ¶break ¶next ¶repeat" (should (eq (face-at-point) 'ess-keyword-face))) (etest-deftest ess-test-r-fontification-keywords-in-test () "`in` is fontified only inside `for ()`." :case "for (foo ¶in bar) {}" (should (eq (face-at-point) 'ess-keyword-face)) :case "for foo ¶in bar {}" (should (not (face-at-point)))) (etest-deftest ess-test-r-fontification-keywords-modifiers-test () "Search list modifiers are fontified only if in function position" :case "¶library ¶attach ¶detach ¶source ¶require" (should (not (face-at-point))) :case "¶library() ¶attach() ¶detach() ¶source() ¶require()" (should (eq (face-at-point) 'ess-modifiers-face)) (forward-word) :result "library¶() attach¶() detach¶() source¶() require¶()" (should (not (face-at-point)))) (etest-deftest ess-test-r-fontification-keywords-assignment-operators-test () :case "foo¶ <- foo¶ <<- foo¶ -> foo¶ ->> foo" (should (not (face-at-point))) (forward-char) :result "foo ¶<- foo ¶<<- foo ¶-> foo ¶->> foo" (should (eq (face-at-point) 'ess-assignment-face)) (skip-syntax-forward ".") :result "foo <-¶ foo <<-¶ foo ->¶ foo ->>¶ foo" (should (not (face-at-point)))) (etest-deftest ess-test-r-fontification-keywords-constants-test () :case " ¶TRUE ¶FALSE ¶NA ¶NULL ¶Inf ¶NaN ¶NA_integer_ ¶NA_real_ ¶NA_complex_ ¶NA_character_ " (should (eq (face-at-point) 'ess-constant-face))) (etest-deftest ess-test-r-fontification-keywords-user-modif () "Can add keywords." :case "¶foobar" (let ((ess-R-keywords (append '("foobaz") ess-R-keywords))) (ess-r-mode) (font-lock-ensure)) (should (not (face-at-point))) :case "¶foobaz()" (should (eq (face-at-point) 'ess-keyword-face))) (etest-deftest ess-test-r-fontification-keywords-disabled-backquoted-defun () "Can disable backquoted function definition fontification." :case " ¶`[.foo` <- function(...) NULL ¶\"[.foo\" <- function(...) NULL " (should (eq (face-at-point) 'font-lock-function-name-face)) (with-ess-disabled-font-lock-keyword 'ess-R-fl-keyword:fun-defs (font-lock-ensure) (if (looking-at "\"") (should (eq (face-at-point) 'font-lock-string-face)) (should (not (face-at-point)))))) (etest-deftest ess-test-r-fontification-keywords-user-nil () "Can set keywords to nil." :case "¶stop()" (let (ess-R-keywords) (ess-r-mode) (font-lock-ensure)) (should (not (face-at-point))) :case "¶for (foo ¶in bar) NULL" (let ((ess-R-keywords '("in"))) (ess-r-mode) (font-lock-ensure)) (if (looking-at "for") (should (not (face-at-point))) (should (eq (face-at-point) 'ess-keyword-face))) :case "foo ¶%>% bar()" (should (eq (face-at-point) 'ess-%op%-face)) (with-ess-disabled-font-lock-keyword '(ess-fl-keyword:operators ess-R-fl-keyword:%op%) (font-lock-ensure) (should (not (face-at-point))) (forward-char) (should (not (face-at-point)))) (with-ess-disabled-font-lock-keyword 'ess-R-fl-keyword:%op% (font-lock-ensure) (should (not (face-at-point))))) (etest-deftest ess-test-r-fontification-keywords-disabled-backquoted-call () "Can disable backquoted function call fontification." :case "¶`fun`()" (should (not (face-at-point))) (with-ess-enabled-font-lock-keyword 'ess-fl-keyword:fun-calls (font-lock-ensure) (should (eq (face-at-point) 'ess-function-call-face)))) (etest-deftest ess-test-r-fontification-keywords-modulo-operator () "Modulo operator is fontified independently from special ops." :case "foo ¶%¶% bar" (with-ess-disabled-font-lock-keyword 'ess-R-fl-keyword:%op% (with-ess-enabled-font-lock-keyword 'ess-fl-keyword:operators (font-lock-ensure) (should (eq (face-at-point) 'ess-operator-face)))) (with-ess-enabled-font-lock-keyword '(ess-R-fl-keyword:%op% ess-fl-keyword:operators) (font-lock-ensure) (should (eq (face-at-point) 'ess-operator-face))) (with-ess-disabled-font-lock-keyword '(ess-R-fl-keyword:%op% ess-fl-keyword:operators) (font-lock-ensure) (should (not (face-at-point))))) (etest-deftest ess-test-r-fontification-keywords-backticked-default-face () "NOTE: These used to return `default', now return `nil'." :case " `¶repeat` `¶%>%` `¶-` " ;; Disabled (when nil (with-ess-enabled-font-lock-keyword '(ess-R-fl-keyword:%op% ess-fl-keyword:operators) (font-lock-ensure) (should (not (face-at-point)))))) (etest-deftest test-ess-r-fontification-inferior-r-backticked () "Backticked symbols are not fontified as strings." :case "¶`f¶oo¶`" (setq-local font-lock-syntactic-face-function #'inferior-ess-r-font-lock-syntactic-face-function) (font-lock-ensure) (should (not (face-at-point)))) ;; Local Variables: ;; etest-local-config: etest-r-config ;; End: ESS-24.01.1/test/ess-test-r-package.el000066400000000000000000000117231455642170100172220ustar00rootroot00000000000000;;; ess-test-r-package.el --- ESS tests for R package functionality -*- lexical-binding: t; -*- ;; ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; ;; This file 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. ;; ;; A copy of the GNU General Public License is available at ;; https://www.r-project.org/Licenses/ ;; ;;; Commentary: ;; (require 'ert) (require 'ess-r-mode) (require 'ess-r-package) (require 'ess-test-r-utils) ;;; Code: (ert-deftest ess-r-package-auto-activation-test () (let ((inhibit-message ess-inhibit-message-in-tests)) (with-temp-buffer (text-mode) (hack-local-variables) (should (not ess-r-package-mode))) (with-ess-test-r-file "dummy-pkg/R/test.R" (hack-local-variables) (should ess-r-package-mode)))) (ert-deftest ess-r-package-auto-activation-in-shell-test () (skip-unless (executable-find "bash")) (let ((inhibit-message ess-inhibit-message-in-tests) (kill-buffer-query-functions nil) (explicit-shell-file-name "bash") (explicit-bash-args '("--noediting" "-i" "--norc" "--noprofile"))) (with-ess-test-r-file "dummy-pkg/R/test.R" (shell) (should ess-r-package-mode) (kill-buffer)) (with-ess-test-r-file "dummy-pkg/R/test.R" (let ((ess-r-package-auto-activate t)) (shell) (should ess-r-package-mode)) (kill-buffer)))) (ert-deftest ess-r-package-auto-no-activation-in-shell-test () ;; FIXME: This test fails in batch in Emacs 27. (skip-unless (and (>= 27 emacs-major-version) (not noninteractive) (executable-find "bash"))) (let ((kill-buffer-query-functions nil) (explicit-shell-file-name "bash") (explicit-bash-args '("--noediting" "-i" "--norc" "--noprofile"))) (with-ess-test-r-file "dummy-pkg/R/test.R" (let ((ess-r-package-exclude-modes '(shell-mode))) (shell) (should (not ess-r-package-mode)) (kill-buffer))) (with-ess-test-r-file "dummy-pkg/R/test.R" (let ((ess-r-package-auto-activate nil)) (shell) (should (not ess-r-package-mode)) (kill-buffer))))) (ert-deftest ess-r-package-vars-test () (with-ess-test-c-file "dummy-pkg/src/test.c" (let* ((inf-buf (run-ess-test-r-vanilla)) (inf-proc (get-buffer-process inf-buf)) (ess-local-process-name (process-name inf-proc))) (ess-test-unwind-protect inf-buf (let ((r-setwd-cmd (cdr (assq 'ess-setwd-command ess-r-customize-alist))) (r-getwd-cmd (cdr (assq 'ess-getwd-command ess-r-customize-alist)))) (should (string= ess-setwd-command r-setwd-cmd)) (should (string= ess-getwd-command r-getwd-cmd))) (let ((pkg-dir (file-truename (cdr (ess-r-package-project)))) ;; Not sure why this is needed: ess-ask-for-ess-directory) (ess-set-working-directory (expand-file-name "src" pkg-dir)) (ess-r-package-use-dir) (should (string= pkg-dir (file-truename (directory-file-name (ess-get-process-variable 'default-directory))))) (ess-wait-for-process) (should (string= pkg-dir (file-truename (ess-get-working-directory)))) (ess-wait-for-process) (inferior-ess-reload) (should (string-match "Process R\\(:.\\)? \\(finished\\|killed\\)" (with-current-buffer inf-buf (buffer-string))))))))) (ert-deftest ess-r-package-package-info-test () (let ((kill-buffer-query-functions nil) (ess-r-package-auto-activate nil)) (with-ess-test-r-file "dummy-pkg/R/test.R" (let ((pkg-info (ess-r-package-info))) (should (string= (plist-get pkg-info :name) "foo")) (should (string-match-p "dummy-pkg$" (plist-get pkg-info :root))) (kill-buffer))) (with-ess-test-c-file "dummy-pkg/src/test.c" (let ((pkg-info (ess-r-package-info))) (should (string= (plist-get pkg-info :name) "foo")) (should (string-match-p "dummy-pkg$" (plist-get pkg-info :root))) (kill-buffer))))) ;;; Project Tests (ert-deftest ess-r-project-auto-activation-test () (let ((inhibit-message ess-inhibit-message-in-tests) (root (expand-file-name "dummy-pkg"))) (with-ess-test-r-file "dummy-pkg/R/test.R" (should (equal (ess-r-project-info) (list :name "dummy-pkg" :root root))) (should (equal (cdr (ess-r-project)) root))) (should (not (ess-r-project-info "~"))) (should (not (ess-r-project "~"))))) (provide 'ess-test-r-package) ;;; ess-test-r-package.el ends here ESS-24.01.1/test/ess-test-r-syntax.el000066400000000000000000000110431455642170100171500ustar00rootroot00000000000000;;; ess-test-r-syntax.el --- ESS tests for R syntax -*- lexical-binding: t; -*- ;; ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; ;; This file 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. ;; ;; A copy of the GNU General Public License is available at ;; https://www.r-project.org/Licenses/ ;; ;;; Commentary: ;; (require 'ert) (require 'etest "etest/etest") (require 'ess-r-mode) (require 'ess-test-r-utils) (etest-deftest ess-r-syntax-backslash-test () :case "sapply(x, ¶\\(y) y" (should (equal (syntax-after (point)) (string-to-syntax "."))) :case "c(\"¶\\\"\")" (should (equal (syntax-after (point)) (string-to-syntax "\\")))) (etest-deftest ess-r-font-lock-boolean-operator-test () :case "foo ¶| foo ¶|¶| foo ¶& foo ¶&¶& foo" (ess-with-enabled-font-lock-keyword 'ess-fl-keyword:operators (font-lock-ensure) (should (eq (face-at-point) 'ess-operator-face)))) (etest-deftest ess-r-font-lock-pipe-operator-test () :case "a ¶|¶> b" (ess-with-enabled-font-lock-keyword 'ess-fl-keyword:operators (font-lock-ensure) (should (eq (face-at-point) 'ess-operator-face)))) (etest-deftest ess-r-tokens-pipe-operator-test () :case "a ¶|> b" (should (ess-test-token= "|>")) :result "a |>¶ b") (etest-deftest ess-r-raw-strings-test () :case " r¶\"(foo\"bar))¶\" r¶\"(foo}\"bar))¶\" r¶\"(foo)'bar))¶\" r¶\"---[foo\"bar]---¶\" r¶\"---[foo\"bar]--\"baz]---¶\" r¶'{foo'bar}¶' r¶\"---{foobar}-\\--\" " (should (equal (syntax-after (point)) (string-to-syntax "|"))) :case " r\"¶(foo\"¶bar))¶\" r\"¶(foo}\"¶bar))¶\" r\"¶(foo)'¶bar))¶\" r\"¶---[foo\"¶bar]---¶\" r\"¶---[foo\"¶bar]--\"¶baz]---¶\" r'¶{foo'¶bar}¶' r\"¶---{foobar}¶-\\--\"¶ " (should (ess-inside-string-p)) :case " ¶r\"(foo\"bar))\"¶, ¶r\"(foo}\"bar))\"¶, ¶r\"(foo)'bar))\"¶, ¶r\"---[foo\"bar]---\"¶, ¶r\"---[foo\"bar]--\"baz]---\"¶, ¶r'{foo'bar}'¶, ¶r\"---{foobar}-\\--\" " (should (not (ess-inside-string-p))) :case "r\"(foor\"()\"ba¶r))\"" (should (not (ess-inside-string-p))) :case " r\"(foor¶'()¶'bar))\" # r¶\"{foo}¶\" " (should (not (equal (syntax-after (point)) (string-to-syntax "|"))))) (etest-deftest ess-r-syntax-climb-test () :case " stuff1 =, ¶stuff2 stuff1 =; ¶stuff2 stuff1 := ¶stuff2 stuff1 %a?a:a% ¶stuff2 stuff1 %% ¶stuff2 stuff1 => ¶stuff2 " (ess-climb-operator) :result " stuff1 =, ¶stuff2 stuff1 =; ¶stuff2 stuff1¶ := stuff2 stuff1¶ %a?a:a% stuff2 stuff1¶ %% stuff2 stuff1¶ => stuff2 " :case " function_call() ¶ " (ess-climb-block-prefix) :result " function_call() ¶ " (ess-climb-block-prefix "function") :result " function_call() ¶ ") (etest-deftest ess-r-syntax-climb-continuations-test () :case "(!stuff1 ||¶ stuff2)" (ess-climb-continuations) :result "(¶!stuff1 || stuff2)" :case " object <- fun_call() %>% ¶fun_call() object <- fun_call() %>% fun_call() %>% ¶fun_call() object <- namespace::fun_call() %>% ¶fun_call() object <- namespace:::fun_call() %>% ¶fun_call() object <- object@fun_call() %>% ¶fun_call() object <- object$fun_call() %>% ¶fun_call() " (ess-climb-continuations) :result " ¶object <- fun_call() %>% fun_call() ¶object <- fun_call() %>% fun_call() %>% fun_call() ¶object <- namespace::fun_call() %>% fun_call() ¶object <- namespace:::fun_call() %>% fun_call() ¶object <- object@fun_call() %>% fun_call() ¶object <- object$fun_call() %>% fun_call() ") (etest-deftest ess-r-syntax-climb-sticky-ops-test () :case " object@field¶ object$field¶ namespace::object¶ namespace:::object¶ " (ess-climb-expression) :result " ¶object@field ¶object$field ¶namespace::object ¶namespace:::object " :case reset (ess-climb-object) :result " ¶object@field ¶object$field ¶namespace::object ¶namespace:::object ") (etest-deftest ess-r-syntax-jump-test () :case " ¶if (test1) stuff1 if (test2) stuff2" (ess-jump-expression) :result " if (test1) stuff1¶ if (test2) stuff2") ;; Local Variables: ;; etest-local-config: etest-r-config ;; End: ESS-24.01.1/test/ess-test-r-token.el000066400000000000000000000246131455642170100167510ustar00rootroot00000000000000;;; ess-test-r-token.el --- ESS tests for R tokens -*- lexical-binding: t; -*- ;; ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; ;; This file 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. ;; ;; A copy of the GNU General Public License is available at ;; https://www.r-project.org/Licenses/ ;; ;;; Commentary: ;; (require 'ert) (require 'etest "etest/etest") (require 'ess-r-mode) (require 'ess-test-r-utils) (etest-deftest ess-test-r-token-jump-strings-symbols-test () :case "¶`a\"a\"a` \"a`a`a\"" (ess-test-should-token= "identifier" "`a\"a\"a`") :result "`a\"a\"a`¶ \"a`a`a\"" (ess-test-should-token= "string" "\"a`a`a\"") :result "`a\"a\"a` \"a`a`a\"¶") (etest-deftest ess-test-r-token-jump-identifiers-test () :case "¶.a_a a10" (ess-test-should-token= "identifier" ".a_a") :result ".a_a¶ a10" (ess-test-should-token= "identifier" "a10") :result ".a_a a10¶") (etest-deftest ess-test-r-token-jump-numbers-test () :case "¶100 1E10 1e10 1.10" (ess-test-should-token= "number" "100") :result "100¶ 1E10 1e10 1.10" (ess-test-should-token= "number" "1E10") :result "100 1E10¶ 1e10 1.10" (ess-test-should-token= "number" "1e10") :result "100 1E10 1e10¶ 1.10" (ess-test-should-token= "number" "1.10") :result "100 1E10 1e10 1.10¶") (etest-deftest ess-test-r-token-jump-delimiters-test () :case "¶() a[[[]]] {}" (ess-test-should-token= "(") :result "(¶) a[[[]]] {}" (ess-test-should-token= ")") :result "()¶ a[[[]]] {}" (ess-jump-token) (ess-test-should-token= "[[") :result "() a[[¶[]]] {}" (should (ess-jump-token "[")) (should (ess-token-before= "[[")) :result "() a[[[¶]]] {}" (ess-test-should-token= "]]") :result "() a[[[]]¶] {}" (should (ess-jump-token "]")) (should (ess-token-before= "]]")) :result "() a[[[]]]¶ {}" (ess-test-should-token= "{") :result "() a[[[]]] {¶}" (ess-test-should-token= "}") :result "() a[[[]]] {}¶") (etest-deftest ess-test-r-token-buffer-boundaries-test () :case "¶" (should (ess-token-before= "buffer-start")) (should (ess-token-after= "buffer-end")) :result "¶") (etest-deftest ess-test-r-token-jump-punctuation-test () :case "¶.; .," (ess-jump-token) (ess-test-should-token= ";") :result ".;¶ .," (ess-jump-token) (ess-test-should-token= ",") :result ".; .,¶") (etest-deftest ess-test-r-token-jump-keywords-test () :case "¶if if_else else function while for" (ess-test-should-token= "if") (ess-test-should-token= "identifier" "if_else") (ess-test-should-token= "else") (ess-test-should-token= "function") (ess-test-should-token= "while") (ess-test-should-token= "for") :result "if if_else else function while for¶") (etest-deftest ess-test-r-token-jump-logical-operators-test () :case "¶a & a && a &&& a | a || a ||| a" (ess-jump-token) (ess-test-should-token= "&") :result "a &¶ a && a &&& a | a || a ||| a" (ess-jump-token) (ess-test-should-token= "&&") :result "a & a &&¶ a &&& a | a || a ||| a" (ess-jump-token) (ess-test-should-token= "&&") :result "a & a && a &&¶& a | a || a ||| a" (should (ess-jump-token "&")) (should (ess-token-before= "&&")) :result "a & a && a &&&¶ a | a || a ||| a" (ess-jump-token) (ess-test-should-token= "|") :result "a & a && a &&& a |¶ a || a ||| a" (ess-jump-token) (ess-test-should-token= "||") :result "a & a && a &&& a | a ||¶ a ||| a" (ess-jump-token) (ess-test-should-token= "||") :result "a & a && a &&& a | a || a ||¶| a" (should (ess-jump-token "|")) (should (ess-token-before= "||")) :result "a & a && a &&& a | a || a |||¶ a") (etest-deftest ess-test-r-token-jump-comparison-operators-test () :case "¶a = a := a == a === a :== a != a :!= a" (ess-jump-token) (ess-test-should-token= "=") :result "a =¶ a := a == a === a :== a != a :!= a" (ess-jump-token) (ess-test-should-token= ":=") :result "a = a :=¶ a == a === a :== a != a :!= a" (ess-jump-token) (ess-test-should-token= "==") :result "a = a := a ==¶ a === a :== a != a :!= a" (ess-jump-token) (ess-test-should-token= "==") :result "a = a := a == a ==¶= a :== a != a :!= a" (should (ess-jump-token "=")) (should (ess-token-before= "==")) :result "a = a := a == a ===¶ a :== a != a :!= a" (ess-jump-token) (ess-test-should-token= ":=") :result "a = a := a == a === a :=¶= a != a :!= a" (should (ess-jump-token "=")) (should (ess-token-before= "==")) :result "a = a := a == a === a :==¶ a != a :!= a" (ess-jump-token) (ess-test-should-token= "!=") :result "a = a := a == a === a :== a !=¶ a :!= a" (ess-jump-token) (ess-test-should-token= ":") :result "a = a := a == a === a :== a != a :¶!= a" (ess-test-should-token= "!=") :result "a = a := a == a === a :== a != a :!=¶ a") (etest-deftest ess-test-r-token-jump-%%-operators-test () :case "¶a %>% a %a`a`a\"a\"a$a@a% a %% a %%% a % a" (ess-jump-token) (ess-test-should-token= "%infix%" "%>%") :result "a %>%¶ a %a`a`a\"a\"a$a@a% a %% a %%% a % a" (ess-jump-token) (ess-test-should-token= "%infix%" "%a`a`a\"a\"a$a@a%") :result "a %>% a %a`a`a\"a\"a$a@a%¶ a %% a %%% a % a" (ess-jump-token) (ess-test-should-token= "%%") :result "a %>% a %a`a`a\"a\"a$a@a% a %%¶ a %%% a % a" (ess-jump-token) (ess-test-should-token= "%%") :result "a %>% a %a`a`a\"a\"a$a@a% a %% a %%¶% a % a" (ess-test-should-token= "%infix%" "% a %") :result "a %>% a %a`a`a\"a\"a$a@a% a %% a %%% a %¶ a") (etest-deftest ess-test-r-token-jump-arithmetic-operators-test () :case "¶a + a - a - -a * a ** a ^ a ^ ++a" (ess-jump-token) (ess-test-should-token= "+") :result "a +¶ a - a - -a * a ** a ^ a ^ ++a" (ess-jump-token) (ess-test-should-token= "-") :result "a + a -¶ a - -a * a ** a ^ a ^ ++a" (ess-jump-token) (ess-test-should-token= "-") :result "a + a - a -¶ -a * a ** a ^ a ^ ++a" (ess-test-should-token= "-") :result "a + a - a - -¶a * a ** a ^ a ^ ++a" (ess-jump-token) (ess-test-should-token= "*") :result "a + a - a - -a *¶ a ** a ^ a ^ ++a" (ess-jump-token) (ess-test-should-token= "**") :result "a + a - a - -a * a **¶ a ^ a ^ ++a" (ess-jump-token) (ess-test-should-token= "^") :result "a + a - a - -a * a ** a ^¶ a ^ ++a" (ess-jump-token) (ess-test-should-token= "^") :result "a + a - a - -a * a ** a ^ a ^¶ ++a" (ess-test-should-token= "+") :result "a + a - a - -a * a ** a ^ a ^ +¶+a" (ess-test-should-token= "+") :result "a + a - a - -a * a ** a ^ a ^ ++¶a") (etest-deftest ess-test-r-token-jump-:-operators-test () :case "¶a: a:: a::: a:::: a:::=" (ess-jump-token) (ess-test-should-token= ":") :result "a:¶ a:: a::: a:::: a:::=" (ess-jump-token) (ess-test-should-token= "::") :result "a: a::¶ a::: a:::: a:::=" (ess-jump-token) (ess-test-should-token= ":::") :result "a: a:: a:::¶ a:::: a:::=" (ess-jump-token) (ess-test-should-token= ":::") :result "a: a:: a::: a:::¶: a:::=" (should (ess-jump-token ":")) (should (ess-token-before= ":::")) :result "a: a:: a::: a::::¶ a:::=" (ess-jump-token) (ess-test-should-token= ":::") :result "a: a:: a::: a:::: a:::¶=") (etest-deftest ess-test-r-token-jump-assignment-operators-test () :case "¶a <- a <<- a -> > a ->> a >> a" (ess-jump-token) (ess-test-should-token= "<-") :result "a <-¶ a <<- a -> > a ->> a >> a" (ess-jump-token) (ess-test-should-token= "<<-") :result "a <- a <<-¶ a -> > a ->> a >> a" (ess-jump-token) (ess-test-should-token= "->") :result "a <- a <<- a ->¶ > a ->> a >> a" (ess-test-should-token= ">") :result "a <- a <<- a -> >¶ a ->> a >> a" (ess-jump-token) (ess-test-should-token= "->>") :result "a <- a <<- a -> > a ->>¶ a >> a" (ess-jump-token) (ess-test-should-token= ">") (ess-test-should-token= ">") :result "a <- a <<- a -> > a ->> a >>¶ a") (etest-deftest ess-test-r-token-jump-inequality-operators-test () :case "¶a < > a >= a > = a <=" (ess-jump-token) (ess-test-should-token= "<") :result "a <¶ > a >= a > = a <=" (ess-test-should-token= ">") :result "a < >¶ a >= a > = a <=" (ess-jump-token) (ess-test-should-token= ">=") :result "a < > a >=¶ a > = a <=" (ess-jump-token) (ess-test-should-token= ">") :result "a < > a >= a >¶ = a <=" (ess-test-should-token= "=") :result "a < > a >= a > =¶ a <=" (ess-jump-token) (ess-test-should-token= "<=") :result "a < > a >= a > = a <=¶") (etest-deftest ess-test-r-token-jump-special-operators-test () :case "¶~a~~a" (ess-test-should-token= "~") :result "~¶a~~a" (ess-jump-token) (ess-test-should-token= "~") (ess-test-should-token= "~") :result "~a~~¶a") (etest-deftest ess-test-r-token-refine-param-assignment-test () :case "call(param ¶= NULL)" (ess-test-should-token= "=") (should (ess-refined-token= (ess-token-before) "param-assign")) :result "call(param =¶ NULL)") (etest-deftest ess-test-r-token-refine-quoted-param-names-test () :case "call(¶\"param\" = NULL)" (ess-test-should-token= "string" "\"param\"") (should (ess-refined-token= (ess-token-before) "identifier")) :result "call(\"param\"¶ = NULL)") (etest-deftest ess-test-r-token-refine-quoted-call-names-test () :case "¶\"call\"()" (ess-test-should-token= "string" "\"call\"") (should (ess-refined-token= (ess-token-before) "identifier")) :result "\"call\"¶()") (etest-deftest ess-test-r-token-skip-blanks-test () :case " text¶ text" (should (ess-skip-blanks-forward t)) :result " text ¶text" (should (not (ess-skip-blanks-backward))) :result " text ¶text" (should (ess-skip-blanks-backward t)) :result " text¶ text") (etest-deftest ess-test-r-token-skip-comments-test () :case "text¶ # comment" (should (ess-skip-blanks-forward t)) :result "text ¶# comment" (should (not (ess-skip-blanks-forward t))) :result "text ¶# comment") (etest-deftest ess-test-r-token-skip-form-feed-test () :case " text ¶text" (should (ess-skip-blanks-backward t)) :result " text¶ text") ;; Local Variables: ;; etest-local-config: etest-r-config ;; End: ESS-24.01.1/test/ess-test-r-utils.el000066400000000000000000000423611455642170100167710ustar00rootroot00000000000000;; ess-test-r-utils.el --- Various utilities for ess R tests -*- lexical-binding: t; -*- ;; ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; ;; This file 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. ;; ;; A copy of the GNU General Public License is available at ;; https://www.r-project.org/Licenses/ ;; ;;; Commentary: ;; Various utilities for ESS tests. ;;; Code: (require 'ert) (require 'etest "etest/etest") (require 'ess-r-mode) (require 'tramp) (require 'seq) (defvar etest-r-config '(:init ((mode . r) (ess-offset . 4) (eval . (progn (ess-test-r-set-local-process) ;; Reset local config to ESS defaults (ess-set-style 'RRR 'quiet) (setq-local ess-fill-calls-newlines nil)))))) (defvar ess-test-fixtures-directory (expand-file-name "fixtures" (file-name-directory (or load-file-name buffer-file-name))) "Location of the fixtures directory.") (defvar ess-inhibit-message-in-tests nil) (defmacro with-ess-test-file (file &rest body) (declare (indent 1) (debug (&rest body))) `(let ((inhibit-message ess-inhibit-message-in-tests) (*file* ,file)) (save-current-buffer (set-buffer (if *file* (find-file-noselect *file*) (generate-new-buffer " *with-r-file-temp*"))) ,@body))) (defmacro with-ess-test-r-file (file &rest body) (declare (indent 1) (debug (sexp body))) `(with-ess-test-file ,file (R-mode) ,@body)) (defmacro with-ess-test-c-file (file &rest body) (declare (indent 1) (debug (sexp body))) `(with-ess-test-file ,file (c-mode) ,@body)) ;; Borrowed from org (defmacro ess-r-test-with-temp-text (text &rest body) "Run body in a temporary buffer with `ess-r-mode' as the active mode holding TEXT. If the string \"¶\" appears in TEXT then remove it and place the point there before running BODY, otherwise place the point at the beginning of the inserted text." (declare (indent 1) (debug (form body))) `(let ((inside-text (if (stringp ,text) ,text (eval ,text))) (ess-r-mode-hook nil)) (with-temp-buffer (ess-r-mode) (let ((point (string-match "¶" inside-text))) (if point (progn (insert (replace-match "" nil nil inside-text)) (goto-char (1+ (match-beginning 0)))) (insert inside-text) (goto-char (point-min)))) ,@body))) (defmacro ess-cpp-test-with-temp-text (text &rest body) "Run body in a temporary buffer with `cpp-mode' as the active mode holding TEXT. Turn on `ess-roxy-mode'. If the string \"¶\" appears in TEXT then remove it and place the point there before running BODY, otherwise place the point at the beginning of the inserted text." (declare (indent 1) (debug (form body))) `(let ((inside-text (if (stringp ,text) ,text (eval ,text))) (c++-mode-hook nil)) (with-temp-buffer (c++-mode) (ess-roxy-mode) (let ((point (string-match "¶" inside-text))) (if point (progn (insert (replace-match "" nil nil inside-text)) (goto-char (1+ (match-beginning 0)))) (insert inside-text) (goto-char (point-min)))) ,@body))) (defmacro ess-test-sleep-while (test seconds timeout &optional msg) (declare (debug t)) `(ess--test-sleep-while-1 (lambda () ,test) ,seconds ,timeout ,msg)) (defun ess--test-sleep-while-1 (test-fun seconds timeout msg) (let ((time-start (current-time))) (while (funcall test-fun) (when (time-less-p timeout (time-subtract (current-time) time-start)) (error (or msg "Exceeded timeout"))) (sleep-for seconds)) t)) (defmacro ess-test-unwind-protect (inf-buf &rest body) (declare (indent 1) (debug (&rest form))) `(ess--test-unwind-protect-1 ,inf-buf (lambda () ,@body))) (defun ess--test-unwind-protect-1 (inf-buf body-fun) (unwind-protect (funcall body-fun) (let* ((inf-proc (get-buffer-process inf-buf))) (when (and inf-proc (process-live-p inf-proc)) (set-process-query-on-exit-flag inf-proc nil) (kill-process inf-proc) (ess-test-sleep-while (process-live-p inf-proc) 0.001 1 "Expected dead process")) (kill-buffer inf-buf)))) (defun run-ess-test-r-vanilla () "Start vanilla R process and return the process object." (save-window-excursion (let ((inhibit-message ess-inhibit-message-in-tests) (ess-ask-for-ess-directory nil)) (R "--no-init-file --no-site-file")))) (let ((inf-bufs '((output . nil) (tracebug . nil)))) (defun ess-r-test-proc-buf--init (type) (setf (cdr (assq type inf-bufs)) (run-ess-test-r-vanilla)) (let* ((inf-buf (cdr (assq type inf-bufs))) (inf-proc (get-buffer-process inf-buf)) (inf-filter (pcase type (`output 'inferior-ess-output-filter) (`tracebug 'inferior-ess-tracebug-output-filter) (_ (error "Unknown filter type"))))) (ess-wait-for-process (get-buffer-process inf-buf)) (set-process-filter inf-proc inf-filter) (with-current-buffer inf-buf ;; Replacing strings of " +" causes random failures, probably ;; because of the buffered output (setq-local inferior-ess-replace-long+ nil) (let ((inhibit-read-only t)) (erase-buffer))) inf-buf)) (defun ess-r-test-proc-buf (type &optional force) "Common process buffer for tests." (or (unless force (cdr (assq type inf-bufs))) (ess-r-test-proc-buf--init type)))) (defun ess-send-input-to-R (input &optional type) "Eval INPUT and return the entire content of the REPL buffer. TYPE can be one of `string', `region', `c-c' or `repl'. If nil or `string', use `ess-send-string' (lowest level primitive); if `region' use `ess-eval-region' if `c-c' use `ess-eval-region-or-function-or-paragraph' which is by default bound to `C-c C-c'; if `repl', eval interactively at the REPL. All prompts in the output are replaced with \"> \". There is no fool proof way to test for prompts given that process output could be split arbitrarily." (let* ((prompt-regexp "^\\([+.>] \\)\\{2,\\}") (inf-buf (run-ess-test-r-vanilla)) (inf-proc (get-buffer-process inf-buf)) (inhibit-message ess-inhibit-message-in-tests)) ;; just in case (ess-wait-for-process inf-proc) (ess--flush-accumulated-output inf-proc) (ess-test-unwind-protect inf-buf (with-current-buffer (process-buffer inf-proc) (let ((inhibit-read-only t)) (erase-buffer) ;; (switch-to-buffer (current-buffer)) ; for debugging (cond ((or (null type) (eq type 'string)) (ess-send-string inf-proc input)) ((eq type 'repl) (insert input) (inferior-ess-send-input)) ((or (eq type 'region) (eq type 'c-c)) (with-temp-buffer (insert input) (goto-char (point-min)) (R-mode) (setq ess-current-process-name (process-name inf-proc)) (if (eq type 'region) (ess-eval-region (point-min) (point-max) nil) (ess-eval-region-or-function-or-paragraph nil)))) (t (error "Invalid TYPE parameter"))) (process-send-string inf-proc "cat('END')\n") ;; wait till we have our end marker (while (not (looking-back "\n?END> " nil t)) (sleep-for 0.01) (goto-char (point-max))) ;; remove END> (delete-region (match-beginning 0) (match-end 0)) ;; (buffer-substring-no-properties (point-min) (point-max)) (replace-regexp-in-string prompt-regexp "> " (buffer-substring-no-properties (point-min) (point-max)))))))) (defun ess-test-R-indentation (file style) (let ((ess-style-alist ess-test-style-alist) (buff (find-file-noselect file t t)) (inhibit-message ess-inhibit-message-in-tests)) (with-current-buffer buff (R-mode) (ess-set-style style) (set-buffer-modified-p nil) (should (not-change-on-indent buff))))) ;; !!! NB: proc functionality from now on uses inferior-ess-ordinary-filter and ;; !!! *proc* dynamic var (defmacro ess-test-with-r-running (buffer-or-file &rest body) "Run BODY within BUFFER-OR-FILE with attached R process. If BUFFER-OR-FILE is a file, the file is visited first. The R process is run with `inferior-ess-ordinary-filter' which is not representative to the common interactive use with tracebug on. BODY can refer to the process via the variable `*proc*'." (declare (indent 1) (debug (form body))) `(ess-test-with-r-running-1 ,buffer-or-file (lambda (*proc*) (ignore *proc*) ,@body))) (defun ess-test-with-r-running-1 (buffer-or-file body-fun) (let* ((inhibit-message ess-inhibit-message-in-tests) (r-file-buffer (cond ((bufferp buffer-or-file) buffer-or-file) ((stringp buffer-or-file) (find-file-noselect buffer-or-file)) (t (generate-new-buffer " *with-r-file-temp*"))))) (with-current-buffer r-file-buffer (R-mode) (let* ((*proc* (get-buffer-process (run-ess-test-r-vanilla))) (ess-local-process-name (process-name *proc*)) (*inf-buf* (process-buffer *proc*))) (unwind-protect (ess-test-unwind-protect *inf-buf* (setq ess-r-tests-current-output-buffer *inf-buf*) (let ((inhibit-read-only t)) (with-current-buffer ess-r-tests-current-output-buffer (ess-wait-for-process *proc*) (erase-buffer))) (set-process-filter *proc* #'inferior-ess-output-filter) (prog1 (funcall body-fun *proc*) (ess-wait-for-process *proc*))) (setq ess-r-tests-current-output-buffer nil)))))) (defvar ess-r-tests-current-output-buffer nil) ;; The following retrieve the last output and clean the output ;; buffer. This is useful to continue testing without restarting a ;; fresh R session. ;; In case of other side effects than mere output, it's probably safer ;; to perform ulterior tests with a fresh R to avoid contaminating ;; them. (defmacro ess-test-output (&rest body) (declare (indent 1) (debug (&rest body))) `(progn (ess-wait-for-process *proc*) ,@body (ess-wait-for-process *proc*) (with-current-buffer ess-r-tests-current-output-buffer (ess-kill-last-line) (prog1 (buffer-substring-no-properties (point-min) (point-max)) (erase-buffer))))) (defmacro ess-test-output= (body expected) (declare (indent 0) (debug (sexp sexp))) `(progn (let ((output (ess-test-output ,body)) (expected ,expected)) (if (string= output expected) output ;; Probably a better way but this gets the job done (signal 'ert-test-failed (list (concat "Expected: \n" expected) (concat "Result: \n" output))))))) (defun ess-test-face-at (point) (save-excursion (if (>= point 0) (goto-char point) (forward-char point)) (get-char-property (point) 'face))) (defun ess-test-insert-fontified (&rest args) (apply #'insert args) (font-lock-default-fontify-buffer)) ;; It is safer to kill the buffer synchronously, otherwise it might be ;; reused in another test (defun ess-test-r-set-local-process (&optional type) (let* ((proc-buf (ess-r-test-proc-buf (or type 'tracebug))) (proc (get-buffer-process proc-buf))) (unless proc (ess-r-test-proc-buf (or type 'tracebug) 'force) (error "process for unit tests died unexpectedly in a previous test and was just relaunched")) (setq ess-local-process-name (process-name (get-buffer-process proc-buf))) (setq etest-local-inferior-buffer proc-buf))) ;; Utilities for testing remote functionality ;; Define a mock TRAMP method to use for testing. This code is taken from ;; `tramp-tests.el'. (add-to-list 'tramp-methods '("mock" (tramp-login-program "sh") (tramp-login-args (("-i"))) (tramp-direct-async-args (("-c"))) (tramp-remote-shell "/bin/sh") (tramp-remote-shell-args ("-c")) (tramp-connection-timeout 10))) (defun ess-test-create-remote-path (path) "Construct a remote path using the `mock' TRAMP method. Take a string PATH representing a local path, and construct a remote path that uses the `mock' TRAMP method." (let ((full-path (abbreviate-file-name (expand-file-name path)))) (concat "/mock::" full-path))) ;; Utilities for testing ESSR injection (defun ess--essr-remove () "Ensure that ESSR objects are removed. Note that if `ess--essr-detach' is successful then it is critical that we don't run `ess--essr-remove-global-objs' because .ess.command doesn't exist in the R runtime environment (and which is relied upon by `ess-command')." (ess-process-put 'format-command-alist nil) (or (ess--essr-detach) (ess--essr-remove-global-objs))) (defun ess--essr-detach () "Ensure that ESSR is not attached." (ess-boolean-command "tryCatch({detach('ESSR'); 'TRUE'}, error = function(e) 'FALSE')\n")) (defun ess--essr-remove-global-objs () "Ensure that all ESSR objects are removed from the global env." (ess-command "rm(list = grep('\\\\.(ess|ESS)', ls(all.names = TRUE), value = TRUE))\n")) (defun ess--essr-check-if-attached () "Check whether ESSR is attached to the search path." (let ((attached-nms (ess-get-words-from-vector "search()\n"))) (seq-some (lambda (str) (string= str "ESSR")) attached-nms))) (defun ess--essr-check-if-in-globalenv () "Check whether any ESSR objects are in the global env." (let* ((r-input "grep('\\\\.(ess|ESS)', ls(all.names = TRUE), value = TRUE)\n") (output-list (ess-get-words-from-vector r-input))) (> (length output-list) 0))) (defun ess--essr-check-if-in-essrenv () "Check whether any ESSR objects are in the ESSR env." (let* ((r-input "grep('\\\\.(ess|ESS)', ls('ESSR', all.names = TRUE), value = TRUE)\n") (output-list (ess-get-words-from-vector r-input))) (> (length output-list) 0))) (defun ess--essr-load-or-throw-error (file ess-r--load-ESSR-fcn) "Attempt to attach the ESSR environment. Throws an error if unsuccesful." (with-ess-test-r-file file (ess-test-with-r-running (current-buffer) ;; ensure that there is no ESSR environment nor any ESSR objects in the ;; global environment (ess--essr-remove) ;; inject environment and attach (funcall ess-r--load-ESSR-fcn) ;; check for successful ESSR injection (should (not (ess--essr-check-if-in-globalenv))) (should (ess--essr-check-if-attached)) (should (ess--essr-check-if-in-essrenv))) (kill-buffer))) (defun ess-test-token= (type &optional value) "Check that the next token conforms to TYPE and VALUE. This checks it back and forth and moves the point after the token." (and (ess-jump-token type value) (ess-token-before= type value))) ;; The macro has better failure reporting (defmacro ess-test-should-token= (type &optional value) "Check that the next token conforms to TYPE and VALUE. This checks it back and forth and moves the point after the token." `(let* ((-type ,type) (-value ,value) (tok (should (ess-jump-token)))) (let ((-type (if (listp -type) -type (list -type))) (-value (if (listp -value) -value (list -value)))) (when -type (should (ess-token-type tok)) (should (member (ess-token-type tok) -type))) (when -value (should (ess-token-value tok)) (should (member (ess-token-value tok) -value)))))) (defmacro ess-with-toggled-font-lock-keyword (enable keywords &rest body) (declare (indent 2) (debug (&rest form))) `(progn (let* ((enable ,enable) (keywords ,keywords) (keywords (if (listp keywords) keywords (list keywords))) toggled) (mapc (lambda (kw) (if (not (eq enable (cdr (assq kw ess-R-font-lock-keywords)))) (progn (ess-font-lock-toggle-keyword kw) (push kw toggled)))) keywords) ,@body (mapc #'ess-font-lock-toggle-keyword toggled)))) (defmacro ess-with-disabled-font-lock-keyword (keywords &rest body) (declare (indent 1) (debug (&rest form))) `(ess-with-toggled-font-lock-keyword nil ,keywords ,@body)) (defmacro ess-with-enabled-font-lock-keyword (keywords &rest body) (declare (indent 1) (debug (&rest form))) `(ess-with-toggled-font-lock-keyword t ,keywords ,@body)) (provide 'ess-test-r-utils) ;; Local Variables: ;; etest-local-config: etest-r-config ;; End: ;;; ess-test-r-utils.el ends here ESS-24.01.1/test/ess-test-r.el000066400000000000000000000763761455642170100156500ustar00rootroot00000000000000;;; ess-test-r.el --- ESS tests for R -*- lexical-binding: t; -*- ;; ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; ;; This file 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. ;; ;; A copy of the GNU General Public License is available at ;; https://www.r-project.org/Licenses/ ;; ;;; Commentary: ;; (require 'ert) (require 'etest "etest/etest") (require 'ess-r-mode) (require 'ess-test-r-utils) (require 'cc-mode) (require 'imenu) (with-no-warnings (when (< emacs-major-version 26) (require 'cl))) ;; FIXME: For? ;;; R ;;; Code: (ert-deftest ess-r-inherits-prog-mode-test () (let* ((pmh-was-run nil) (prog-mode-hook (lambda () (setq pmh-was-run t)))) (with-ess-test-r-file nil (should (derived-mode-p 'prog-mode)) (should pmh-was-run) (should ;; Test that prog-mode-map is a keymap-parent (let ((map (current-local-map)) found) (while (and map (not found)) (if (eq (keymap-parent map) prog-mode-map) (setq found t) (setq map (keymap-parent map)))) found))))) (ert-deftest ess-build-eval-command-R-test () (let ((command "command(\"string\")") (ess-dialect "R")) (should (string= (ess-build-eval-command command) "base::as.environment('ESSR')$.ess.eval(\"command(\\\"string\\\")\", visibly = FALSE, output = FALSE)\n")) (should (string= (ess-build-eval-command command nil t) "base::as.environment('ESSR')$.ess.eval(\"command(\\\"string\\\")\", visibly = FALSE, output = TRUE)\n")) (should (string= (ess-build-eval-command command t t "file.ext" "foo") "base::as.environment('ESSR')$.ess.ns_eval(\"command(\\\"string\\\")\", visibly = TRUE, output = TRUE, package = 'foo', verbose = TRUE, file = 'file.ext')\n")))) (ert-deftest ess-build-load-command-R-test () (let ((ess-dialect "R")) (should (string= (ess-build-load-command "file.ext") "base::as.environment('ESSR')$.ess.source('file.ext', visibly = FALSE, output = FALSE)\n")) (should (string= (ess-build-load-command "file.ext" t t) "base::as.environment('ESSR')$.ess.source('file.ext', visibly = TRUE, output = TRUE)\n")) (should (string= (ess-build-load-command "file.ext" nil t "foo") "base::as.environment('ESSR')$.ess.ns_source('file.ext', visibly = FALSE, output = TRUE, package = 'foo', verbose = TRUE)\n")))) (ert-deftest inferior-ess-inherits-from-comint-test () (let ((inhibit-message ess-inhibit-message-in-tests)) (with-temp-buffer (inferior-ess-r-mode) ;; Derive from comint (should (derived-mode-p 'comint-mode)) (should ;; Test that comint-mode-map is a keymap-parent (let ((map (current-local-map)) found) (while (and map (not found)) (if (eq (keymap-parent map) comint-mode-map) (setq found t) (setq map (keymap-parent map)))) found))))) (ert-deftest ess-r-send-single-quoted-strings-test () (ess-test-with-r-running nil (insert "'hop'\n") (let (ess-eval-visibly) (should (ess-test-output= (ess-eval-buffer nil) "[1] \"hop\""))))) (ert-deftest ess-r-send-double-quoted-strings-test () (ess-test-with-r-running nil (insert "\"hop\"\n") (let (ess-eval-visibly) (should (ess-test-output= (ess-eval-buffer nil) "[1] \"hop\""))))) (ert-deftest ess-eval-line-test () (ess-test-with-r-running nil (insert "1 + 1") (let (ess-eval-visibly) (should (ess-test-output= (ess-eval-line) "[1] 2"))) (let ((ess-eval-visibly t)) (should (ess-test-output= (ess-eval-line) "1 + 1\n[1] 2"))))) (ert-deftest ess-eval-region-test () (ess-test-with-r-running nil (insert "1 + \n1") (let (ess-eval-visibly) (should (ess-test-output= (ess-eval-region (point-min) (point-max) nil) "+ [1] 2"))) (let ((ess-eval-visibly t)) (should (ess-test-output= (ess-eval-region (point-min) (point-max) nil) "1 + \n+ 1\n[1] 2"))))) (ert-deftest ess-eval-function () (ess-test-with-r-running nil (let (ess-eval-visibly) (insert "x <- function(a){\n a + 1\n}") (forward-line -1) (ess-eval-function) (delete-region (progn (beginning-of-defun) (point)) (progn (end-of-defun) (point))) (insert "x(1)") (should (ess-test-output= (ess-eval-region (point-min) (point-max) nil) "+ + > [1] 2"))))) (ert-deftest ess-r-eval-rectangle-mark-mode-test () (ess-test-with-r-running nil (insert "x <- 1\nx\nx + 1\nx + 2\n") (let (ess-eval-visibly) (should (ess-test-output= (progn (goto-char (point-min)) (transient-mark-mode) (rectangle-mark-mode) (forward-line 3) (end-of-line) (ess-eval-region-or-line-and-step)) "> [1] 1\n> [1] 2\n> [1] 3"))))) (ert-deftest ess-set-working-directory-test () (ess-test-with-r-running nil (ess-set-working-directory "/") (ess-eval-linewise "getwd()" 'invisible) (should (ess-test-output= (ess-eval-buffer nil) "setwd('/')\n> [1] \"/\"")) (should (string= (ess-get-process-variable 'default-directory) "/")))) (ert-deftest ess-inferior-force-test () (ess-test-with-r-running nil (should (equal (ess-get-words-from-vector "letters[1:2]\n") (list "a" "b"))))) ;;; Namespaced evaluation (ert-deftest ess-r-run-presend-hooks-test () (ess-test-with-r-running nil (let ((ess-presend-filter-functions (list (lambda (_string) "\"bar\""))) (ess-r-evaluation-env "base") ess-eval-visibly) (insert "\"foo\"\n") (should (ess-test-output= (ess-eval-region (point-min) (point-max) nil) "[1] \"bar\""))))) (ert-deftest ess-r-namespaced-eval-no-sourced-message-test () (ess-test-with-r-running nil (let ((ess-r-evaluation-env "base") ess-eval-visibly) (insert "\"foo\"\n") (should (ess-test-output= (ess-eval-region (point-min) (point-max) nil) "[1] \"foo\""))))) (ert-deftest ess-r-namespaced-eval-no-srcref-in-errors-test () ;; Fails since https://github.com/emacs-ess/ESS/commit/3a7d913 (when nil (ess-test-with-r-running nil (let ((ess-r-evaluation-env "base") (error-msg "Error: unexpected symbol") ess-eval-visibly) (insert "(foo bar)\n") (let ((output (ess-test-output (ess-eval-region (point-min) (point-max) nil)))) (should (string= (substring output 0 (length error-msg)) error-msg))))))) ;;; Misc (ert-deftest ess-r-makevars-mode-test () (save-window-excursion (mapc (lambda (file) (switch-to-buffer (find-file-noselect file)) (should (eq major-mode 'makefile-mode))) `(,(expand-file-name "Makevars" ess-test-fixtures-directory) ,(expand-file-name "Makevars.win" ess-test-fixtures-directory))))) (ert-deftest ess-find-newest-date-test () (should (equal (ess-find-newest-date '(("2003-10-04" . "R-1.7") ("2006-11-19" . "R-2.2") ("2007-07-01" . "R-dev") ("-1" . "R-broken") ("2005-12-30" . "R-2.0"))) "R-dev"))) (ert-deftest ess-skip-thing-test () (should (eql 18 (ess-r-test-with-temp-text "x <- function(x){\n mean(x)\n }\n \n \n x(3)\n " (goto-char (point-min)) (ess-skip-thing 'line) (point)))) (should (eql 30 (ess-r-test-with-temp-text "x <- function(x){\n mean(x)\n }\n \n \n x(3)\n " (goto-char (point-min)) (ess-skip-thing 'function) (point)))) (should (eql 31 (ess-r-test-with-temp-text "x <- function(x){\n mean(x)\n }\n \n \n x(3)\n " (goto-char (point-min)) (ess-skip-thing 'paragraph) (point)))) ;; The following fails because end-of-defun assume that beginning-of-defun ;; always moves the pointer. We currently don't in ess-r-beginning-of-function ;; when there is no function. This might change when we have aproper ;; ess-r-beginning-of-defun. ;; (should (eql 1 (ess-r-test-with-temp-text "mean(1:10)" ;; (goto-char (point-min)) ;; (ess-skip-thing 'function) ;; (point)))) ) (ert-deftest ess-next-code-line-test () (should (eql 5 (ess-r-test-with-temp-text "1+1\n#2+2\n#3+3\n4+4" (let ((ess-eval-empty t)) (goto-char (point-min)) (ess-next-code-line) (point))))) (should (eql 15 (ess-r-test-with-temp-text "1+1\n#2+2\n#3+3\n4+4" (let (ess-eval-empty) (goto-char (point-min)) (ess-next-code-line) (point))))) (should (eql 5 (ess-r-test-with-temp-text "1+1\n" (let (ess-eval-empty) (goto-char (point-min)) (end-of-line) (ess-next-code-line) (point)))))) (ert-deftest ess-Rout-file-test () (let* ((file (expand-file-name "file.Rout" ess-test-fixtures-directory)) (buf (or (find-buffer-visiting file) (find-file-noselect file)))) (with-current-buffer buf (should (eq major-mode 'ess-r-transcript-mode)) (goto-char (point-min)) (font-lock-default-fontify-buffer) (should (eq (face-at-point) 'font-lock-function-name-face))))) (ert-deftest inferior-ess-r-fontification-test () (ess-test-with-r-running nil (with-ess-process-buffer nil ;; Function-like keywords (should (eq major-mode 'inferior-ess-r-mode)) (ess-test-insert-fontified "for") (should (not (ess-test-face-at -1))) (ess-test-insert-fontified "(") (should (eq (ess-test-face-at -2) 'ess-keyword-face)) ;; `in` keyword (ess-test-insert-fontified "foo in bar)") (search-backward "in") (should (eq (face-at-point) 'ess-keyword-face)) (erase-buffer) (ess-test-insert-fontified "for foo in bar") (search-backward "in") (should (not (face-at-point)))))) ;; roxy (ert-deftest ess-roxy-preview-Rd-test () (let ((buf (generate-new-buffer " *temp*"))) (ess-test-with-r-running buf (if (member "roxygen2" (ess-installed-packages)) (should (string= "% Generated by roxygen2: do not edit by hand \\name{add} \\alias{add} \\title{Add together two numbers. add(10, 1)} \\usage{ add(x, y) } \\description{ Add together two numbers. add(10, 1) } " (with-current-buffer buf (R-mode) (ess-roxy-mode) (insert "##' Add together two numbers. add(10, 1) add <- function(x, y) { x + y }") (goto-char (point-min)) (ess-roxy-preview-Rd) ;; Delete the reference to the file which isn't ;; reproducible across different test environments (goto-char (point-min)) (forward-line 1) (kill-whole-line) (buffer-substring-no-properties (point-min) (point-max))))) (ert-skip "Roxygen2 not installed"))))) (ert-deftest ess-test-roxy-font-lock () (ess-r-test-with-temp-text "#' a function #' #' @param x the param #' @param y the other param my_mean <- function(x, y){ mean(x) + mean(y) }" (font-lock-ensure) (goto-char (point-min)) (search-forward "@par") (should (equal (face-at-point) 'font-lock-keyword-face)) (search-forward "x") (forward-char -1) (should (equal (face-at-point) 'font-lock-variable-name-face)) (search-forward "the para") (should (equal (face-at-point) 'font-lock-comment-face))) (ess-r-test-with-temp-text "#' @describeIn foo #' @export foo <- function(x){ mean(x) }" (font-lock-ensure) (goto-char (point-min)) (search-forward "@des") (should (equal (face-at-point) 'font-lock-keyword-face)) (search-forward "@exp") (should (equal (face-at-point) 'font-lock-variable-name-face)))) (ert-deftest ess-roxy-get-function-args-test () (ess-r-test-with-temp-text "#' a function #' #' @param x the param my_mean <- function(x, y){ mean(x) + mean(y) } #' another function #' #' @param z the param my_mean2 <- function(z){ mean(z) }" (should (equal (ess-roxy-get-function-args) '("x" "y"))) (search-forward "param z the param") (should (equal (ess-roxy-get-function-args) '("z"))))) (ert-deftest ess-roxy-update-entry-test () (should (string= "fun1 <- function(x) x ##' .. content for \\description{} (no empty lines) .. ##' ##' .. content for \\details{} .. ##' @title ##' @param x ##' @return ##' @author Jane Doe fun2 <- function(x) x" (ess-r-test-with-temp-text "fun1 <- function(x) x ¶fun2 <- function(x) x" (let ((ess-roxy-template-alist '(("description" . ".. content for \\description{} (no empty lines) ..") ("details" . ".. content for \\details{} ..") ("title" . "") ("param" . "") ("return" . "") ("author" . "Jane Doe")))) (ess-roxy-update-entry)) (buffer-substring-no-properties (point-min) (point-max)))))) (ert-deftest ess-roxy-cpp-test () ;; Test M-q (should (string= "//' Title //' //' @param Lorem ipsum dolor sit amet, consectetur adipiscing elit, //' sed do eiusmod. //' @param Lorem ipsum dolor sit amet, consectetur adipiscing elit, //' sed do eiusmod. //' @examples //' mean() " (ess-cpp-test-with-temp-text "//' Title //' //' @param Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod. //' @param ¶Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod. //' @examples //' mean() " (c-fill-paragraph) (buffer-substring-no-properties (point-min) (point-max))))) ;; Test newline (should (string= "//'\n//' " (ess-cpp-test-with-temp-text "//' ¶" (ess-roxy-newline) (buffer-substring-no-properties (point-min) (point-max))))) (should (string= "//\n" (ess-cpp-test-with-temp-text "//¶" (ess-roxy-newline) (buffer-substring-no-properties (point-min) (point-max)))))) ;; Navigation (ert-deftest ess-r-function-beg-end-test () (ess-r-test-with-temp-text "x <- function(a){\n a + 1\n}" (search-forward "(a)") (beginning-of-defun) (should (eql (point) 1)) (search-forward "(a)") (end-of-defun) (should (eql (point) 28)))) (ert-deftest ess-r-beginning/defun-limits-test () (with-ess-test-r-file (expand-file-name "navigation.R" ess-test-fixtures-directory) (goto-char (point-min)) (end-of-defun 1) (should (looking-back "end of fn1\n")) (beginning-of-defun 1) (should (looking-at "fn1 <-")) (beginning-of-defun -1) (should (looking-at "fn1 <-")) (end-of-defun 3) (should (looking-back "end of fn3\n")) (beginning-of-defun) (should (looking-at "fn3 <-")) (end-of-defun 2) (should (looking-back "setMethod\n")) (end-of-defun 1) (should (looking-back "end of fn4\n")) (beginning-of-defun 1) (should (looking-at "fn4 <-")) (beginning-of-defun 1) (should (looking-at "setMethod(")) (end-of-defun -1) (should (looking-back "fn3\n")) (re-search-forward "^f8 <-") (beginning-of-line) (end-of-defun 1) (should (looking-back "end of f8\n")) (end-of-defun -1) (should (looking-back "end of f5\n")))) (ert-deftest ess-r-beginning/function-limits-test-1 () (with-ess-test-r-file (expand-file-name "navigation.R" ess-test-fixtures-directory) (goto-char (point-min)) (ess-r-end-of-function 1) (should (looking-at " ## end of fn1")) (ess-r-beginning-of-function 1) (should (looking-at "fn1 <-")) (ess-r-beginning-of-function -1) (should (looking-at "fn1 <-")) (ess-r-end-of-function) (ess-r-end-of-function) (ess-r-end-of-function) (should (looking-at " ## end of fn3\n")) (ess-r-beginning-of-function) (should (looking-at "fn3 <-")) (ess-r-end-of-function) (ess-r-end-of-function) (should (looking-at " ## end of setMethod")) (ess-r-end-of-function 1) (should (looking-at " ## end of fn4")) (ess-r-beginning-of-function 1) (should (looking-at "inner_fn5 <-")) (ess-r-beginning-of-function 1) (should (looking-at "fn4 <-")) (ess-r-beginning-of-function 1) (should (looking-at "setMethod(")) (ess-r-end-of-function -1) (should (looking-at " ## end of fn3")))) (ert-deftest ess-r-beginning/function-limits-test-2 () (with-ess-test-r-file (expand-file-name "navigation.R" ess-test-fixtures-directory) (goto-char (point-min)) (re-search-forward "after f5") (ess-r-end-of-function) (should (looking-at ".* end of f6$")) (ess-r-end-of-function) (should (looking-at ".* end of f7")) (goto-char (point-min)) (re-search-forward "some_code6") (ess-r-beginning-of-function) (should (looking-at-p "f6 = function")) (re-search-forward "some_code7") (ess-r-beginning-of-function) (should (looking-at-p "f7 = function")) (goto-char (point-min)) (search-forward "f8 <-") (ess-r-beginning-of-function) (should (looking-at-p "f8 <-")) (goto-char (point-min)) (search-forward "f9 <-") (beginning-of-line 1) (ess-r-beginning-of-function) (should (looking-at-p "f8 <-")))) (ert-deftest ess-r-goto-beginning/end-of-function-or-para-test () (with-ess-test-r-file (expand-file-name "navigation.R" ess-test-fixtures-directory) (goto-char (point-min)) (ess-goto-end-of-function-or-para) (should (looking-back "fn1\n")) (ess-goto-beginning-of-function-or-para) (should (looking-at "fn1 <-")) (ess-goto-end-of-function-or-para) (ess-goto-end-of-function-or-para) (should (looking-back "fn2\n")) (ess-goto-end-of-function-or-para) (should (looking-back "fn3\n")) (ess-goto-end-of-function-or-para) (should (looking-back "par1\n")) (ess-goto-end-of-function-or-para) (should (looking-back "setMethod\n")) (ess-goto-beginning-of-function-or-para) (should (looking-at "setMethod")) (ess-goto-beginning-of-function-or-para) (should (looking-at "par1 <-")) (ess-goto-beginning-of-function-or-para) (should (looking-at "fn3 <-")))) (ert-deftest ess-r-beginning/end-of-defun-ignore-inner-fn-test () (with-ess-test-r-file (expand-file-name "navigation.R" ess-test-fixtures-directory) (goto-char (point-min)) (re-search-forward "fn5_body") (beginning-of-defun) (should (looking-at "fn4 <- ")) (re-search-forward "fn5_body") (end-of-defun) (should (looking-back "fn4\n")))) (ert-deftest ess-r-comment-dwim-test () "Test `comment-dwim' and Bug #434." (let ((ess-style 'RRR)) (ess-r-test-with-temp-text "#¶ " (let ((ess-indent-with-fancy-comments t)) (comment-dwim nil) (should (eql 42 (current-column))) (ess-indent-or-complete) (should (eql 42 (current-column))))) (ess-r-test-with-temp-text "#¶ " (let ((ess-indent-with-fancy-comments nil)) (comment-dwim nil) (should (eql 2 (current-column))) (ess-indent-or-complete) (should (eql 2 (current-column))))))) ;; imenu (ert-deftest ess-imenu-test () (ess-r-test-with-temp-text " library(knitr) x <- function(a) mean(a) y = function(c){ sum(c) } the_dat <- read.csv(\"foo.csv\")" (let ((result (funcall imenu-create-index-function))) (should (equal (car (nth 0 result)) "Data")) (should (equal (caadr (nth 0 result)) "the_dat")) (should (equal (car (nth 1 result)) "Package")) (should (equal (caadr (nth 1 result)) "knitr")) (should (equal (car (nth 2 result)) "Functions")) (should (equal (caadr (nth 2 result)) "x")) (should (equal (caaddr (nth 2 result)) "y"))))) (ert-deftest ess-narrow-to-defun-or-para-test () (ess-r-test-with-temp-text "mean(1:10) x <- function(x){ mean(x) }) " (goto-char (point-min)) (search-forward "mean(x)") (ess-narrow-to-defun-or-para) (goto-char (point-min)) (should (looking-at-p "x <- function(x){$")))) (ert-deftest ess-test-r-help-mode () (ess-test-with-r-running nil (let ((ess-pop-to-buffer t)) (ess-display-help-on-object "plot") (should (equal ess-help-object "plot")) (should (derived-mode-p 'ess-r-help-mode)) ;; Ensure help buffers after button presses are also in ;; `ess-r-help-mode', Bug#836 (forward-button 2) (push-button) (should (or (equal ess-help-object "plot.default") (equal ess-help-object "plot"))) (should (derived-mode-p 'ess-r-help-mode))))) (ert-deftest ess-test-r-index-mode () (skip-unless (not noninteractive)) (ess-test-with-r-running nil (let ((ess-pop-to-buffer t)) (ess-display-package-index "stats") (should (equal ess-help-object "stats")) (should (derived-mode-p 'ess-r-help-mode)) ;; Ensure help buffers after button presses are also in ;; `ess-r-help-mode', Bug#836 (forward-button 2) (push-button) (should (equal ess-help-object "plot.default")) (should (derived-mode-p 'ess-r-help-mode))))) (ert-deftest ess-transcript-comint-prompt-test () ;; Bug#853 (insert "> set.seed(1); (i <- rnorm(7)) [1] -0.6264538 0.1836433 -0.8356286 1.5952808 0.3295078 -0.8204684 0.4874291 > rep(i, 3) [1] -0.6264538 0.1836433 -0.8356286 1.5952808 0.3295078 -0.8204684 0.4874291 [8] -0.6264538 0.1836433 -0.8356286 1.5952808 0.3295078 -0.8204684 0.4874291 [15] -0.6264538 0.1836433 -0.8356286 1.5952808 0.3295078 -0.8204684 0.4874291 > sum(i) [1] 0.3133101") (ess-r-transcript-mode) (goto-char (point-min)) (comint-next-prompt 1) (should (equal (line-number-at-pos) 3))) (ert-deftest ess-test-r-startup-directory () (let ((proj-dir (expand-file-name "..")) (cur-dir (directory-file-name (expand-file-name default-directory)))) (let ((ess-startup-directory nil)) (ess-test-with-r-running nil (with-current-buffer (ess-get-process-buffer) (should (string= proj-dir (directory-file-name (expand-file-name default-directory))))))) (let ((ess-startup-directory 'default-directory)) (ess-test-with-r-running nil (with-current-buffer (ess-get-process-buffer) (should (string= cur-dir (directory-file-name (expand-file-name default-directory))))))))) (ert-deftest ess-test-r-comint-input-ring-file-name () (let ((ess-history-file t) (ess-startup-directory 'default-directory) ; don't start in the project ess-history-directory) (ess-test-with-r-running nil (should (string= (expand-file-name ".Rhistory" default-directory) (buffer-local-value 'comint-input-ring-file-name (ess-get-process-buffer)))))) (let ((ess-history-file "foo") (ess-history-directory temporary-file-directory)) (ess-test-with-r-running nil (should (string= (expand-file-name "foo" temporary-file-directory) (buffer-local-value 'comint-input-ring-file-name (ess-get-process-buffer)))))) (let ((ess-history-file t) (ess-history-directory temporary-file-directory)) (ess-test-with-r-running nil (should (string= (expand-file-name ".Rhistory" temporary-file-directory) (buffer-local-value 'comint-input-ring-file-name (ess-get-process-buffer)))))) (let (ess-history-file ess-history-directory) (ess-test-with-r-running nil (should-not (buffer-local-value 'comint-input-ring-file-name (ess-get-process-buffer)))))) (ert-deftest ess-test-roxy-prefix-strip () "Only strip prefix if the whole string is prefixed (#1020)" (let ((ess-roxy-re "^#+'")) (should (equal (ess-roxy-remove-roxy-re "#' 1\n#' 2") "1\n2")) (should (equal (ess-roxy-remove-roxy-re "#' 1\n#' 2\nNULL") "#' 1\n#' 2\nNULL")))) (defun ess-r-test-transcript-init () (ess-r-transcript-mode) (read-only-mode -1) (ess-test-r-set-local-process)) (etest-deftest ess-r-transcript-motions-test () "[enter] handles commands, non-commands, and prompts (#1013)." :init ((eval . (ess-r-test-transcript-init))) :case " ¶R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. " "RET" :result " R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. ¶" :inf-result " > " :messages "No command at this point" :case " > ¶for(i in 1:3) { + print(i) + } [1] 1 [1] 2 [1] 3 " "RET" :result " > for(i in 1:3) { + print(i) + } [1] 1 [1] 2 [1] 3 ¶" :inf-result "for(i in 1:3) { + print(i) + } [1] 1 [1] 2 [1] 3 > ") (etest-deftest ess-r-eval-linewise-visibly-test () "C-c C-n always evaluates visibly. https://github.com/emacs-ess/ESS/issues/725#issuecomment-431781558" :init ((mode . r) (eval . (ess-test-r-set-local-process))) :case " ¶1 2 3 " (setq-local ess-eval-visibly-p 'nowait) "C-c C-n" :result " 1 ¶2 3 " :inf-result "1 [1] 1 > " (setq-local ess-eval-visibly-p nil) "C-c C-n" :result " 1 2 ¶3 " :inf-result "2 [1] 2 > ") (ert-deftest ess-r-commands-test () "M-x R works (#1035)" (should (commandp 'R)) (should (commandp 'R-newest))) (etest-deftest ess-command-last-value-test () "`ess-command` preserves `.Last.value (#1058)" :case "100¶" "C-c C-c" :inf-result "100 [1] 100 > " :case ".Last.value¶" "C-c C-c" :inf-result ".Last.value [1] 100 > " (ess-command "-1\n") :case ".Last.value¶" "C-c C-c" :inf-result ".Last.value [1] 100 > ") (etest-deftest ess-r-pager-test () (should (string= (car (ess-get-words-from-vector "getOption('pager')\n")) "cat"))) ;; rdired (require 'ess-rdired) (etest-deftest ess-rdired-test () :inf-cleanup (progn (kill-buffer ess-rdired-buffer) (ess-command "rm(my_rdired_variable, envir = globalenv())\n")) (ess-command "assign('my_rdired_variable', TRUE, envir = globalenv())\n") (save-window-excursion (ess-rdired)) (with-current-buffer ess-rdired-buffer (goto-char (point-min)) (should (re-search-forward "my_rdired_variable" nil t)))) ;; help (ert-deftest ess-help-get-pkg-from-help-path-test () "Handles packages with `.` in name (#1101)." (should (string= (ess-r-help--get-pkg-from-help-path "~/library/4.0/data.table/help/data.table") "data.table"))) ;; Utils for inferior R process (ert-deftest ess-mock-remote-process () ;; Check that our test is doing what we think it should, namely that it is ;; creating a mock remote process (i.e. a test of our test setup) (with-ess-test-r-file (ess-test-create-remote-path "dummy-pkg/R/test.R") (ess-test-with-r-running (current-buffer) (should (file-remote-p (ess-get-process-variable 'default-directory)))) (kill-buffer))) ;; The assertions in this test do NOT require an internet connection (ert-deftest ess-r-load-ESSR-github-fetch-no () ;; Local ESSR load (ess--essr-load-or-throw-error "dummy-pkg/R/test.R" #'ess-r--load-ESSR-local) ;; Remote ESSR injection through process connection (ess--essr-load-or-throw-error (ess-test-create-remote-path "dummy-pkg/R/test.R") #'ess-r--load-ESSR-remote)) ;; The assertions in this test DO require an internet connection (ert-deftest ess-r-load-ESSR-github-fetch-yes () ;; Skip test when performing as part of the CI (when (equal (getenv "TRAVIS") "true") (ert-skip "Running on TRAVIS")) (let* ((remote-file-path (ess-test-create-remote-path "dummy-pkg/R/test.R")) (essr-nm (concat "ESSRv" essr-version ".rds")) (essr-path (expand-file-name essr-nm "~/.config/ESSR"))) ;; Ensure that ESSR doesn't currently exist on the machine which in turn ;; ensures that a GitHub fetch will be required to load ESSR. Note that for ;; Emacs <= 25 `delete-file' throws an error if the file doesn't exist. (ignore-errors (delete-file essr-path)) ;; Remote ESSR load through GitHub fetch (ess--essr-load-or-throw-error remote-file-path #'ess-r--fetch-ESSR-remote) ;; ESSR has already been loaded on the remote machine, so this time the ;; function doesn't make a GitHub fetch (should (file-exists-p essr-path)) (ess--essr-load-or-throw-error remote-file-path #'ess-r--fetch-ESSR-remote))) (ert-deftest ess-r-failed-init-disable-bg-eval-test () (ess-test-with-r-running nil (should-error (ess-r--init-error-handler)) (should (not (ess-can-eval-in-background))) (let ((proc (ess-get-current-process))) (should (and proc (not (eq (ess-get-next-available-bg-process) proc)))))) (unwind-protect (progn (setenv "ESSR_TEST_LOAD_ERROR" "true") (let ((err (should-error (progn (run-ess-test-r-vanilla) (with-current-buffer buf (ess-wait-for-process nil nil nil nil 2)))))) (with-current-buffer inferior-ess--last-started-process-buffer (should (string-match-p "Loading failed with a nice message." (caddr err))) (should (not (ess-can-eval-in-background))) (should (not (ess-process-get 'format-command-alist))) (ess-send-string (ess-get-current-process) "Sys.unsetenv('ESSR_TEST_LOAD_ERROR')\n") ;; Can recover manually (ess-r-initialize) (should (ess-can-eval-in-background)) (should (ess-process-get 'format-command-alist))))) (setenv "ESSR_TEST_LOAD_ERROR" nil))) (etest-deftest ess-r-command-error-test () (let ((err (should-error (ess-command "stop('bar')\n")))) (should (string-match-p "R error during background ESS command â€stop('bar')’\nError: bar" (cadr err)))) :inf-result "") (ert-deftest ess-r-post-run-hook-test () "ESS waits before running user hook so that blocking commands may be used." (let* (result (ess-r-post-run-hook (list (lambda () (setq result (ess-get-words-from-vector "'foo'\n")))))) (ess-test-with-r-running nil) (should (equal result (list "foo"))))) (provide 'ess-test-r) ;; Local Variables: ;; etest-local-config: etest-r-config ;; End: ;;; ess-test-r.el ends here ESS-24.01.1/test/ess-test-rd.el000066400000000000000000000025071455642170100157750ustar00rootroot00000000000000;;; ess-test-rd.el --- ESS tests for Rd-mode -*- lexical-binding: t; -*- ;; ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; ;; This file 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. ;; ;; A copy of the GNU General Public License is available at ;; https://www.r-project.org/Licenses/ ;; ;;; Commentary: ;; (require 'ert) (require 'etest "etest/etest") (require 'ess-r-mode) (require 'ess-test-r-utils) (require 'ess-rd) ;;; Code: (defun ess-r-test-rd-init () (Rd-mode) (ess-test-r-set-local-process)) (etest-deftest ess-rd-eval-linewise-visibly-test () "C-c C-n always evaluates visibly. https://github.com/emacs-ess/ESS/issues/725#issuecomment-431781558" :init ((eval . (ess-r-test-rd-init))) :case " \\examples{ ¶1 2 3 } " (setq-local ess-eval-visibly-p 'nowait) "C-c C-n" :result " \\examples{ 1 ¶2 3 } " :inf-result "1 [1] 1 > " (setq-local ess-eval-visibly-p nil) "C-c C-n" :result " \\examples{ 1 2 ¶3 } " :inf-result "2 [1] 2 > " ) ESS-24.01.1/test/ess-test-roxy.el000066400000000000000000000057271455642170100164000ustar00rootroot00000000000000;;; ess-test-roxy.el --- ESS tests for Roxygen -*- lexical-binding: t; -*- ;; ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; ;; This file 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. ;; ;; A copy of the GNU General Public License is available at ;; https://www.r-project.org/Licenses/ ;; ;;; Commentary: ;; (require 'ert) (require 'etest "etest/etest") (require 'ess-r-mode) (defun ess-test--faces-at-point () (let ((face (get-char-property (point) 'face))) (if (listp face) face (list face)))) (etest-deftest ess-roxy-fill-paragraph-test () :case " ##' Title ##' ##' @param¶ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. ¶##' @param Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. " "M-q" :result " ##' Title ##' ##' @param¶ Lorem ipsum dolor sit amet, consectetur adipiscing elit, ##' sed do eiusmod tempor incididunt ut labore et dolore magna ##' aliqua. Ut enim ad minim veniam, quis nostrud exercitation ##' ullamco laboris nisi ut aliquip ex ea commodo consequat. ¶##' @param Lorem ipsum dolor sit amet, consectetur adipiscing elit, ##' sed do eiusmod tempor incididunt ut labore et dolore magna ##' aliqua. Ut enim ad minim veniam, quis nostrud exercitation ##' ullamco laboris nisi ut aliquip ex ea commodo consequat. ") (etest-deftest ess-roxy-ret-test () :case " ##' ¶ " "RET" :result " ##' ##' ¶ " "RET" :result " ##' ##' ##' ¶ " (setq-local ess-roxy-insert-prefix-on-newline nil) "RET" :result " ##' ##' ##' ¶ " :case " ##' ¶ " "M-j" :result " ##' ##' ¶ ") (etest-deftest ess-roxy-faces-param-test () :case " ##' ¶@param foo ##' @¶param foo " (should (memq 'font-lock-keyword-face (ess-test--faces-at-point))) :case " ##' @param ¶foo " (should (not (memq 'font-lock-keyword-face (ess-test--faces-at-point)))) (should (memq 'font-lock-variable-name-face (ess-test--faces-at-point))) ;; Comma-separated params :case " ##' @param ¶foo,bar baz ##' @param foo¶,bar baz ##' @param foo,¶bar baz NULL " (should (memq 'font-lock-variable-name-face (ess-test--faces-at-point))) :case " ##' @param foo,bar ¶baz NULL " (should (not (memq 'font-lock-variable-name-face (ess-test--faces-at-point))))) ;; Local Variables: ;; etest-local-config: etest-r-config ;; End: ESS-24.01.1/test/ess-test.el000066400000000000000000000037071455642170100153750ustar00rootroot00000000000000;;; ess-test.el --- ESS tests -*- lexical-binding: t; -*- ;; ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; ;; This file 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. ;; ;; A copy of the GNU General Public License is available at ;; https://www.r-project.org/Licenses/ ;; ;;; Commentary: ;; ESS tests (require 'ert) (require 'ess-site) ;;; Code: (unless (fboundp 'provided-mode-derived-p) ;; From dev Emacs (defun provided-mode-derived-p (mode &rest modes) (while (and (not (memq mode modes)) (setq mode (get mode 'derived-mode-parent)))) mode)) (ert-deftest ess-mode-inherits-prog-mode () (should (unless nil (provided-mode-derived-p 'ess-mode 'prog-mode)))) ;; Ensure that major modes can be invoked without errors: (ert-deftest R-mode () (should (string= 'ess-r-mode (with-temp-buffer (R-mode) major-mode)))) (ert-deftest ess-jags-mode () (should (string= 'ess-jags-mode (with-temp-buffer (ess-jags-mode) major-mode)))) (ert-deftest ess-bugs-mode () (should (string= 'ess-bugs-mode (with-temp-buffer (ess-bugs-mode) major-mode)))) (ert-deftest ess-julia-mode () (skip-unless (and (require 'julia-mode nil t) (require 'ess-julia))) (should (string= 'ess-julia-mode (with-temp-buffer (ess-julia-mode) major-mode)))) (ert-deftest sas-mode () (should (string= 'SAS-mode (with-temp-buffer (SAS-mode) major-mode)))) ;; Various tests from e.g. ess-utils.el (ert-deftest ess-flatten-list () (should (equal (list 'a 'b 'c 'd 'e 'f 'g 'h 'i 'j) (ess-flatten-list '((a . b) c (d . e) (f g h) i . j))))) (provide 'ess-test) ;;; ess-test.el ends here ESS-24.01.1/test/etest/000077500000000000000000000000001455642170100144215ustar00rootroot00000000000000ESS-24.01.1/test/etest/.nosearch000066400000000000000000000000001455642170100162120ustar00rootroot00000000000000ESS-24.01.1/test/etest/README.md000066400000000000000000000202271455642170100157030ustar00rootroot00000000000000 # Introduction etest is an ERT extension to make it easier to test Emacs behavior such as cursor and mark movement and inferior buffer output. This package contains programming tools as well as user commands. Add `ESS/test/etest/` to your load-path or install it with: ``` M-x package-install-file ``` # Usage The interface of etest is inspired by the ERT and use-package macros. Like ERT, the `etest-deftest` macro has a similar syntax to `defun` and `defmacro`. It takes an ERT test name, an empty list of arguments, and an optional documentation string: ```elisp (etest-deftest my-test () "Documentation string for the unit test.") ``` This macro wraps around `ert-deftest` so these tests can be run with the usual ERT tools. ## Defining test cases At its heart, the `etest-deftest` macro is an interpreter of lisp forms and keywords command. The main keywords to know about are `:case` and `:result`. ### `:case` All etest tests are run in a dedicated buffer. The `:case` takes a string that defines the content of the test buffer. The special characters `¶` and `Ă—` specify the positions of the Emacs point and mark cursors in that buffer. These characters were chosen to be 1 character wide so they don't distract from the general structure of the test case, and outside of the ASCII range so they don't conflict with valid symbols in the tested languages. ```elisp (etest-deftest my-test () :case "¶Initial text in the test buffer.") ``` The mark cursor `Ă—` is optional. When the point cursor `¶` is omitted, the cursor is set at `(point-min)`. ### Lisp forms and commands Any lisp form that isn't prefixed with a keyword is evaluated as lisp. These forms may contain ert code such as `should` or may cause side effects in the test buffer. ```elisp (etest-deftest my-test () :case "¶Initial text in the test buffer." (forward-word) ``` These free forms may also be commands described in strings as key descriptions (the sort that you would pass to `kbd`). The key is looked up in the active keymaps of the test buffer: ```elisp (etest-deftest my-test () :case "¶Initial text in the test buffer." "M-f" ``` These can be freely mixed: ```elisp (etest-deftest my-test () :case "¶Initial text in the test buffer." "M-f" (forward-word) "M-f" ``` ### `:result` You can test how these commands affect the test buffer with the `:result` keyword. An easy way to add this keyword is to first supply an empty string: ```elisp (etest-deftest my-test () :case "¶Initial text in the test buffer." "M-f" :result "") ``` Then move the point inside the `etest-deftest` block and call `M-x etest-update`. This function runs the test command in the dedicated test buffer, examines the state of the buffer for each `:result` keyword, and updates it in place. You should now see the `:result` value filled in: ```elisp (etest-deftest my-test () :case "¶Initial text in the test buffer." "M-f" :result "Initial¶ text in the test buffer.") ``` This block has now become a unit test for the behavior of the `"M-f"` keybinding. When ERT runs the test, the contents of the buffer as well as the position of the cursor after typin `"M-f"` must correspond to the comparison case recorded in `:result`, otherwise the test fails. Note that you don't need a `:result` keyword to perform tests. You can also use `should` statement or any other ERT testing device in keyword-free forms: ```elisp (etest-deftest my-test () :case "¶Initial text in the test buffer." (should (looking-at "Initial"))) ``` ## Initializing and cleaning up the test buffer ### `:init` By default, the test buffer is in fundamental mode. The `:init` keyword offers a convenient initialization syntax. It takes an alist of local variables with the same syntax as [directory local variables](https://www.gnu.org/software/emacs/manual/html_node/emacs/Directory-Variables.html). ```elisp (etest-deftest my-test () :init ((mode . text) (var . value))) ``` The `eval` command supports arbitrary lisp code. This is a convenient way of abstracting initialization in a function: ```elisp (defun my-init () (text-mode 1) (setq var value)) (etest-deftest my-test () :init ((eval . (my-init)))) ``` ### `:cleanup` The `:cleanup` takes lisp expressions evaluated in LIFO order with unwind protection when the test exits. It is useful to clean up side effects introduced in your tests: ```elisp (defun my-init () (setq-local my-buf (get-buffer-create "my-buffer"))) (etest-deftest my-test () :init ((eval . (my-init))) :cleanup (kill-buffer my-buf)) ``` ## Reusing mode-specific configuration Mode-specific configuration can be stored in a variable or created with a function. This typically includes an `:init` keyword that sets up the major-mode for the test buffer: ```elisp (defvar my-config '(:init ((mode . text)))) ``` The configuration may contain any valid etest code and is registered with the `:config` keyword. This keyword must appear before any other keywords: ```elisp (etest-deftest my-test () :config my-config)) ``` You can also set it with the buffer-local variable `etest-local-config`. It is convenient to set it as a file-local variable, this way `etest-update` is automatically aware of the configuration relevant to the test file. ```elisp (etest-deftest my-test ()) ;; Local Variables: ;; etest-local-config: my-config ;; End: ``` If supplied, the `:config` keyword has precedence over the configuration stored in `etest-local-config` and completely replaces it. ## Checking the contents of an inferior buffer In addition to checking the side effects in the test buffer, it is often useful to check the side effects in an auxiliary buffer. For instance, checking the output in an inferior process buffer. ### `:inf-buffer` Let's define rudimentary initialization and cleanup functions for an R inferior. These save the inferior buffer in a buffer-local variable `inf-buf`. ```elisp (defun my-inferior-init () (setq-local inf-buf (run-ess-r)) (setq-local inf-proc (get-buffer-process inf-buf)) (setq ess-local-process-name (process-name inf-proc)) (with-current-buffer inf-buf (comint-clear))) (defun my-inferior-cleanup () (kill-process inf-proc)) ``` Use `:inf-buffer` keyword to set up `inf-buf` as the inferior buffer to monitor: ```elisp (etest-deftest my-test () :init ((mode . r) (eval . (my-inferior-init))) :cleanup (my-inferior-cleanup) :inf-buffer inf-buf) ``` This enables usage of `:inf-result`. ### `:inf-result` We'll test the result of calling `C-c C-c` in a buffer containing `1 + 1`. The `:inf-result` keyword is similar to `:result`. Set it to the empty string to start with: ```elisp (etest-deftest my-test () :init ((mode . r) (eval . (my-inferior-init))) :cleanup (my-inferior-cleanup) :inf-buffer inf-buf :case "1 + 1" "C-c C-c" :inf-result "") ``` After calling `etest-update` we get: ```elisp (etest-deftest my-test () :init ((mode . r) (eval . (my-inferior-init))) :cleanup (my-inferior-cleanup) :inf-buffer inf-buf :case "1 + 1" "C-c C-c" :inf-result "> 1 + 1 [1] 2 > ") ``` ## Other features ### Using multiple cursors Use multiple `¶` characters to define multiple cursors. Lisp code and commands are run once for each cursor. This is useful for testing motions on many keywords at a time for instance: ```elisp (etest-deftest my-test () :case "¶if ¶while ¶for" "M-f" :result "if¶ while¶ for¶") ``` Or for testing properties of many keywords: ```elisp (etest-deftest my-test () "Test that control flow keywords are only fontified if they are followed by an open parenthesis." :init ((mode . r)) :case "¶if ¶while ¶for" (should (not (face-at-point))) :case "¶if () ¶while () ¶for ()" (should (eq (face-at-point) 'ess-keyword-face))) ``` ### Checking messages #### `:messages` Messages are normally inhibited during the duration of the test. If you want to check the messages, use the `:messages` keyword. As usual, start with an empty string value: ```elisp (etest-deftest my-test () (message "foo") (message "bar") :messages "") ``` And call `etest-update` to define a comparison case: ```elisp (etest-deftest my-test () (message "foo") (message "bar") :messages "foo bar") ``` ESS-24.01.1/test/etest/etest.el000066400000000000000000000352621455642170100160770ustar00rootroot00000000000000;;; etest.el --- Emacs behavioural test framework -*- lexical-binding: t; -*- ;; Copyright (C) 2014-2022 Free Software Foundation, Inc. ;; Author: ;; Lionel Henry ;; Oleh Krehel ;; Version: 1.0.0 ;; Package-Requires: ((ert)) ;; Keywords: tools, unit-test ;; URL: https://github.com/emacs-ess/ESS/tree/master/test/etest ;;; Commentary: ;; etest makes it easy to test the behaviour of Emacs commands. See ;; the project README for documentation. ;;; Code: (require 'ert) (eval-when-compile (require 'cl-lib)) (defvar-local etest-local-inferior-buffer nil "External buffer containing output to check. Use the `:inf-result' to flush this buffer and test its contents.") (defvar-local etest-local-config nil "Local configuration for `etest-deftest'. List of etest keywords and commands, e.g. an `:init' spec to set up a particular mode.") ;; Evaluate symbols to make it easier to set local variables (defmacro etest--push-local-config (place) `(unless (eq (car ,place) :config) (let ((etest--config (cond ((not etest-local-config) nil) ((symbolp etest-local-config) (eval etest-local-config t)) (t etest-local-config)))) (when etest--config (setq ,place (append etest--config ,place)))))) (cl-defmacro etest-deftest (name args &body body) (declare (doc-string 3) (indent 2)) (let ((etest--docstring (when (stringp (car body)) (list (pop body))))) ;; Record this at compile time because ert doesn't run tests locally (etest--push-local-config body) `(ert-deftest ,name ,args ,@etest--docstring (etest--run-test (quote ,body) (lambda (actual expected) (should (string= actual expected))))))) (defmacro etest--setup-body (place) `(progn (when (eq (car ,place) :config) (pop ,place) (setq ,place (append (eval (pop ,place) t) ,place))) (etest--pop-init ,place))) (defmacro etest--pop-init (place) `(let (local) (while (eq (car ,place) :init) (pop ,place) (setq local (append local (pop ,place)))) local)) (defmacro etest--with-test-buffer (init &rest body) (declare (indent 1) (debug (&rest form))) `(let ((etest--buf (etest--new-buffer ,init))) (unwind-protect (with-current-buffer etest--buf ,@body) (kill-buffer etest--buf)))) (defun etest--new-buffer (init) (let ((buf (generate-new-buffer " *elt-temp*"))) (with-current-buffer buf (setq-local file-local-variables-alist (nreverse (copy-alist init))) (hack-local-variables-apply) (transient-mark-mode 1)) buf)) (defun etest--run-test (body do-result) "Parse BODY as list of expressions. `:eval' arguments are evaluated in a dedicated buffer. The keyword can be a command or a list of commands. Strings are interpreted as `kbd' commands. Top-level expressions are evaluated in the same way as `:eval' arguments. The buffer is initialised with the list of local variables found in `:init' keywords. The `:cleanup' keyword takes unwind-protected expressions that are evaluated in LIFO order after the test succeeds or fails. `:result' keywords are processed with DO-RESULT. This should be a function taking ACTUAL and EXPECTED strings. `:inf-buffer' takes an auxiliary buffer whose contents can be tested with `:inf-result'. The latter keyword work similarly to `:result' but returns the current output in the inferior buffer. This buffer is flushed. The inferior buffer is stored in the buffer-local variable `etest-local-inferior-buffer'. `:messages' keywords check the contents of the messages buffers and are processed with DO-RESULT." (etest--with-test-buffer (etest--setup-body body) (let ((etest--msg-sentinel (etest--make-message-sentinel)) (etest--last-case "") etest--cleanup) (unwind-protect (while body (if (keywordp (car body)) (let ((etest--key (pop body)) (etest--value (pop body))) (pcase etest--key (`:inf-buffer (setq etest-local-inferior-buffer (eval etest--value t))) (`:cleanup (push etest--value etest--cleanup)) (`:inf-cleanup (push `(progn ,etest--value (etest--wait-for-inferior) (etest-clear-inferior-buffer)) etest--cleanup)) (`:case (progn (erase-buffer) (setq last-command nil) (if (eq etest--value 'reset) (insert etest--last-case) (insert etest--value) (setq etest--last-case etest--value)))) (`:eval (etest-run (current-buffer) (etest--wrap-test etest--value))) (`:result (funcall do-result (etest--result (current-buffer)) etest--value)) (`:inf-result (etest--flush-inferior-buffer do-result etest--value)) (`:messages (progn (etest--flush-messages etest--msg-sentinel do-result etest--value) (setq etest--msg-sentinel (etest--make-message-sentinel)))) (_ (error (format "Expected an etest keyword, not `%s`" etest--key))))) (etest-run (current-buffer) (etest--wrap-test (pop body))))) (mapc #'eval etest--cleanup))))) (defun etest--wrap-test (x) (if (or (not (listp x)) (symbolp (car x))) (list x) x)) (defun etest--wait-for-inferior () (unless etest-local-inferior-buffer (error "Must set `etest-local-inferior-buffer'")) (let* ((inf-buf etest-local-inferior-buffer) (inf-proc (get-buffer-process inf-buf))) ;; Wait until a trailing prompt for maximum 10ms (with-current-buffer inf-buf (save-excursion (let ((times 0)) (while (and (< times 10) (not (re-search-forward "> \\'" nil t))) (accept-process-output inf-proc 0.001) (goto-char (point-min)) (setq times (1+ times)))))))) (defun etest--flush-inferior-buffer (do-result value) (unwind-protect (progn (etest--wait-for-inferior) (funcall do-result (etest--result etest-local-inferior-buffer t) value)) (etest-clear-inferior-buffer))) (defun etest-clear-inferior-buffer () (with-current-buffer etest-local-inferior-buffer (let ((inhibit-read-only t)) (erase-buffer)))) (defun etest--make-message-sentinel () (let ((sentinel (format "etest-messages-%s" (gensym))) (inhibit-message t)) (message sentinel) sentinel)) (defun etest--flush-messages (msg-sentinel do-result value) (let ((msgs (with-current-buffer (get-buffer "*Messages*") (save-excursion (goto-char (point-min)) (re-search-forward msg-sentinel nil t) (let ((start (1+ (point)))) (buffer-substring start (max start (1- (point-max))))))))) (funcall do-result msgs value))) ;;; Update expected results in a test block (defvar etest--result-re "[ \n\t]*:\\(\\(inf-\\)?result\\|messages\\) *\s\"") ;;;###autoload (defun etest-update () "Update all result keywords for the etest block at point. Move point into an `etest-deftest' block and call this function to update the value of `:result', `:inf-result', and `:messages' keywords." (interactive) (save-window-excursion (save-excursion (let* ((beg (etest--climb-deftest)) (end (progn (forward-sexp) (point-marker))) (str (buffer-substring-no-properties beg end)) (body (car (read-from-string str)))) ;; Skip `etest-deftest` and initial arguments (dotimes (_i 3) (pop body)) (when (stringp (car body)) (pop body)) (etest--push-local-config body) (let ((results (etest--read-results body))) (goto-char beg) (forward-char 1) (while results (while (and (etest--forward-sexp) (prog1 t (while (forward-comment 1))) (not (looking-at-p etest--result-re)))) (unless (looking-at-p etest--result-re) (error "Can't find any result keyword")) (re-search-forward etest--result-re end t) (let ((result-beg (1- (point))) (result-end (progn (etest--backward-up-strings) (etest--forward-sexp) (point))) (result-str (prin1-to-string (pop results)))) (goto-char result-beg) (delete-region result-beg result-end) (insert result-str) (etest--forward-sexp -1)))))))) (defun etest--read-results (body) (let (results) (etest--run-test body (lambda (actual _expected) (push actual results))) (nreverse results))) (defun etest--forward-sexp (&optional N) (or N (setq N 1)) (condition-case nil (prog1 t (goto-char (or (scan-sexps (point) N) (buffer-end N)))) (error nil))) (defun etest--backward-up-strings () (let ((syntax (syntax-ppss (point)))) (while (nth 3 syntax) (goto-char (nth 8 syntax)) (setq syntax (syntax-ppss (point)))))) (defun etest--climb-deftest () ;; Climb one character when point is in front of a parenthesis. ;; This puts the cursor inside the `etest-deftest` when it is in ;; front. (etest--backward-up-strings) (unless (looking-at "(") (ignore-errors (backward-char 1)) (unless (looking-at ")") (ignore-errors (forward-char 1)))) ;; Climb enclosing lists until we find the `test-deftest` (while (and (not (looking-at "(etest-deftest")) (ignore-errors (prog1 t (backward-up-list nil t t))))) (point)) ;;; Run commands with cursor and mark tracking ;; The following code is adapted from the `lispy-with' macro by Oleh ;; Krehel in . ;; The main difference is support for multiple cursors. (defun etest-run (buf cmds &optional _reset-state) "Run CMDS in BUF. If RESET-STATE is non-nil, `last-command' and `current-prefix-arg' are set to nil for all cursors." ;; FIXME: `reset-state' is not used! (with-current-buffer buf (goto-char (point-min)) (when (search-forward "Ă—" nil t) (backward-delete-char 1) (set-mark (point)) (when (search-forward "Ă—" nil t) (error "There can only be one mark cursor"))) (goto-char (point-max)) (let (cursors-start cursors-end) (while (search-backward "¶" nil t) (delete-char 1) (let ((marker (point-marker))) (set-marker-insertion-type marker t) (push marker cursors-start))) (unless cursors-start (setq cursors-start (list (point-min)))) ;; Fontification must take place after removing "¶" (font-lock-ensure) (let ((current-lc last-command) (current-cpa current-prefix-arg)) (dolist (cursor cursors-start) (goto-char cursor) ;; Reset Emacs state for each cursor (setq last-command current-lc) (setq current-prefix-arg current-cpa) (mapc (lambda (x) (cond ((equal x '(kbd "C-u")) (setq current-prefix-arg (list 4))) ((stringp x) (if (string= x "C-u") (setq current-prefix-arg (list 4)) (etest--unalias (kbd x)))) ((and (listp x) (eq (car x) 'kbd)) (etest--unalias x)) (t (let ((inhibit-message t)) (eval x t))))) cmds) (let ((marker (point-marker))) (set-marker-insertion-type marker t) (push marker cursors-end)))) (dolist (cursor cursors-end) (goto-char cursor) (insert "¶"))) (when (region-active-p) (exchange-point-and-mark) (insert "Ă—") (exchange-point-and-mark)) t)) (defun etest--result (buf &optional trim-last-newline) (with-current-buffer buf (let ((beg (point-min)) (end (point-max))) (when (and trim-last-newline (> end beg) (string= (buffer-substring (1- end) end) "\n")) (setq end (1- end))) (buffer-substring-no-properties beg end)))) (defun etest--unalias (seq) "Emulate pressing keys decoded from SEQ." (if (vectorp seq) (etest--unalias-key seq (key-binding seq)) (let ((lkeys (etest--decode-keysequence seq)) (current-prefix-arg current-prefix-arg) key) (while (setq key (pop lkeys)) (when (numberp key) (setq current-prefix-arg (list key)) (setq key (pop lkeys))) (let ((cmd (key-binding key))) (while (keymapp cmd) (setq key (pop lkeys)) (setq cmd (lookup-key cmd key))) (etest--unalias-key key cmd)))))) (defun etest--unalias-key (key cmd) "Call command that corresponds to KEY. Insert KEY if there's no command." (setq last-input-event (aref key 0)) (cond ((eq cmd 'self-insert-command) (insert key)) ((null cmd) (error "Can't find binding in keymap")) (t (setq last-command-event (aref key 0)) (setq this-command cmd) (let ((inhibit-message t)) (call-interactively cmd)) (setq last-command cmd)))) (defun etest--decode-keysequence (str) "Decode STR from e.g. \"23ab5c\" to ='(23 \"a\" \"b\" 5 \"c\")" (let ((table (copy-sequence (syntax-table)))) (cl-loop for i from ?0 to ?9 do (modify-syntax-entry i "." table)) (cl-loop for i from ? to ? do (modify-syntax-entry i "w" table)) (cl-loop for i in '(? ?\( ?\) ?\[ ?\] ?{ ?} ?\" ?\' ?\ ) do (modify-syntax-entry i "w" table)) (cl-mapcan (lambda (x) (let ((y (ignore-errors (read x)))) (if (numberp y) (list y) (mapcar #'string x)))) (with-syntax-table table (split-string str "\\b" t))))) (provide 'etest) ;;; etest.el ends here ESS-24.01.1/test/etest/test-etest.el000066400000000000000000000152731455642170100170540ustar00rootroot00000000000000;; -*- lexical-binding: t -*- (require 'ert) (require 'etest "../etest") (etest-deftest etest-local-vars-test () "`:init' keyword specifies local variables." :init ((mode . text) (foo . t)) :init ((bar . t)) (should (eq major-mode 'text-mode)) (should foo) (should bar)) (etest-deftest etest-test-result-test () "`:eval' causes side effects in test buffer and `:result' checks output." :case "¶foo bar" :eval (forward-word) :result "foo¶ bar" :eval ((forward-char) (forward-char)) :eval ((forward-char) "RET") :result "foo ba\n¶r") (etest-deftest etest-climb-deftest-test () "Find enclosing `etest-deftest'." ;; Within parentheses :case " (etest-deftest name () (foo (bar¶)) " (etest--climb-deftest) :result " ¶(etest-deftest name () (foo (bar)) " ;; Within a string :case " (etest-deftest name () (foo \"bar¶\") " (etest--climb-deftest) :result " ¶(etest-deftest name () (foo \"bar\") " ;; Behind deftest :case " ¶(etest-deftest name () :foo) " (etest--climb-deftest) :result " ¶(etest-deftest name () :foo) " ;; In front of deftest :case " (etest-deftest name () :foo)¶ " (etest--climb-deftest) :result " ¶(etest-deftest name () :foo) ") (etest-deftest etest-update-test () "`etest-update' updates test block at point." :case " (etest-deftest test-etest-update () :case \"¶foo bar\" (forward-word) :result \"\" (forward-char) (forward-char) (forward-char) \"RET\" :result \"\") " (etest-update) :result " (etest-deftest test-etest-update () :case \"¶foo bar\" (forward-word) :result \"foo¶ bar\" (forward-char) (forward-char) (forward-char) \"RET\" :result \"foo ba ¶r\") ") (etest-deftest etest-update-result-not-on-bol-test () "`etest-update' works when `:result` is not at bol." :case " (etest-deftest test-etest-update () :case \"¶foo bar\" (forward-word) :result \"\" (forward-word) :result \"\") " (etest-update) :result " (etest-deftest test-etest-update () :case \"¶foo bar\" (forward-word) :result \"foo¶ bar\" (forward-word) :result \"foo bar¶\") ") (etest-deftest etest-keep-state-test () "`last-command' is preserved. Using multiple cursors in the test to make sure Emacs state is reset after a cursor has finished evaluating." :case "¶foo ¶bar" "M-f" (should (eq last-command 'forward-word)) ;; Ideally we'd test `this-command` at the time "M-f" is ;; called but for simplicity we do it here (should (eq this-command 'forward-word)) "M-b" (should (eq last-command 'backward-word)) (should (eq this-command 'backward-word)) :result "¶foo ¶bar") (ert-deftest etest-wrap-test-keyword-test () "`:eval' keywords are appropriately wrapped in lists." (should (equal (etest--wrap-test "foo") '("foo"))) (should (equal (etest--wrap-test 'foo) '(foo))) (should (equal (etest--wrap-test '(foo)) '((foo)))) (should (equal (etest--wrap-test '((foo))) '((foo))))) (etest-deftest etest-cleanup-test () "`:cleanup' keywords are evaluated in LIFO order." :init ((foo . "foo") (bar . "bar")) :cleanup (progn (should (equal foo "FOO")) (should (equal bar "BAR"))) :cleanup (progn (should (equal foo "foo")) (should (equal bar "BAR")) (setq foo "FOO")) :cleanup (progn (should (equal foo "foo")) (should (equal bar "bar")) (setq bar "BAR"))) (etest-deftest etest-inferior-buffer-test () "Inferior buffer is flushed and tested." :inf-buffer (get-buffer-create "aux-buffer") (with-current-buffer etest-local-inferior-buffer (insert "foo")) :inf-result "foo" :inf-result "" (with-current-buffer etest-local-inferior-buffer (insert "foobar")) :inf-result "foobar" :inf-result "") (etest-deftest etest-messages-test () "Can retrieve messages with `:messages'." :messages "" (message "foo") (message "bar") :messages "foo bar" :messages "") (ert-deftest etest-unalias-prefix-key () "Can supply keymap prefix commands like `C-c C-c`." (with-temp-buffer (let ((map (make-sparse-keymap)) called) (define-key map (kbd "C-c C-c") (lambda () (interactive) (setq called t))) (use-local-map map) (etest--unalias (kbd "C-c C-c")) (should called)))) (etest-deftest etest-multiple-results-test () "Parser is not fazed by multiple consecutive results." :case " (etest-deftest etest-multiple-results-test () :case \"¶1\" \"\" :result \"\" :result \"\") " (etest-update) :result " (etest-deftest etest-multiple-results-test () :case \"¶1\" \"\" :result \"1¶\" :result \"1¶\") ") (etest-deftest etest-skip-comments-test () "Parser skips any comments when looking for `:result' keywords." :case " (etest-deftest test () :case \"¶1\" \"\" ;; Comment ;; Comment ;; Comment :result \"\") " (etest-update) :result " (etest-deftest test () :case \"¶1\" \"\" ;; Comment ;; Comment ;; Comment :result \"1¶\") ") (etest-deftest etest-mark-test () "Mark is properly handled." :case "¶fooĂ—" "" :result "f¶ooĂ—" "" :result "fo¶oĂ—") (defun etest-make-config () '(:init ((mode . text)))) (etest-deftest etest-config-fun-test () "Configuration is picked up from function." :config (etest-make-config) (should (eq major-mode 'text-mode))) (defvar etest-some-config '(:init ((mode . text)))) (etest-deftest etest-config-var-test () "Configuration is picked up from variable." :config etest-some-config (should (eq major-mode 'text-mode))) ;; `let' doesn't seem to work here, perhaps an interaction between ;; scoping in macros and file-local variables (setq etest-local-config '(:init ((mode . text)))) (etest-deftest etest-config-local-test () "Local configuration is picked up." (should (eq major-mode 'text-mode))) (etest-deftest etest-config-keyword-test () "Keyword config has precedence over local config." :config nil (should (eq major-mode 'fundamental-mode))) (setq etest-local-config nil) (etest-deftest etest-default-mode () "Default mode is fundamental. Also tests local config test is cleaned up properly." (should (eq major-mode 'fundamental-mode))) (etest-deftest etest-truncation-test () "`backward-up-list' isn't confused by syntax in strings." :case " (etest-deftest test () :result \"\") \")\" " (etest-update) :result "¶ (etest-deftest test () :result \"\") \")\" ") (etest-deftest etest-reset-case-test () "Can reset case to its last value" :case " ¶foo " (kill-line) :result " ¶ " :case reset :result " ¶foo ") ESS-24.01.1/test/fixtures/000077500000000000000000000000001455642170100151465ustar00rootroot00000000000000ESS-24.01.1/test/fixtures/Makevars000066400000000000000000000000001455642170100166300ustar00rootroot00000000000000ESS-24.01.1/test/fixtures/Makevars.win000066400000000000000000000000001455642170100174240ustar00rootroot00000000000000ESS-24.01.1/test/fixtures/file.R000066400000000000000000000000211455642170100162010ustar00rootroot00000000000000 x <- TRUE "foo" ESS-24.01.1/test/fixtures/file.Rout000066400000000000000000000000261455642170100167360ustar00rootroot00000000000000test <- function() {} ESS-24.01.1/test/fixtures/navigation.R000066400000000000000000000020501455642170100174250ustar00rootroot00000000000000fn1 <- function(a, b) something(aaa) + aa / bb %>% cc ## end of fn1 fn2 <- function(a, b) something(aaa) + aa / bb %>% cc ## end of fn2 ### Some comments ## extra comments ## more comments fn3 <- function() { ## comment a <- 1 b <- 3 a + b } ## end of fn3 ## some paragraph par1 <- 1 par1 <- par1 setMethod("method1", function() { }) ## end of setMethod fn4 <- function() { ## comment inner_fn5 <- function() { fn5_body } b <- 3 a + b } ## end of fn4 f5 <- function(){} ## end of f5 "after f5" funcs <- list(f6 = function(){ some_code6 <- here }, ## end of f6 f7 = function(){ some_code7 -> there }) ## end of f7 f8 <- function(aaa, bb = bbb(), cc = "cccc") { Call <- match.call() miss.data <- missing(data) || !is.data.frame(data) ... } ## end of f8 f9 <- function (x, ...) some_code ## navigation.R ends here ESS-24.01.1/test/generate-indent-cases000077500000000000000000000030461455642170100173730ustar00rootroot00000000000000#!/usr/bin/env emacs --script ;; (Re)generate files with test cases for indentation (let ((current-directory (file-name-directory load-file-name))) (setq ess-test-path (expand-file-name "." current-directory)) (setq ess-styles-path (expand-file-name "./styles/" current-directory)) (setq ess-root-path (expand-file-name "../lisp/" current-directory)) (setq etest-path (expand-file-name "etest/" ess-test-path))) (add-to-list 'load-path ess-root-path) (add-to-list 'load-path ess-test-path) (add-to-list 'load-path etest-path) (require 'ess-r-mode) (load (expand-file-name "ess-test-indentation.el" ess-test-path) nil t) ;; The RRR file is taken as a model, so modify this file to add or ;; adjust test cases. (let ((ess-style-alist ess-test-style-alist) (RRR-file (expand-file-name "RRR.R" ess-styles-path))) ;; Regenerate indentation in RRR file (set-buffer (find-file-noselect RRR-file)) (setq ess-indent-with-fancy-comments t) (ess-set-style 'RRR) (indent-region (point-min) (point-max)) (save-buffer) (mapc (lambda (test-conf) (let* ((test-name (car test-conf)) (test-file (expand-file-name (concat (symbol-name test-name) ".R") ess-styles-path))) (set-buffer (find-file-noselect test-file)) (setq ess-indent-with-fancy-comments t) (ess-set-style test-name) (insert-file-contents-literally RRR-file nil nil nil 'replace) (indent-region (point-min) (point-max)) (save-buffer))) (assq-delete-all 'RRR ess-test-style-alist))) ESS-24.01.1/test/generate-literate-cases000077500000000000000000000016141455642170100177220ustar00rootroot00000000000000#!/usr/bin/env emacs --script ;; (Re)generate files with test cases for indentation (let ((current-directory (file-name-directory load-file-name))) (setq ess-test-path (expand-file-name "." current-directory)) (setq ess-etest-path (expand-file-name "./etest/" current-directory)) (setq ess-literate-path (expand-file-name "./literate/" current-directory)) (setq ess-root-path (expand-file-name "../lisp/" current-directory))) (add-to-list 'load-path ess-root-path) (add-to-list 'load-path ess-test-path) (add-to-list 'load-path ess-etest-path) (require 'ert) (require 'ess-r-mode) (load (expand-file-name "ess-test-literate.el" ess-test-path) nil t) (message "\nStarting literate tests") (mapc (lambda (file) (elt-do 'regenerate (expand-file-name file ess-literate-path))) '("elt.R" "roxy.R" "code-fill.R" "misc.R" "syntax.R" "tokens.R" "fontification.R" "keybindings.R")) ESS-24.01.1/test/manual/000077500000000000000000000000001455642170100145525ustar00rootroot00000000000000ESS-24.01.1/test/manual/R-ESS-bugs.R000066400000000000000000000744751455642170100165050ustar00rootroot00000000000000#### File showing off things that go wrong or *went* wrong in the past #### -- with R-mode (mostly coded in ../lisp/ess-mode.el ) ### NOTE: this file is indented with RRR style !!!!! ### but do not change indentations anymore of anything in here: ### expressions are written as we *want* them, not as ESS currently puts them options(keep.source = FALSE) # so we see R's deparse() + print() indentation ### --- 1 --------- extraneous comment chars : This seems fixed ## From: Robert Gentleman ## To: Martin Maechler ## Subject: ESS buglet ## Date: Sun, 01 Jul 2007 21:41:24 -0700 ## Hi Martin, ## It seems that the following buglet exists (at least in what ever ## version I am using) ##a silly comment ##and a second one foo <- function(x=a, abc = list("def", a=1,3,3), more.args, and, bla, blu, bl, another, plus, yet.another, and_mbasd, lots = NULL, more = NULL, args = NULL) { x } ##- when the line before a function def is a comment, and adding args, ##- then new lines, when generated have a comment char at the beginning of ##- the line. It is slightly annoying as I have to remove the comment char. ##- ##- If I add a blank line after the comment line, then the problem does not ##- occur. ## and another ''anonymous'' function: function(x=a, abc = list("def", a=c(1,3,3)), more.args, and, bla, blu, blo, Abc, def, another, and_another, and_this) { ...; ... } ## This is a "TRUE" example (from Matrix/tests/ ): NA.or.True <- function(x) is.na(x) | x abc <- function(x, y, ...) this.is.just.a.one.liner(x,y, z=TRUE, ...) ## A more-liner function with no "{...}" -- this one even works (but not all!) mindiff <- function(df) df[which.min(df$diff), which.max(df$daff)] ## Two functions in one line - can I "send" just one of them? {no, not "simply"} f1 <- function(x) be.friendly(x, force=TRUE); f2 <- function(x,y) x*sin(pi*x) ### --- 2 ---------------------------------------------------------------- ### --- Suggestion (Jenny Brian): --> Create a (defun ess-eval-multiline .) ## Here is useful valid R "test code": ## From 'example(plot.default)' : Speed <- cars$speed Distance <- cars$dist plot(Speed, Distance, panel.first = grid(8,8), pch = 0, cex = 1.2, col = "blue") pp <- plot(Speed, Distance, panel.first = grid(8,8), pch = 0, cex = 1.2, col = "blue") plot(Speed, Distance, panel.first = lines(lowess(Speed, Distance), lty = "dashed"), pch = 0, cex = 1.2, col = "blue") ## Note: We now at least C-c C-c {ess-eval-function-or-paragraph-and-step} ### --- 3 ---------------------------------------------------------------- ###--- This one (from the Matrix package) is for testing ess-roxy..., ## i.e., C-c C-o ## not exported but used more than once for "dimnames<-" method : ## -- or do only once for all "Matrix" classes ?? dimnamesGets <- function (x, value) { d <- dim(x) if (!is.list(value) || length(value) != 2 || !(is.null(v1 <- value[[1]]) || length(v1) == d[1]) || !(is.null(v2 <- value[[2]]) || length(v2) == d[2])) stop(gettextf("invalid dimnames given for '%s' object", class(x))) x@Dimnames <- list(if(!is.null(v1)) as.character(v1), if(!is.null(v2)) as.character(v2)) x } ### --- 4 ---------------------------------------------------------------- ### continued statements a <- function(ch) { if(ch == Inf) { E.cond <- numeric(nb) } else { indic <- ifelse(jinf+1 <= 1 & jsup >= 1,1,0) E.cond <- ch*(-pbinom(jinf,ni,prb) + 1-pbinom(js.n,ni,prb)) + ifelse(ni == 1, prb*indic, mu*(pbinom(js.n-1,pmax(ni-1,1),prb) - pbinom(jinf-1,pmax(ni-1,1),prb))) / sV - ### ^-- now here (better) mu/sV*(pbinom(js.n,ni,prb) - pbinom(jinf,ni,prb)) ### ^-- now here (ok; more indentation would also be ok) indic2 <- ifelse(jinf+1 <= 1 & jsup >= 1 & ni == 2,1,0) } } ### --- 5 ---------------------------------------------------------------- ### The beginning of function is not found correctly, and hence ### all "ess-*-function" (C-M-a, C-M-e, ...) fail: setMeneric <- ## It is clearly allowed to have comments here. ## S version 4, and John Chambers in particular like it. ## ## BUG: M-C-e or M-C-a fails from ``here'' -- ## --- effectively because of ess-beginning-of-function fails ## and that really relies on finding ess-function-pattern; ## i.e., ess-R-function-pattern in ~/emacs/ess/lisp/ess-cust.el ## function(name, def = NULL, group = list(), valueClass = character(), where = topenv(parent.frame()), genericFunction = NULL) { ## comments in here are at least kept via "source" attribute if(exists(name, "package:base") && typeof(get(name, "package:base")) != "closure") { FALSE } "ABC" } ### --- 6 ---------------------------------------------------------------- ## In one-liners without "{ ... }" body, the end-of-function is also ## not correctly found: ## Use C-M-e to see: In these two, the "end-of-function" is after ## 'class' : ## ---- these all work now (ESS version 5.3.8) : ## no it doesn't VS[10-03-2012|ESS 12.03]: onelinerFails <- function(x, ...) class(x) onelinerFailsToo <- function(x, ...) class(x) onelinerWorks <- function(x, ...) { class(x) } onelinerWorksToo <- function(x, ...) { class(x) } ### --- 7 ---------------------------------------------------------------- ## idem: ## this has one line more before 'function' than "typically:" setMethod("[", signature(x = "dgTMatrix", i = "numeric", j = "missing", drop = "logical"), function (x, i, j, ..., drop) { ## select rows storage.mode(i) <- "integer" xi <- x@i + 1:1 # 1-indexing ## ................... if (drop && any(nd == 1)) drop(as(x,"matrix")) else x }) ### --- 8 ---------------------------------------------------------------- ## idem: ## all bellow are ok VS[10-03-2012|ESS 12.03]: "dimnames<-.data.frame" <- function(x, value) { d <- dim(x) if(!is.list(value) || length(value) != 2 || d[[1]] != length(value[[1]]) || d[[2]] != length(value[[2]])) stop("invalid 'dimnames' given for data frame") row.names(x) <- as.character(value[[1]]) # checks validity names(x) <- as.character(value[[2]]) x } '[.foo' <- function(x, i, value) { ### y <- x y[i] <- value y } '[[.bar' <- function(x, i, value) { ## bla bla bla y <- as.foo(x) ; y[[i]] <- value y } "[<-.foobar" <- function(x,i,j,value) { ## just something x } "names<-.foobar" <- function(x, value) { ## just something else x } `[<-.data.frame` <- function(x, i, j, value) { nA <- nargs() # value is never missing, so 3 or 4. ###.......... class(x) <- cl x } "[[<-.data.frame"<- function(x, i, j, value) { cl <- oldClass(x) ## delete class: Version 3 idiom ## to avoid any special methods for [[<- class(x) <- NULL ###........... class(x) <- cl x } "$<-.data.frame" <- function(x, i, value) { cl <- oldClass(x) ## delete class: Version 3 idiom ## to avoid any special methods for [[<- ###........... class(x) <- cl return(x) } ## swanky functions: `swank:quit-inspector` <- function(slimeConnection, sldbState) { resetInspector(slimeConnection) FALSE } 'swank:quit-inspector' <- function(slimeConnection, sldbState) { resetInspector(slimeConnection) FALSE } ### --- 9 ---------------------------------------------------------------- ## VS[03-2012|12.03]:FIXED: ## From: "Sebastian P. Luque" ## To: ess-bugs@stat.math.ethz.ch ## Subject: [ESS-bugs] ess-mode 5.12; `ess-indent-line' error ## Date: Tue, 17 Aug 2010 13:08:25 -0500 ## With the following input, and point on the line with "Table 8.3": ## it was the parenthetical expression at the beg of line if (require(lme4)) { ## Model in p. 213 (fm1 <- lmer(logFEV1 ~ age + log(height) + age0 + log(height0) + (age | id), data=fev1, subset=logFEV1 > -0.5)) ## Table 8.3 VarCorr(fm1)$id * 100 ## Model in p. 216 (fm2 <- update(fm1, . ~ . - (age | id) + (log(height) | id))) } ### ----- ## hitting TAB (`ess-indent-command'), which calls `ess-indent-line' I get ## the following trace: ## ....: (scan-error "Containing expression ends prematurely" 20 20) ## scan-sexps(177 -2) ## forward-sexp(-2) ## ... ## ess-continued-statement-p() ## ...... ## Interestingly, if the lines 2-4 are absent, then the problem is gone. ## The problem is also there in ESS 5.11. ## I'll try to find out what is going on in `ess-continued-statement-p' but ## given that I'm not very familiar with the stuff in ess-mode.el, I'm ## submitting the report in case somebody can detect the issue sooner. ## another example: hitting Tab at }else line .essDev_differs <- function(f1, f2){ if (is.function(f1) && is.function(f2)){ !(identical(body(f1), body(f2)) && identical(args(f1), args(f2))) }else !identical(f1, f2) } ### --- 10 --------------------------------------------------------------- ## indent at 0 after }else: ## VS:[03-2012|12.03]:FIXED: if (is.function(f1) && is.function(f2)){ !(identical(body(f1), body(f2)) && identical(args(f1), args(f2))) }else !identical(f1, f2) ### --- 11 --------------------------------------------------------------- ## --------------- C-c C-c was finding the wrong "beginning of function" ## [:FIXED:, 2011-05-28] foobar <- function(...) {} rm(list=ls()) ##--------> consequence of the above experiments: ## the 2nd form is numerically "uniformly better" than the first ##--------> 2011-05-27: Change Frank's psiInv() to ## psiInv = function(t,theta) ## -log1p(exp(-theta)*expm1((1-t)*theta)/expm1(-theta)) ### --- 12 --------------------------------------------------------------- ##--- In the following block, in the first line, C-c C-c does *NOT* behave ## VS[10-03-2012|ESS 12.03]: works fine for me: th <- 48 # now do ls() and see what happened ... the horror !!! d <- 3 cpF <- list("Frank", list(th, 1:d)) cop <- acF <- cpF$copula ### --- 13 --------------------------------------------------------------- ## VS[05-05-2012|ESS 12.04]: looks like :FIXED: ## From: Aleksandar Blagotic ## To: ## Subject: [ESS] R-mode: forward-sexp: Scan error: "Unbalanced parentheses" ## Date: Tue, 6 Dec 2011 01:24:11 +0100 # ## Let's presuppose that I have a function like this: # fn <- function(x, ...){ re <- "^#{1,6} [[:print:]]+$" grepl(re, x, ...) } ## As soon as I put my cursor at the end of the line with regexp, and ## press RET, I get this error: ## forward-sexp: Scan error: "Unbalanced parentheses" ## ##------- ## Rodney S: I can reproduce it ... ## Martin M: I can NOT reproduce it, neither with 'emacs -Q'; ## tried both ESS 5.14 and ESS from svn ## VS[03-2012|12.03]: Cannot reproduce it either, solved? ### --- 14 --------------------------------------------------------------- ## check the behavior of ess-arg-function-offset-new-line a <- some.function( arg1, arg2) ## ^--- RRR has ess-arg-function-offset-new-line (4) ==> should indent here a <- some.function(arg1, arg2) ## ^--- here ### --- 15 -------------------------------------------------------------- ## VS[05-05-2012|ESS 12.04]:FIXED: ## indentation of the 3rd line is wrong for(s in seq(10, 50, len = 5)) for(a in seq(.5, 1, len = 5)) pt_dif_plot(s, a) ## ^-- here ### --- 16 ---- ## VS[05-05-2012|ESS 12.04]:FIXED: ## MM[2014-04-28]: added '}' before else (=> "{" after if(.)) ## so parse() works at all! ## Gives error unbalanced para at else lines and indentation is wrong ## error: Point is not in a function according to 'ess-function-pattern'. getOrCreateForm <- function(bindName, whereEnv) if(exists(bindName, envir = get(".forms", envir = whereEnv))) { get(bindName, envir = whereEnv) ### ^-- here } else new("protoForm") ### ^-- here parentContainer <- if(is.null(.getPrototype(.Object@host))) { emptyenv() } else sdf ### ^-- here parentContainer <- if(is.null(.getPrototype(.Object@host))) emptyenv() else sdf ### ^-- here ### --- 17 --- ## Indentation ----- "expression" is special expression <- c(1, 3, 9876)# was always ok ## Had wrong indentation here: expression <- c(2343, 23874, 239487) ## or here: foo <- function(x) { expression <- c(2343, 23874, 239487) 10 + expression } ## Where as here, we *do* want the indentation to ## *NOT* go all the way to the right: { my.long.Expression <- expression( x[a[j]] == exp(theta[1] + theta[2]^2), x[b[i]] == sin(theta[3] ~~ theta[4]) ) ausdruck <- expression my.long.Expr...... <- ausdruck( x[a[j]] == exp(theta[1] + theta[2]^2), ) } ## VS[18-08-2012]: redundant feature. This is a feature for long subexpressions ## immediately following new line. Documented in ess-arg-function-offset-new-line ### --- 18 --- ## M-C-a (beginning of function) ## ----- anywhere inside the following function, M-C-a must go to beginning Ops.x.x <- function(e1, e2) { d <- dimCheck(e1,e2) if((dens1 <- extends(c1 <- class(e1), "denseMatrix"))) gen1 <- extends(c1, "generalMatrix") if((dens2 <- extends(c2 <- class(e2), "denseMatrix"))) gen2 <- extends(c2, "generalMatrix") if(dens1 && dens2) { ## both inherit from ddense* geM <- TRUE if(!gen1) { if(!gen2) { ## consider preserving "triangular" / "symmetric" geM <- FALSE le <- prod(d) isPacked <- function(x) length(x@x) < le } } ## now, in all cases @x should be matching & correct {only "uplo" part is used} r <- callGeneric(e1@x, e2@x) if(geM) new(paste0(.M.kind(r), "geMatrix"), x = r, Dim = d, Dimnames = dimnames(e1)) else new(paste0(.M.kind(r), Mclass), x = r, Dim = d, .....) } else { r <- .... ## criterion "2 * nnz(.) < ." as in sparseDefault() in Matrix() [./Matrix.R] : if(2 * nnzero(r, na.counted = TRUE) < prod(d)) as(r, "sparseMatrix") else r } } ### --- 19 --- ## indentation with regexp (bug in ess-backward-to-noncomment) parse_roc <- function(lines, match = "^\\s*+\' ?") { lines <- lines[str_detect(lines, match)] if (length(lines) == 0) return(NULL) ### ^-- here (2014-11: fixed) } ### --- 20 --- ## continuation indentation must be consistent in/out {}: { a <- ggplot(data = overtime.by.month, aes(x="", y=Percent, fill = Overtime)) + geom_bar(width = 1) + xlab('') + ylab(sub.txt) + labs(title = title.txt) + facet_wrap(~Year.Month) } a <- ggplot(data = overtime.by.month, aes(x="", y=Percent, fill = Overtime)) + geom_bar(width = 1) + xlab('') + ylab(sub.txt) + labs(title = title.txt) + facet_wrap(~Year.Month) ### ^-- face_wrap must be here ### --- 20b --- ## From https://github.com/emacs-ess/ESS/issues/120 mean(rnorm(100, mean = runif(1, 1, 10)), na.rm =TRUE) + 2 ## ^--- 2 is here mean(rnorm(100, mean = runif(1, 1, 10)), na.rm =TRUE) + 2 ## ^--- 2 is here mean(rnorm(100, mean = runif(1, 1, 10)), na.rm=TRUE) + 2 ## ^--- 2 is here ### --- 21 --- ## From: Marius Hofert ## Date: Fri, 15 Mar 2013 21:00:45 +0100 ## Hi, ## The following bug happens in ESS 12.09-2 [rev. 5395 (2013-01-10)]. Put the ## cursor in the line before the function head and hit C-c C-c. foo <- function(x) x # bar x <- 1:10 ## I'll see ## > + > [1] 1 2 3 4 5 6 7 8 9 10 ## ESS 15.03: Error in eval(expr, .... : object 'x' not found foo <- function(x) x*x bar <- function(y) y ## via C-c C-c leads to "Error: object 'bar' not found". -- fixed ### --- 22 ---- ## now correct indentation (in spite of # {was same reason as 19}) if (!grepl("#", x)) return(res) ### --- 23 ---- ### three ways to indent closing parent depending on context: foo <- function_call( a, b, c ) ### ^-- ) is here now foo <- function_call( a, b, c ) ### ")" is at column 0 foo <- function_call(a, b, c ) ### ^-- ) is here ### --- 24 --- ### shift comma in function calls foo <- function_call(a , b , c ### ^-- c is here ) ### ^-- ) is here ### --- 25 --- ## if/else in function calls and nested function_call(abc = if (test) do_something else do_something_else) function_call( abc = if (test) do_something else do_something_else) function_call(abc = if (test) do_something else do_something_else) ## real example is smooth.spline() source code [still (2015-04-08) wrong / bug!] ss <- function (x, all.knots, nknots, ...) { if (all.knots) { if (!missing(nknots) && !is.null(nknots)) warning("'all.knots' is TRUE; 'nknots' specification is disregarded") nknots <- nx } else if (is.null(nknots)) # <- for back compatibility nknots <- .nknots.smspl(nx) else { ### ^ want 'else' there if (is.function(nknots)) nknots <- nknots(nx) else if (!is.numeric(nknots)) stop("'nknots' must be numeric (in {1,..,n})") if (nknots < 1) stop("'nknots' must be at least 1") else if (nknots > nx) stop("cannot use more inner knots than unique 'x' values") } ### ^-- want '}' there } ## "if" conditional is an exception of the continuation rules: ## Here, we do not want subsequently further indentation of the c1 || c2 || c3 ## part: t2 <- function(x) { if(long.expression.of.some.size(x, pi) || another.longish.expression(sin(x)*exp(x)) || a.third.condition.under.which.A.is.chosen) ### ^-- here A else B } r <- (some.function (x, 2342) + another.f (x^3) + sdfsdf - sdfsdf + and(x) + the(x) - last(x)*part(3)) ### --- 26 ---- ## This is formally correct R, though help(parse) mentions the line-length limit of ## 4095 __when reading from the console__ ## ESS gives syntax errors ("Error: unexpected ','" ...) when evaluating this ## because line length >= 4096 : ## x <- c(1, 3.075819, 1.515999, 2.156169, 1.480742, 1.765485, 1.460206, 1.603707, 1.427429, 1.504712, 1.334528, 1.48297, 1.355308, 1.383867, 1.319241, 1.36065, 1.307467, 1.365596, 1.255259, 1.352741, 1.239381, 3.15342, 1.799889, 2.258497, 1.688312, 1.906779, 1.548203, 1.724785, 1.500873, 1.573442, 1.417137, 1.540805, 1.395945, 1.472596, 1.394247, 1.377487, 1.337394, 1.369354, 1.333378, 1.3181, 1.313813, 1.315528, 2.12777, 2.718898, 1.993509, 2.220433, 1.820585, 1.97782, 1.672455, 1.770151, 1.587478, 1.685352, 1.539295, 1.584536, 1.499487, 1.50702, 1.41952, 1.449058, 1.393042, 1.432999, 1.369964, 1.400997, 1.333824, 2.950549, 2.145387, 2.382224, 1.927077, 2.032489, 1.8371, 1.877833, 1.710891, 1.756053, 1.620778, 1.657761, 1.558978, 1.56257, 1.508633, 1.534406, 1.46709, 1.468734, 1.432529, 1.455283, 1.386975, 1.417532, 2.229573, 2.494447, 2.016117, 2.190061, 1.877996, 1.978964, 1.767284, 1.836948, 1.677372, 1.743316, 1.616383, 1.655964, 1.55484, 1.594831, 1.502185, 1.543723, 1.467005, 1.491123, 1.44402, 1.446915, 1.401578, 2.580264, 2.109121, 2.240741, 1.944719, 2.043397, 1.821808, 1.89725, 1.748788, 1.786988, 1.659333, 1.697012, 1.610622, 1.616503, 1.538529, 1.562024, 1.499964, 1.529344, 1.474519, 1.483264, 1.441552, 1.434448, 2.165233, 2.320281, 2.007836, 2.086471, 1.884052, 1.950563, 1.76926, 1.843328, 1.708941, 1.741039, 1.627206, 1.644755, 1.580563, 1.593402, 1.527312, 1.568418, 1.501462, 1.502542, 1.464583, 1.467921, 1.431141, 2.340443, 2.048262, 2.161097, 1.926082, 1.995422, 1.81446, 1.853165, 1.738533, 1.784456, 1.679444, 1.696463, 1.612931, 1.629483, 1.548186, 1.580026, 1.52198, 1.531111, 1.482914, 1.484824, 1.442726, 1.447838, 2.093386, 2.185793, 1.948989, 2.02804, 1.867137, 1.907732, 1.771923, 1.800413, 1.691612, 1.720603, 1.642705, 1.649769, 1.589028, 1.598955, 1.539759, 1.55096, 1.503965, 1.50703, 1.471349, 1.469791, 1.436959, 2.218315, 1.997369, 2.041128, 1.887059, 1.928524, 1.79626, 1.827538, 1.716748, 1.735696, 1.658329, 1.664211, 1.599286, 1.611511, 1.553925, 1.562637, 1.516805, 1.529894, 1.476064, 1.482474, 1.453253, 1.458467, 2.0247, 2.07899, 1.921976, 1.949376, 1.824629, 1.851671, 1.744713, 1.765647, 1.683525, 1.685592, 1.625113, 1.624961, 1.571921, 1.581223, 1.535257, 1.537464, 1.497165, 1.504879, 1.468682, 1.469319, 1.448344, 2.092315, 1.941412, 1.969843, 1.844093, 1.866133, 1.766145, 1.783829, 1.703613, 1.709714, 1.646078, 1.654264, 1.594523, 1.598488, 1.545105, 1.555356, 1.514627, 1.521353, 1.483958, 1.487677, 1.449191, 1.459721, 1.958987, 1.985144, 1.87739, 1.879643, 1.786823, 1.799642, 1.720015, 1.724688, 1.663539, 1.662997, 1.609267, 1.615124, 1.56746, 1.562026, 1.520586, 1.52503, 1.493008, 1.502496, 1.471983, 1.468546, 1.435064, 1.994706, 1.880348, 1.894254, 1.805827, 1.815965, 1.744296, 1.743389, 1.665481, 1.681644, 1.624466, 1.626109, 1.584028, 1.5818, 1.54376, 1.547237, 1.504878, 1.515087, 1.479032, 1.47936, 1.450758, 1.45073, 1.892685, 1.91087, 1.825301, 1.827176, 1.745363, 1.746115, 1.693373, 1.701692, 1.648247, 1.637112, 1.594648, 1.592013, 1.554849, 1.55013, 1.522186, 1.520901, 1.492606, 1.493072, 1.460868, 1.46733, 1.440956, 1.92771, 1.835696, 1.841979, 1.775991, 1.766092, 1.703807, 1.708791, 1.654985, 1.655917, 1.602388, 1.611867, 1.570765, 1.573368, 1.53419, 1.529033, 1.506767, 1.503596, 1.481126, 1.471806, 1.444917, 1.451682, 1.850262, 1.855034, 1.778997, 1.789995, 1.718871, 1.717326, 1.667357, 1.666291, 1.619743, 1.631475, 1.582624, 1.58766, 1.546302, 1.545063, 1.512222, 1.517888, 1.489127, 1.487271, 1.466722, 1.463618, 1.444137, 1.8709, 1.794033, 1.80121, 1.736376, 1.740201, 1.673776, 1.682541, 1.638153, 1.642294, 1.604417, 1.597721, 1.559534, 1.559108, 1.533942, 1.529348, 1.499517, 1.501586, 1.473147, 1.473031, 1.457615, 1.452348, 1.805753, 1.812952, 1.746549, 1.747222, 1.696924, 1.694957, 1.652157, 1.650568, 1.607807, 1.613666, 1.577295, 1.570712, 1.543704, 1.538272, 1.515369, 1.517113, 1.487451, 1.491593, 1.464514, 1.464658, 1.439359, 1.823222, 1.758781, 1.767358, 1.70872, 1.712926, 1.666956, 1.667838, 1.62077, 1.621445, 1.592891, 1.58549, 1.55603, 1.559042, 1.521501, 1.523342, 2, 3, 4) ### --- 27 ---- ## Indentation after open brace .a.lst <- list(ex1 = function(p) { cMah <- qchisq(0.975, p) function(d) as.numeric(d < cMah) ### ^--- now here (less indented than prev.) }, ex2 = function(p) { cM <- qchisq(0.95, p) function(d) as.numeric(d < cM) ### ^--- here }) ### ^--- '}' here .a.lst <- list(ex1 = function(p) { cMah <- qchisq(0.975, p) function(d) as.numeric(d < cMah) }, ## <- now at column 0 {also the next line} ex2 = function(p) { cM <- qchisq(0.95, p) function(d) as.numeric(d < cM) }) .a.lst <- list(list(aa = { bbb ### ^--- here }, aaa = function(p) { qchisq(0.95, p) ### ^--- here }, aaaa = { cccc ### ^--- here })) list(function(p){ abc ### ^-- here ## <-- Press [Tab] before/at the first '#': should *NOT* insert '...=' }) ### at column 0 (ab) { sfdsf ### ^-- here } ### --- 27b --- [new, 2015-04-09] print.MethodsFunction <- function(x, byclass = attr(x, "byclass"), ...) { info <- attr(x, "info") values <- if (byclass) { unique(info$generic) } else { visible <- ifelse(info$visible, "", "*") paste0(rownames(info), visible) ### ^-- both lines above should start here } ### ^-- "}" here ## 2nd version: val <- if (byclass) { unique(info$generic) } else { visible <- ifelse(info$visible, "", "*") paste0(rownames(info), visible) ### ^-- both lines above should start here } ### ^-- "}" here invisible(x) } ### --- 28 --- [2015-02-17; still unfixed, 2015-11-21] ## Indentation of end-line comments (to column 40 = 'indent-column') ## {this is part of "real" code in Rmpfr/R/hjk.R}: hjk <- function(x,n) { # <--- C-M-q "on {" -- does *no longer* indent the "# .." ##-- Setting steps and stepsize ----- nsteps <- floor(log2(1/tol)) # number of steps steps <- 2^c(-(0:(nsteps-1))) # decreasing step size dir <- diag(1, n, n) # orthogonal directions x <- par # start point fx <- f(x) # smallest value so far fcount <- 1 # counts number of function calls if (info) cat(sprintf("step nofc %-12s | %20s\n", "fmin", "xpar")) ##-- Start the main loop ------------ ns <- 0 while (ns < nsteps && fcount < maxfeval && abs(fx) < target) { ns <- ns + 1 hjs <- .hjsearch(x, f, steps[ns], dir, fcount, maxfeval, target) } hjs } ### --- 29 --- foreach(a = 1:3) %do% { a^2 ### ^--- here } foreach(a = 1:3) %:% foreach(b = 10:13) %dopar% { ### ^--- here a + b ### ^---- here } ### ^--- here read.csv('file.csv') %>% mutate(X = X+2, Y = Y/2) %>% ### ^--- here filter(X < 5) ### ^-- here (*was* indented earlier) ### --- 30 --- ## a) ok: { r <- array(if (d[3L] == 3L) rgb(t(x[,,1L]), t(x[,,2L]), t(x[,,3L]), maxColorValue = max) else if (d[3L] == 4L) rgb(t(x[,,1L]), t(x[,,2L]), t(x[,,3L]), t(x[,,4L]), maxColorValue = max) else stop("foo"), dim = d[1:2]) } ## b) ok : { obj <- obj && (condition1 || class2 %in% .BasicClasses || condition3) } ## c) ok: { if (any(abs(d) < .001*abs(dd) | (is.na(d) & x == y))) TRUE } ### --- 31 -------- ## C-s "recog"; M-C-a -- should go to beginning of function, does not glmmTMB <- function (formula, data = NULL) { ## glFormula <- function(formula, data=NULL, family = gaussian, ## subset, weights, na.action, offset, ## contrasts = NULL, mustart, etastart, ## control = glmerControl(), ...) { ## FIXME: check for offsets in ziformula/dispformula, throw an error call <- mf <- mc <- match.call() if (is.null(family$family)) { print(family) stop("'family' not recognized") } } ### --- 32 --- 2015-11-07 --- indentation again! -------- { yl <- if(strictlim) { ylim } else { range(y, ylim) } ## room below for weights dy <- 4*dy } ## -- 32 b) { yl <- if(strictlim) { ylim } else range(y, ylim) ## continue } ## -- 32 c) { U <- if(is.matrix(x)) apply(x, 2, foo) / (nrow(x) + 1) else foo(x) / (length(x) + 1) } ## 'else' now aligns with 'if' (and their code too) ### --- 33 -- Treat `<<-` as `<-` { f(X <- callme(arg)) f(X <<- callme(arg)) } ## the 2nd callme() now indents like the first ### --- 34 --- "eval-function" (e.g. C-c C-c) fails with this ##' checking pretty(): chkPretty <- function(x, n = 5, min.n = NULL, ..., max.D = 1) { if(is.null(min.n)) { ## work with both pretty.default() and greDevices::prettyDate() ## *AND* these have a different default for 'min.n' we must be "extra smart": min.n <- if(inherits(x, "Date") || inherits(x, "POSIXt")) n %/% 2 # grDevices:::prettyDate else n %/% 3 # pretty.default } pr <- pretty(x, n=n, min.n=min.n, ...) ## if debugging: pr <- grDevices:::prettyDate(x, n=n, min.n=min.n, ...) stopifnot(length(pr) >= (min.n+1), abs(length(pr) - (n+1)) <= max.D, ## must be equidistant [may need fuzz, i.e., signif(.) ?]: length(pr) == 1 || length(unique(diff(pr))) == 1, ## pretty(x, *) must cover range of x: min(pr) <= min(x), max(x) <= max(pr)) invisible(pr) } ### --- 35 --- indentation of conditional function definitions: ## from a robustbase vignette: { ## calculate robustness weights lwgts <- Mwgt(lresid, lctrl$tuning.psi, lctrl$psi) ## function to calculate robustified leverages tfun <- if (is.function(attr(estlist$design, 'gen'))) function(i) { if (all(is.na(wi <- lwgts[i,]))) wi else .lmrob.hat(lXs[,,i,lcdn[2]],wi) } else ### \-<-- 'else' (and all below) should indent 4 more, 'else' matching the above 'if' function(i) { if (all(is.na(wi <- lwgts[i,]))) wi else .lmrob.hat(lX, wi) } } ### --- 36 --- indentation of '#' inside string plus a '#' after that, issue #446 A <- f("abc") + f("abc") + f("abc") + f("abc # abc") + ## The above is now ok, f("abc # abc") + # <- comment w/o quotes or hashtag -- fixed now: next line was indented to beginning of line f("ABCDEF") + f(g(h("abc # def"), "foo ## bar")) + f("another") ### --- 37 ----------Github issue #432 ---- now fixed ## Indentation after string with "*" fo4 <- function(x, ...) { if(length(x) > 0) warning("Result gave strings of *different* #{characters}") x ## 'x' was wrongly indented --here: ^ } ### --- 38 ----------Mario Bouguin to ESS-bugs, Nov 21, 2017 ---- scored <- read.csv(scored_path, comment.char="#") ## writes ## When I'm on the line and execute ess-eval-region-or-function-or-paragraph-and-step (i.e. C-c C-c), R only receives this: ## ## > scored <- read.csv(scored_path, comment.char=" ## + ## MM: but I don't see this, so told him to upgrade ESS (he had 16.10, Windows) ### --- 39 --issue ..: problem *only* inside package code [ess-tracebug related] rm(old,new) old <- 10 # line 1, use ess-eval-line, i.e., C-c C-j new <- old+1 # line 2, use ess-eval-line-and-step, i.e., C-c C-n ### --- 40 -- C-M-e / C-M-a problems : ## (ess-goto-end-of-function-or-para) / (ess-goto-beginning-of-function-or-para) ## If inside a function go to end of it. ## Otherwise go to the end of paragraph. ## ---------------------------------------------------------- ## MM: have other examples which are still buggy (but not "here") ### Local Variables: ### page-delimiter: "^### --- [1-9]" ### End: ESS-24.01.1/test/manual/R-error-patterns.R000066400000000000000000000110401455642170100200570ustar00rootroot00000000000000## TODO: automate this somehow. ## ## For now manually ## ## (progn ## (setq-local compilation-error-regexp-alist ess-error-regexp-alist) ## (compilation-minor-mode)) ## ## and check if everything is highlighted as expected ## 1 Error: chunk 7 (label = OP4) Error in disp.Rnw:656:31: unexpected symbol 655: par(mgp = c(2.5, 1, 1), mar = c(0, 0, 0, 0), 656: plt= c(0.08, 0.9, 0.25, 0.p9 )) ## 2 Browse[2]> Error in x %*% y (from models.R#46) : Cholmod error 'X and/or Y have wrong dimensions' at file ../MatrixOps/cholmod_sdmult.c, line 90 ## 3 Error in source("~/works/protoClasses/R/funcs.R") (from hierarchy.R#6) : ~/works/protoClasses/R/funcs.R:1797:5: unexpected '[[' 1796: b[[2]] <- quote(browser()) 1797: [[ ^ ## 4 source("basicModel.R") Error in source("basicModel.R") : basicModel.R:95:1: unexpected symbol 94: 95: ixQ ^ ## 5.a > + Error in source(file = "/home/vitoshka/works/pbm/R/S4.R") (from #1) : /home/vitoshka/works/pbm/R/S4.R:36:62: unexpected ')' 35: }, list(vname = as.name(".pix_v")), 36: pname = as.name(".pix_p")))) ^ ## 5.b > + Error in source(file = "/home/vitoshka/works/pbm/R/S4.R") (from #1) : c:/home/vitoshka/works/pbm/R/S4.R:36:62: unexpected ')' 35: }, list(vname = as.name(".pix_v")), 36: pname = as.name(".pix_p")))) ^ ## 6 first line is not a pattern! + . + Error in base::source(file = file, echo = echo, local = local, print.eval = print.eval, (from #95) : /tmp/model_mixture.R@4:5:13: unexpected symbol 4: Mq$DATA$ixs$clust <- data$ixQ 5: Mq ## 7 don't highlight dates id lat lon obs_date Min. : 1.00 Min. :21.57 Min. :-179.88 01/02/1997 04:16:53: 1 1st Qu.: 99.25 1st Qu.:24.36 1st Qu.:-147.38 01/02/1997 05:56:25: 1 Median :197.50 Median :25.64 Median :-119.64 01/04/1997 17:41:54: 1 Mean :197.50 Mean :27.21 Mean : -21.52 01/05/1997 17:20:07: 1 3rd Qu.:295.75 3rd Qu.:27.41 3rd Qu.: 153.66 01/06/1997 04:31:13: 1 Max. :394.00 Max. :39.84 Max. : 179.93 01/06/1997 06:12:56: 1 (Other) :388 ## 8 valgrind errors ==25269== Invalid read of size 8 ==25269== at 0x9EC363C: inner_product (stl_numeric.h:183) ==25269== by 0x9EC363C: distance (rwmd.cpp:21) ==25269== by 0x9EC90C9: operator()(unsigned long, unsigned long) (rwmd.cpp:137) ## 9 testhat new patterns test_embeddings.R:20: failure: average embedding works embed_vocab(vocab, embs) not equal to embs[, 1:N]. Attributes: < Length mismatch: comparison on first 1 components > test_embeddings.R:59: error: average embedding works with missing values no 'dimnames' attribute for array 1: expect_equal(e[, "dd"], e[, "ee"]) at /store/Dropbox/dev/mlvocab/tests/testthat/test_embeddings.R:59 2: quasi_label(enquo(object), label) at /tmp/Rtmp6McxD6/R.INSTALL70c948e315c6/testthat/R/expect-equality.R:51 3: eval_bare(get_expr(quo), get_env(quo)) at /tmp/Rtmp6McxD6/R.INSTALL70c948e315c6/testthat/R/expectation.R:90 # 10 rlang backtrace Backtrace: â– 1. ├─global::update_orders(self, mm()) 2. │ └─self$orders(name) ~/dev/foo/bla.R:157:2 3. │ └─purrr::keep(...) ~/dev/foo/bla.R:85:14 4. │ └─purrr:::probe(.x, .p, ...) 5. │ └─purrr::map_lgl(.x, .p, ...) 6. └─purrr:::stop_bad_type(...) # 11 "at" rlang backtrace 10. └─shapvis::shiny_xdeps_ui(shads, name = "SHAP TS", per_page = per_page) at shiny/R/bootstrap.R:761:2 11. └─shapvis:::shiny_ui(...) at shapvis/R/app.R:72:2 12. └─shapvis:::var_groups(shad, exclude_regexp) at shapvis/R/app.R:106:2 13. ├─base::unique(...) at shapvis/R/app.R:33:2 14. └─base::colnames(shad$extra) at shapvis/R/app.R:33:2 15. └─base::is.data.frame(x) # 12 testhat failure Failure (test-kmeans.R:430:3): predict_KMeans returns the correct output if the input is a data frame AND # 13 shiny pattern Warning: Error in *: non-numeric argument to binary operator 173: plot_shap_deps_internal [/home/joe/proj/R/plot.R#219] 172: fn [/home/joe/proj/R/plot.R#184] ## but not these ranges: > str(list(1:3)) List of 1 $ : int [1:3] 1 2 3 > ESS-24.01.1/test/run-tests000077500000000000000000000045021455642170100151700ustar00rootroot00000000000000#!/usr/bin/env -S emacs --script ;; -*- mode: emacs-lisp -*- ;; This script must be run from the test directory ;; With no argument, run all tests. Otherwise run only mentioned tests. ;; Possible arguments: --r --r-indent etc. (let ((current-directory (file-name-directory load-file-name))) (setq ess-root-path (expand-file-name "../lisp/" current-directory)) (setq ess-test-path (expand-file-name "." current-directory)) (setq etest-path (expand-file-name "etest/" ess-test-path))) (add-to-list 'load-path ess-root-path) (add-to-list 'load-path ess-test-path) (add-to-list 'load-path etest-path) (require 'ess-test-r-utils) (setq ess-inhibit-message-in-tests t) (setq ert-batch-backtrace-right-margin 130) ;; lintr probably isn't installed in the test suite and flymake will ;; complain about that. Disable it during tests. (setq ess-use-flymake nil) (when (= (length argv) 0) (setq argv '("--ess" "--inf" "--org" "--r-core" "--r-indent" "--r-pkg"))) ;; Enable file-local variables while loading (defun ess-test-load-locally (name &optional dir) (let ((file (expand-file-name name dir))) (unless (assoc file load-history) (with-current-buffer (find-file-noselect file) (load file nil t))))) (put 'etest-local-config 'safe-local-variable #'symbolp) (when (member "--ess" argv) (ess-test-load-locally "ess-test.el" ess-test-path)) (when (member "--inf" argv) (ess-test-load-locally "ess-test-inf.el" ess-test-path)) (when (member "--org" argv) (ess-test-load-locally "ess-test-org.el" ess-test-path)) (when (member "--r-core" argv) (ess-test-load-locally "ess-test-r-eval.el" ess-test-path) (ess-test-load-locally "ess-test-r-package.el" ess-test-path) (ess-test-load-locally "ess-test-r-edit.el" ess-test-path) (ess-test-load-locally "ess-test-r-fontification.el" ess-test-path) (ess-test-load-locally "ess-test-r-syntax.el" ess-test-path) (ess-test-load-locally "ess-test-r-token.el" ess-test-path) (ess-test-load-locally "ess-test-r.el" ess-test-path) (ess-test-load-locally "ess-test-roxy.el" ess-test-path) (ess-test-load-locally "ess-test-rd.el" ess-test-path)) (when (member "--r-indent" argv) (ess-test-load-locally "ess-test-indentation.el" ess-test-path)) (when (member "--r-pkg" argv) (ess-test-load-locally "ess-test-r-package.el" ess-test-path)) ;; run tests (ert-run-tests-batch-and-exit t) ESS-24.01.1/test/styles/000077500000000000000000000000001455642170100146205ustar00rootroot00000000000000ESS-24.01.1/test/styles/C++.R000066400000000000000000000357671455642170100152750ustar00rootroot00000000000000 ### Function declarations ## 1 { fun <- function(argument1, argument2) { body } } ## 2 { function( argument1, argument2 ) { body } } ## 3 function(argument_fun(sub_argument1, sub_argument2), argument) {} ## 4 function(argument1, parameter = fun_call( sub_argument), argument2) {} ## 5 function() function() body ## 6a object <- function() { body } ## 6b object <- function() { body } ## 6c object = function() { body } ## 6d fun_call(argument) <- function() { body } ## 7 { object <- function() { body } } ## 8 { fun_call(parameter = function() { body }) } ## 9 { fun_call(parameter = function() { body }) } ## 10 fun_call( function() { stuff } ) ## 11 { fun_call1(fun_call2(argument, function() { stuff }) ) } ## 12 { fun_call1(argument, fun_call2(function() { stuff }) ) } ## 13 fun_call(object := function() { body }) ## 14 fun_call(argument, function(x) stuff ) ## 15a `object` <- function() { body } ## 15b "object" <- function() { body } ## 15c 'object' <- function() { body } ### Function calls ## 1 fun_call(argument1, argument2) ## 2 fun_call( argument1, argument2 ) ## 3 fun_call(parameter = ( stuff ), argument) ## 4 fun_call(parameter = fun_argument( argument1 ), argument2) ## 5 fun_call(parameter = fun_argument(argument1, argument2 ) , argument3) ## 6 `fun_call`(argument1, argument2) ## 6b `:=`(argument1, argument2) ## 7 `fun_call`( argument1, argument2 ) ## 7b `:=`( argument1, argument2 ) ## 8 fun_call(argument1 , argument2 , argument3, argument4, ( stuff1 ), argument5, ( stuff2 ) , argument6 ) ## 9 fun_call(parameter = fun_argument( sub_argument ), argument ) ## 10 fun_call(parameter = fun_argument( sub_argument ), argument ) ## 11 { fun_call1( fun_call2 (argument1, argument2, parameter = fun_call3( argument3, argument4 ), function(x) { body }, argument5, fun_call4( argument6 ), argument7 ), { stuff }, argument8 ) } ## 12 object <- fun_call( arg1, arg2 ) ## 13 fun_call1(fun_call2( argument )) ## 14 some_function <- fun_call1(fun_call2( argument )) ## 15 object[, fun_call( argument )] ## 16 fun_call1(argument1, fun_call2(fun_call3( argument2 )) ) ## 17 fun_call({ stuff1 stuff2 stuff3 }) ## 18 fun_call(argument1 %>% stuff, argument2) ## 19 fun_call(argument, ) ## 20 fun_call(parameter1 = , parameter2 = argument) ### Blocks ## 1 { function() { body } } ## 2 { fun_call({ stuff1 }, { stuff2 } ) } ## 3 fun_call({ stuff1 }, { stuff2 }) ## 4 fun_call( parameter1 = { stuff1 }, parameter2 = { stuff2 } ) ## 5 fun_call(parameter1 = { stuff1 }, { stuff2 }, parameter2 = { stuff3 }, { stuff4 }, parameter3 = stuff5 ~ stuff6 + stuff7, argument) ## 6 fun <- fun_call({ stuff1 }, { stuff2 }, { stuff3 } ) ## 7 fun <- fun_call({ stuff }, argument ) ## 8 fun_call(function(x) { body1 }, function(x) { body2 }) ## 9 fun_call( { stuff }, { stuff } ) ## 10 object <- fun_call({ stuff }, { stuff }) ## 11 object <- fun_call( { body } ) ## 12 fun_call1( fun_call2({ stuff } ) ) ## 13 { stuff1 { stuff2 } } ## 14 {{ stuff } } ## 15 ({ stuff }) ## 16 ( { stuff } ) ## 17 fun_call(argument, function(argument1, argument2) { body } ) ## 18 fun_call( argument, function(argument1, argument2) { body } ) ## 19 fun_call1( fun_call2(argument, function(x) { body }) ) ## 20 fun_call1({ object1 <- fun_call2( argument) object2 }) ## 21 fun_call(argument, function() { stuff } } ## 22 function_call() stuff ### Bracket indexing ## 1 object[ argument1, argument2 ] ## 2 object[argument1, argument2 ] ## 3 object[( argument1 )] ## 4 { object[ fun_call( body ), argument[ ( sub_argument ) ] ] } ## 5 { object[ argument1, argument2, by = argument3 ][ argument4, fun_call1(argument1, argument2) argument5 ][ argument6, fun_call2( argument1, argument2 ) ] } ### Control flow ## 1 { if (condition) { stuff1 } else { stuff2 } } ## 2 { if (condition) { stuff1 } else { stuff2 } } ## 3 { if (condition) { stuff1 } else { stuff2 } } ## 4 { if (condition) { stuff1 } else { stuff2 } } ## 5 { for (sequence) { stuff } } ## 6 { for (sequence) { stuff } } ## 7 if (condition) stuff ## 8 for (sequence) stuff ## 9 object <- if (condition) { stuff1 } else { stuff2 } ## 10 { object <- if (condition) stuff1 else stuff2 } ## 10 { object <- if (condition) fun_call( argument1, argument2 ) else stuff } ## 11 { fun_call(parameter = if (condition) stuff1 else stuff2 ) } ## 12 { if (condition1) { stuff1 } else if (condition2) stuff2 else if (condition3) { stuff3 } else if (condition4) stuff4 else stuff5 } ## 13 fun_call( argument, parameter = if (condition1) { stuff1 } else if (condition2) { stuff3 } else { stuff2 } ) ## 14 fun_call( argument, parameter = if (condition1) stuff1 else if (condition2) stuff3 else stuff2 ) ## 15 object <- fun_call(argument, parameter = if (condition1) { stuff1 } else if (condition2) { stuff3 } else { stuff2 } ) ## 16 object <- fun_call(argument, if (condition) stuff1 else if (condition2) stuff2 ) ## 17 while(condition) stuff ## 18 if (condition1) stuff1 else if (condition2) { stuff2 } ## 19 object <- if (condition) fun_call()[index] else stuff ## 20 funcall({ if (test1) stuff1 if (test2) stuff2 }) ## 21 fun_call(argument, function() { if (cond) object1 <- object2 else object3 <- object4 }) ## 22 if (cond1) if (cond2) if (cond3) stuff1 else if (cond4) stuff2 else if (cond5) stuff3 else stuff4 else if (cond6) stuff5 else if (cond7) stuff6 else stuff7 else if (cond8) stuff8 else if (cond9) stuff9 else stuff10 ## 23 if (cond1) if (cond2) for (sequence1) if (cond3) stuff1 else stuff2 else if (cond4) for (sequence2) stuff3 else if (cond5) fun_call( argument ) else stuff5 else stuff6 ## 24 object <- if(cond) stuff1 else stuff2 ## 25 if (condition) { (stuff) } ## 26 { if (condition1) stuff1 else if (condition2) { stuff2 } else if (condition3) stuff3 } ## 27 object <- if (condition) { stuff1 } else { stuff2 } ## 28 if (condition) object <- stuff ## 29 if (condition1) object <- if (condition2) stuff1 else stuff2 else stuff3 ### Continuation lines ## 1 stuff1 %>% stuff2 %>% stuff3 ## 2 { stuff1 %>% stuff2 %>% stuff3 } %>% stuff4 %>% stuff5 ## 3 ( stuff1 %>% stuff2 %>% stuff3 ) %>% stuff4 %>% stuff5 ## 4 object[ stuff1 %>% stuff2 %>% stuff3 ] %>% stuff4 %>% stuff5 ## 5 stuff1 %>% stuff2 %>% if (condition) { stuff3 %>% stuff4 %>% stuff5 } else { stuff6 %>% stuff7 %>% stuff8 } %>% stuff9 %>% stuff10 ## 6 stuff[stuff1 %>% stuff2 %>% stuff3] %>% stuff4 %>% stuff5 ## 7 ggplot() + geom(lhs - rhs ) + geom() ## 8 { ggplot() + geom1(argument1, argument2 = ( stuff1 ) - stuff2) + geom2() + geom3() } ## 9 stuff + fun_call(parameter = argument1, fun_call((stuff1 - stuff2 + stuff3 ) / stuff4) ) / stuff5 fun_call(arg1 + arg2, arg3 + arg4) ## 10 fun_call(argument1 %>% stuff1, argument2 %>% stuff2, { stuff3 %>% stuff4 } %>% stuff5, argument3 ) ## 11 object1 <- object2 %>% fun_call1() %>% fun_call2() ## 12 object1 <- object2%>%fun_call1() %>% fun_call2()%>% fun_call3() ## 13 { (stuff) %>% fun_call() {stuff} %>% fun_call() } ## 14 { object + ( stuff ) %>% fun_call() object + { stuff } %>% fun_call() } ## 15 object <- stuff1 + stuff2 ~ stuff3 + stuff4 := stuff5 + stuff6 = stuff7 + stuff8 ## 16 object <- stuff1 + stuff2 + stuff3 + stuff4 ~ stuff5 + stuff6 + stuff7 + stuff8 := stuff9 + stuff10 + stuff11 + stuff12 = stuff13 + stuff14 + stuff15 + stuff16 ## 17 object %>% { stuff1 } %>% object[index] %>% {stuff2} %>% fun_call1() + {if (condition1) stuff3 else stuff4} + if (condition2) { stuff5 } else if (condition3) { stuff6 } else { stuff7 } %>% (fun_call2()) %>% fun_call3() %>% fun_call3() ## 18 `object`$`elem` <- stuff1 + stuff2 `object`@`elem` <- stuff1 + stuff2 ## 19 { ## comment object1 <- object2 } ## 20 fun_call(stuff1 + stuff2 + stuff3 + (stuff4 + stuff5 + stuff6) + object[stuff7 + stuff8] + {stuff9 + stuff10}) ## 21 object %>% fun_call({ stuff1 }) %>% stuff2 ## 22 "string1" %>% 'string2' %>% `stuff1` %>% stuff2 ## 23 object[index] %>% fun_call1( argument1 )[index2] %>% fun_call2( argument2 )[[index3]] %>% stuff ## 24 fun_call(argument) <- hop ## 25 fun_call1(argument, fun_call2( stuff1 ) + stuff2) ## 26 object <- { stuff1 } %>% ( stuff2 ) ## 27 fun_call1(fun_call2(fun_call3( argument ))) %>% fun_call2() ## 28 fun_call(argument1 %>% stuff, argument2) ## 29 fun_call(stuff1 := (stuff2), argument) ## 30 fun_call1(fun_call2( fun_call3()) %>% stuff) ## 31 fun_call(object1 + object2 ~ object3 + object4 + object5 := object6 + object7, argument) ## 32 fun_call(object ~ ) ## 33 fun_call(object + ) ## 34 fun_call(object[index1]$element[index2][index3]@attribute + stuff) ## 35a fun_call(argument <- object) ## 35b fun_call(argument <<- object) ## 36 funcall(!stuff1 || stuff2) ## 37 (issue #857) fun_call({ stuff <- namespace:::fun_call() %>% fun_call() stuff }) fun_call({ stuff <- namespace::fun_call() %>% fun_call() stuff }) ## 38a (issue #412) namespace::fun_call() %>% namespace::fun_call() %>% namespace::fun_call() %>% namespace::fun_Call() ## 38b namespace:::fun_call() %>% namespace:::fun_call() %>% namespace:::fun_call() %>% namespace:::fun_Call() ## 38c object@fun_call() %>% object@fun_call() %>% object@fun_call() %>% object@fun_Call() ## 38d object$fun_call() %>% object$fun_call() %>% object$fun_call() %>% object$fun_Call() ## 39 x |> f1() |> f2() |> f3() ## 40 \(x) x + 2 ### Comments ## 1 # Side comment ## 2 { ## Hanging comment 1 fun_call( { ## Hanging comment 2 } ) } ## 3 { ### Section comment } ## 4 fun_call( ## Comment argument ) ## 5 object %>% ## comment, ## comment stuff ## 6a object <- function() { stuff ## comment } ## 6b object <- function() { ## comment } ## 7 { fun_call(lhs + ### Comment rhs ) } ## 8 "#" + # comment NULL ## 9 "* #" x ### Logical operators ## 1 stuff1 && stuff2 || stuff3 ## 2 (stuff1 && stuff2 || stuff3) ## 3 if (condition1 && condition2 || (condition3 && condition4) || (condition5 && condition6 && condition7) || condition8) { stuff } && condition8 || condition9 || condition10 ## 4 stuff1 == stuff2 || condition ## 5 (stuff1 == stuff2 || condition ) ## 6 (stuff1 != stuff2 || condition ) ## 7 object <- condition1 | condition2 | condition3 | condition4 ## 8 if (condition1 || object1 %op% object2 || condition3) { stuff } ## 9 any(condition1 | condition2) && all(condition3 & condition4) ### Specific situations and overrides ## 10 fun_call( ifelse(condition1, argument1, ifelse(condition2, argument2, ifelse)) ) ## 11 1:10 |> x => 2 ** x %>% sum() ESS-24.01.1/test/styles/RRR+.R000066400000000000000000000410741455642170100154710ustar00rootroot00000000000000 ### Function declarations ## 1 { fun <- function(argument1, argument2) { body } } ## 2 { function( argument1, argument2 ) { body } } ## 3 function(argument_fun(sub_argument1, sub_argument2), argument) {} ## 4 function(argument1, parameter = fun_call( sub_argument), argument2) {} ## 5 function() function() body ## 6a object <- function() { body } ## 6b object <- function() { body } ## 6c object = function() { body } ## 6d fun_call(argument) <- function() { body } ## 7 { object <- function() { body } } ## 8 { fun_call(parameter = function() { body }) } ## 9 { fun_call(parameter = function() { body }) } ## 10 fun_call( function() { stuff } ) ## 11 { fun_call1(fun_call2(argument, function() { stuff }) ) } ## 12 { fun_call1(argument, fun_call2(function() { stuff }) ) } ## 13 fun_call(object := function() { body }) ## 14 fun_call(argument, function(x) stuff ) ## 15a `object` <- function() { body } ## 15b "object" <- function() { body } ## 15c 'object' <- function() { body } ### Function calls ## 1 fun_call(argument1, argument2) ## 2 fun_call( argument1, argument2 ) ## 3 fun_call(parameter = ( stuff ), argument) ## 4 fun_call(parameter = fun_argument( argument1 ), argument2) ## 5 fun_call(parameter = fun_argument(argument1, argument2 ) , argument3) ## 6 `fun_call`(argument1, argument2) ## 6b `:=`(argument1, argument2) ## 7 `fun_call`( argument1, argument2 ) ## 7b `:=`( argument1, argument2 ) ## 8 fun_call(argument1 , argument2 , argument3, argument4, ( stuff1 ), argument5, ( stuff2 ) , argument6 ) ## 9 fun_call(parameter = fun_argument( sub_argument ), argument ) ## 10 fun_call(parameter = fun_argument( sub_argument ), argument ) ## 11 { fun_call1( fun_call2 (argument1, argument2, parameter = fun_call3( argument3, argument4 ), function(x) { body }, argument5, fun_call4( argument6 ), argument7 ), { stuff }, argument8 ) } ## 12 object <- fun_call( arg1, arg2 ) ## 13 fun_call1(fun_call2( argument )) ## 14 some_function <- fun_call1(fun_call2( argument )) ## 15 object[, fun_call( argument )] ## 16 fun_call1(argument1, fun_call2(fun_call3( argument2 )) ) ## 17 fun_call({ stuff1 stuff2 stuff3 }) ## 18 fun_call(argument1 %>% stuff, argument2) ## 19 fun_call(argument, ) ## 20 fun_call(parameter1 = , parameter2 = argument) ### Blocks ## 1 { function() { body } } ## 2 { fun_call({ stuff1 }, { stuff2 } ) } ## 3 fun_call({ stuff1 }, { stuff2 }) ## 4 fun_call( parameter1 = { stuff1 }, parameter2 = { stuff2 } ) ## 5 fun_call(parameter1 = { stuff1 }, { stuff2 }, parameter2 = { stuff3 }, { stuff4 }, parameter3 = stuff5 ~ stuff6 + stuff7, argument) ## 6 fun <- fun_call({ stuff1 }, { stuff2 }, { stuff3 } ) ## 7 fun <- fun_call({ stuff }, argument ) ## 8 fun_call(function(x) { body1 }, function(x) { body2 }) ## 9 fun_call( { stuff }, { stuff } ) ## 10 object <- fun_call({ stuff }, { stuff }) ## 11 object <- fun_call( { body } ) ## 12 fun_call1( fun_call2({ stuff } ) ) ## 13 { stuff1 { stuff2 } } ## 14 {{ stuff } } ## 15 ({ stuff }) ## 16 ( { stuff } ) ## 17 fun_call(argument, function(argument1, argument2) { body } ) ## 18 fun_call( argument, function(argument1, argument2) { body } ) ## 19 fun_call1( fun_call2(argument, function(x) { body }) ) ## 20 fun_call1({ object1 <- fun_call2( argument) object2 }) ## 21 fun_call(argument, function() { stuff } } ## 22 function_call() stuff ### Bracket indexing ## 1 object[ argument1, argument2 ] ## 2 object[argument1, argument2 ] ## 3 object[( argument1 )] ## 4 { object[ fun_call( body ), argument[ ( sub_argument ) ] ] } ## 5 { object[ argument1, argument2, by = argument3 ][ argument4, fun_call1(argument1, argument2) argument5 ][ argument6, fun_call2( argument1, argument2 ) ] } ### Control flow ## 1 { if (condition) { stuff1 } else { stuff2 } } ## 2 { if (condition) { stuff1 } else { stuff2 } } ## 3 { if (condition) { stuff1 } else { stuff2 } } ## 4 { if (condition) { stuff1 } else { stuff2 } } ## 5 { for (sequence) { stuff } } ## 6 { for (sequence) { stuff } } ## 7 if (condition) stuff ## 8 for (sequence) stuff ## 9 object <- if (condition) { stuff1 } else { stuff2 } ## 10 { object <- if (condition) stuff1 else stuff2 } ## 10 { object <- if (condition) fun_call( argument1, argument2 ) else stuff } ## 11 { fun_call(parameter = if (condition) stuff1 else stuff2 ) } ## 12 { if (condition1) { stuff1 } else if (condition2) stuff2 else if (condition3) { stuff3 } else if (condition4) stuff4 else stuff5 } ## 13 fun_call( argument, parameter = if (condition1) { stuff1 } else if (condition2) { stuff3 } else { stuff2 } ) ## 14 fun_call( argument, parameter = if (condition1) stuff1 else if (condition2) stuff3 else stuff2 ) ## 15 object <- fun_call(argument, parameter = if (condition1) { stuff1 } else if (condition2) { stuff3 } else { stuff2 } ) ## 16 object <- fun_call(argument, if (condition) stuff1 else if (condition2) stuff2 ) ## 17 while(condition) stuff ## 18 if (condition1) stuff1 else if (condition2) { stuff2 } ## 19 object <- if (condition) fun_call()[index] else stuff ## 20 funcall({ if (test1) stuff1 if (test2) stuff2 }) ## 21 fun_call(argument, function() { if (cond) object1 <- object2 else object3 <- object4 }) ## 22 if (cond1) if (cond2) if (cond3) stuff1 else if (cond4) stuff2 else if (cond5) stuff3 else stuff4 else if (cond6) stuff5 else if (cond7) stuff6 else stuff7 else if (cond8) stuff8 else if (cond9) stuff9 else stuff10 ## 23 if (cond1) if (cond2) for (sequence1) if (cond3) stuff1 else stuff2 else if (cond4) for (sequence2) stuff3 else if (cond5) fun_call( argument ) else stuff5 else stuff6 ## 24 object <- if(cond) stuff1 else stuff2 ## 25 if (condition) { (stuff) } ## 26 { if (condition1) stuff1 else if (condition2) { stuff2 } else if (condition3) stuff3 } ## 27 object <- if (condition) { stuff1 } else { stuff2 } ## 28 if (condition) object <- stuff ## 29 if (condition1) object <- if (condition2) stuff1 else stuff2 else stuff3 ### Continuation lines ## 1 stuff1 %>% stuff2 %>% stuff3 ## 2 { stuff1 %>% stuff2 %>% stuff3 } %>% stuff4 %>% stuff5 ## 3 ( stuff1 %>% stuff2 %>% stuff3 ) %>% stuff4 %>% stuff5 ## 4 object[ stuff1 %>% stuff2 %>% stuff3 ] %>% stuff4 %>% stuff5 ## 5 stuff1 %>% stuff2 %>% if (condition) { stuff3 %>% stuff4 %>% stuff5 } else { stuff6 %>% stuff7 %>% stuff8 } %>% stuff9 %>% stuff10 ## 6 stuff[stuff1 %>% stuff2 %>% stuff3] %>% stuff4 %>% stuff5 ## 7 ggplot() + geom(lhs - rhs ) + geom() ## 8 { ggplot() + geom1(argument1, argument2 = ( stuff1 ) - stuff2) + geom2() + geom3() } ## 9 stuff + fun_call(parameter = argument1, fun_call((stuff1 - stuff2 + stuff3 ) / stuff4) ) / stuff5 fun_call(arg1 + arg2, arg3 + arg4) ## 10 fun_call(argument1 %>% stuff1, argument2 %>% stuff2, { stuff3 %>% stuff4 } %>% stuff5, argument3 ) ## 11 object1 <- object2 %>% fun_call1() %>% fun_call2() ## 12 object1 <- object2%>%fun_call1() %>% fun_call2()%>% fun_call3() ## 13 { (stuff) %>% fun_call() {stuff} %>% fun_call() } ## 14 { object + ( stuff ) %>% fun_call() object + { stuff } %>% fun_call() } ## 15 object <- stuff1 + stuff2 ~ stuff3 + stuff4 := stuff5 + stuff6 = stuff7 + stuff8 ## 16 object <- stuff1 + stuff2 + stuff3 + stuff4 ~ stuff5 + stuff6 + stuff7 + stuff8 := stuff9 + stuff10 + stuff11 + stuff12 = stuff13 + stuff14 + stuff15 + stuff16 ## 17 object %>% { stuff1 } %>% object[index] %>% {stuff2} %>% fun_call1() + {if (condition1) stuff3 else stuff4} + if (condition2) { stuff5 } else if (condition3) { stuff6 } else { stuff7 } %>% (fun_call2()) %>% fun_call3() %>% fun_call3() ## 18 `object`$`elem` <- stuff1 + stuff2 `object`@`elem` <- stuff1 + stuff2 ## 19 { ## comment object1 <- object2 } ## 20 fun_call(stuff1 + stuff2 + stuff3 + (stuff4 + stuff5 + stuff6) + object[stuff7 + stuff8] + {stuff9 + stuff10}) ## 21 object %>% fun_call({ stuff1 }) %>% stuff2 ## 22 "string1" %>% 'string2' %>% `stuff1` %>% stuff2 ## 23 object[index] %>% fun_call1( argument1 )[index2] %>% fun_call2( argument2 )[[index3]] %>% stuff ## 24 fun_call(argument) <- hop ## 25 fun_call1(argument, fun_call2( stuff1 ) + stuff2) ## 26 object <- { stuff1 } %>% ( stuff2 ) ## 27 fun_call1(fun_call2(fun_call3( argument ))) %>% fun_call2() ## 28 fun_call(argument1 %>% stuff, argument2) ## 29 fun_call(stuff1 := (stuff2), argument) ## 30 fun_call1(fun_call2( fun_call3()) %>% stuff) ## 31 fun_call(object1 + object2 ~ object3 + object4 + object5 := object6 + object7, argument) ## 32 fun_call(object ~ ) ## 33 fun_call(object + ) ## 34 fun_call(object[index1]$element[index2][index3]@attribute + stuff) ## 35a fun_call(argument <- object) ## 35b fun_call(argument <<- object) ## 36 funcall(!stuff1 || stuff2) ## 37 (issue #857) fun_call({ stuff <- namespace:::fun_call() %>% fun_call() stuff }) fun_call({ stuff <- namespace::fun_call() %>% fun_call() stuff }) ## 38a (issue #412) namespace::fun_call() %>% namespace::fun_call() %>% namespace::fun_call() %>% namespace::fun_Call() ## 38b namespace:::fun_call() %>% namespace:::fun_call() %>% namespace:::fun_call() %>% namespace:::fun_Call() ## 38c object@fun_call() %>% object@fun_call() %>% object@fun_call() %>% object@fun_Call() ## 38d object$fun_call() %>% object$fun_call() %>% object$fun_call() %>% object$fun_Call() ## 39 x |> f1() |> f2() |> f3() ## 40 \(x) x + 2 ### Comments ## 1 # Side comment ## 2 { ## Hanging comment 1 fun_call( { ## Hanging comment 2 } ) } ## 3 { ### Section comment } ## 4 fun_call( ## Comment argument ) ## 5 object %>% ## comment, ## comment stuff ## 6a object <- function() { stuff ## comment } ## 6b object <- function() { ## comment } ## 7 { fun_call(lhs + ### Comment rhs ) } ## 8 "#" + # comment NULL ## 9 "* #" x ### Logical operators ## 1 stuff1 && stuff2 || stuff3 ## 2 (stuff1 && stuff2 || stuff3) ## 3 if (condition1 && condition2 || (condition3 && condition4) || (condition5 && condition6 && condition7) || condition8) { stuff } && condition8 || condition9 || condition10 ## 4 stuff1 == stuff2 || condition ## 5 (stuff1 == stuff2 || condition ) ## 6 (stuff1 != stuff2 || condition ) ## 7 object <- condition1 | condition2 | condition3 | condition4 ## 8 if (condition1 || object1 %op% object2 || condition3) { stuff } ## 9 any(condition1 | condition2) && all(condition3 & condition4) ### Specific situations and overrides ## 10 fun_call( ifelse(condition1, argument1, ifelse(condition2, argument2, ifelse)) ) ## 11 1:10 |> x => 2 ** x %>% sum() ESS-24.01.1/test/styles/RRR.R000066400000000000000000000363671455642170100154270ustar00rootroot00000000000000 ### Function declarations ## 1 { fun <- function(argument1, argument2) { body } } ## 2 { function( argument1, argument2 ) { body } } ## 3 function(argument_fun(sub_argument1, sub_argument2), argument) {} ## 4 function(argument1, parameter = fun_call( sub_argument), argument2) {} ## 5 function() function() body ## 6a object <- function() { body } ## 6b object <- function() { body } ## 6c object = function() { body } ## 6d fun_call(argument) <- function() { body } ## 7 { object <- function() { body } } ## 8 { fun_call(parameter = function() { body }) } ## 9 { fun_call(parameter = function() { body }) } ## 10 fun_call( function() { stuff } ) ## 11 { fun_call1(fun_call2(argument, function() { stuff }) ) } ## 12 { fun_call1(argument, fun_call2(function() { stuff }) ) } ## 13 fun_call(object := function() { body }) ## 14 fun_call(argument, function(x) stuff ) ## 15a `object` <- function() { body } ## 15b "object" <- function() { body } ## 15c 'object' <- function() { body } ### Function calls ## 1 fun_call(argument1, argument2) ## 2 fun_call( argument1, argument2 ) ## 3 fun_call(parameter = ( stuff ), argument) ## 4 fun_call(parameter = fun_argument( argument1 ), argument2) ## 5 fun_call(parameter = fun_argument(argument1, argument2 ) , argument3) ## 6 `fun_call`(argument1, argument2) ## 6b `:=`(argument1, argument2) ## 7 `fun_call`( argument1, argument2 ) ## 7b `:=`( argument1, argument2 ) ## 8 fun_call(argument1 , argument2 , argument3, argument4, ( stuff1 ), argument5, ( stuff2 ) , argument6 ) ## 9 fun_call(parameter = fun_argument( sub_argument ), argument ) ## 10 fun_call(parameter = fun_argument( sub_argument ), argument ) ## 11 { fun_call1( fun_call2 (argument1, argument2, parameter = fun_call3( argument3, argument4 ), function(x) { body }, argument5, fun_call4( argument6 ), argument7 ), { stuff }, argument8 ) } ## 12 object <- fun_call( arg1, arg2 ) ## 13 fun_call1(fun_call2( argument )) ## 14 some_function <- fun_call1(fun_call2( argument )) ## 15 object[, fun_call( argument )] ## 16 fun_call1(argument1, fun_call2(fun_call3( argument2 )) ) ## 17 fun_call({ stuff1 stuff2 stuff3 }) ## 18 fun_call(argument1 %>% stuff, argument2) ## 19 fun_call(argument, ) ## 20 fun_call(parameter1 = , parameter2 = argument) ### Blocks ## 1 { function() { body } } ## 2 { fun_call({ stuff1 }, { stuff2 } ) } ## 3 fun_call({ stuff1 }, { stuff2 }) ## 4 fun_call( parameter1 = { stuff1 }, parameter2 = { stuff2 } ) ## 5 fun_call(parameter1 = { stuff1 }, { stuff2 }, parameter2 = { stuff3 }, { stuff4 }, parameter3 = stuff5 ~ stuff6 + stuff7, argument) ## 6 fun <- fun_call({ stuff1 }, { stuff2 }, { stuff3 } ) ## 7 fun <- fun_call({ stuff }, argument ) ## 8 fun_call(function(x) { body1 }, function(x) { body2 }) ## 9 fun_call( { stuff }, { stuff } ) ## 10 object <- fun_call({ stuff }, { stuff }) ## 11 object <- fun_call( { body } ) ## 12 fun_call1( fun_call2({ stuff } ) ) ## 13 { stuff1 { stuff2 } } ## 14 {{ stuff } } ## 15 ({ stuff }) ## 16 ( { stuff } ) ## 17 fun_call(argument, function(argument1, argument2) { body } ) ## 18 fun_call( argument, function(argument1, argument2) { body } ) ## 19 fun_call1( fun_call2(argument, function(x) { body }) ) ## 20 fun_call1({ object1 <- fun_call2( argument) object2 }) ## 21 fun_call(argument, function() { stuff } } ## 22 function_call() stuff ### Bracket indexing ## 1 object[ argument1, argument2 ] ## 2 object[argument1, argument2 ] ## 3 object[( argument1 )] ## 4 { object[ fun_call( body ), argument[ ( sub_argument ) ] ] } ## 5 { object[ argument1, argument2, by = argument3 ][ argument4, fun_call1(argument1, argument2) argument5 ][ argument6, fun_call2( argument1, argument2 ) ] } ### Control flow ## 1 { if (condition) { stuff1 } else { stuff2 } } ## 2 { if (condition) { stuff1 } else { stuff2 } } ## 3 { if (condition) { stuff1 } else { stuff2 } } ## 4 { if (condition) { stuff1 } else { stuff2 } } ## 5 { for (sequence) { stuff } } ## 6 { for (sequence) { stuff } } ## 7 if (condition) stuff ## 8 for (sequence) stuff ## 9 object <- if (condition) { stuff1 } else { stuff2 } ## 10 { object <- if (condition) stuff1 else stuff2 } ## 10 { object <- if (condition) fun_call( argument1, argument2 ) else stuff } ## 11 { fun_call(parameter = if (condition) stuff1 else stuff2 ) } ## 12 { if (condition1) { stuff1 } else if (condition2) stuff2 else if (condition3) { stuff3 } else if (condition4) stuff4 else stuff5 } ## 13 fun_call( argument, parameter = if (condition1) { stuff1 } else if (condition2) { stuff3 } else { stuff2 } ) ## 14 fun_call( argument, parameter = if (condition1) stuff1 else if (condition2) stuff3 else stuff2 ) ## 15 object <- fun_call(argument, parameter = if (condition1) { stuff1 } else if (condition2) { stuff3 } else { stuff2 } ) ## 16 object <- fun_call(argument, if (condition) stuff1 else if (condition2) stuff2 ) ## 17 while(condition) stuff ## 18 if (condition1) stuff1 else if (condition2) { stuff2 } ## 19 object <- if (condition) fun_call()[index] else stuff ## 20 funcall({ if (test1) stuff1 if (test2) stuff2 }) ## 21 fun_call(argument, function() { if (cond) object1 <- object2 else object3 <- object4 }) ## 22 if (cond1) if (cond2) if (cond3) stuff1 else if (cond4) stuff2 else if (cond5) stuff3 else stuff4 else if (cond6) stuff5 else if (cond7) stuff6 else stuff7 else if (cond8) stuff8 else if (cond9) stuff9 else stuff10 ## 23 if (cond1) if (cond2) for (sequence1) if (cond3) stuff1 else stuff2 else if (cond4) for (sequence2) stuff3 else if (cond5) fun_call( argument ) else stuff5 else stuff6 ## 24 object <- if(cond) stuff1 else stuff2 ## 25 if (condition) { (stuff) } ## 26 { if (condition1) stuff1 else if (condition2) { stuff2 } else if (condition3) stuff3 } ## 27 object <- if (condition) { stuff1 } else { stuff2 } ## 28 if (condition) object <- stuff ## 29 if (condition1) object <- if (condition2) stuff1 else stuff2 else stuff3 ### Continuation lines ## 1 stuff1 %>% stuff2 %>% stuff3 ## 2 { stuff1 %>% stuff2 %>% stuff3 } %>% stuff4 %>% stuff5 ## 3 ( stuff1 %>% stuff2 %>% stuff3 ) %>% stuff4 %>% stuff5 ## 4 object[ stuff1 %>% stuff2 %>% stuff3 ] %>% stuff4 %>% stuff5 ## 5 stuff1 %>% stuff2 %>% if (condition) { stuff3 %>% stuff4 %>% stuff5 } else { stuff6 %>% stuff7 %>% stuff8 } %>% stuff9 %>% stuff10 ## 6 stuff[stuff1 %>% stuff2 %>% stuff3] %>% stuff4 %>% stuff5 ## 7 ggplot() + geom(lhs - rhs ) + geom() ## 8 { ggplot() + geom1(argument1, argument2 = ( stuff1 ) - stuff2) + geom2() + geom3() } ## 9 stuff + fun_call(parameter = argument1, fun_call((stuff1 - stuff2 + stuff3 ) / stuff4) ) / stuff5 fun_call(arg1 + arg2, arg3 + arg4) ## 10 fun_call(argument1 %>% stuff1, argument2 %>% stuff2, { stuff3 %>% stuff4 } %>% stuff5, argument3 ) ## 11 object1 <- object2 %>% fun_call1() %>% fun_call2() ## 12 object1 <- object2%>%fun_call1() %>% fun_call2()%>% fun_call3() ## 13 { (stuff) %>% fun_call() {stuff} %>% fun_call() } ## 14 { object + ( stuff ) %>% fun_call() object + { stuff } %>% fun_call() } ## 15 object <- stuff1 + stuff2 ~ stuff3 + stuff4 := stuff5 + stuff6 = stuff7 + stuff8 ## 16 object <- stuff1 + stuff2 + stuff3 + stuff4 ~ stuff5 + stuff6 + stuff7 + stuff8 := stuff9 + stuff10 + stuff11 + stuff12 = stuff13 + stuff14 + stuff15 + stuff16 ## 17 object %>% { stuff1 } %>% object[index] %>% {stuff2} %>% fun_call1() + {if (condition1) stuff3 else stuff4} + if (condition2) { stuff5 } else if (condition3) { stuff6 } else { stuff7 } %>% (fun_call2()) %>% fun_call3() %>% fun_call3() ## 18 `object`$`elem` <- stuff1 + stuff2 `object`@`elem` <- stuff1 + stuff2 ## 19 { ## comment object1 <- object2 } ## 20 fun_call(stuff1 + stuff2 + stuff3 + (stuff4 + stuff5 + stuff6) + object[stuff7 + stuff8] + {stuff9 + stuff10}) ## 21 object %>% fun_call({ stuff1 }) %>% stuff2 ## 22 "string1" %>% 'string2' %>% `stuff1` %>% stuff2 ## 23 object[index] %>% fun_call1( argument1 )[index2] %>% fun_call2( argument2 )[[index3]] %>% stuff ## 24 fun_call(argument) <- hop ## 25 fun_call1(argument, fun_call2( stuff1 ) + stuff2) ## 26 object <- { stuff1 } %>% ( stuff2 ) ## 27 fun_call1(fun_call2(fun_call3( argument ))) %>% fun_call2() ## 28 fun_call(argument1 %>% stuff, argument2) ## 29 fun_call(stuff1 := (stuff2), argument) ## 30 fun_call1(fun_call2( fun_call3()) %>% stuff) ## 31 fun_call(object1 + object2 ~ object3 + object4 + object5 := object6 + object7, argument) ## 32 fun_call(object ~ ) ## 33 fun_call(object + ) ## 34 fun_call(object[index1]$element[index2][index3]@attribute + stuff) ## 35a fun_call(argument <- object) ## 35b fun_call(argument <<- object) ## 36 funcall(!stuff1 || stuff2) ## 37 (issue #857) fun_call({ stuff <- namespace:::fun_call() %>% fun_call() stuff }) fun_call({ stuff <- namespace::fun_call() %>% fun_call() stuff }) ## 38a (issue #412) namespace::fun_call() %>% namespace::fun_call() %>% namespace::fun_call() %>% namespace::fun_Call() ## 38b namespace:::fun_call() %>% namespace:::fun_call() %>% namespace:::fun_call() %>% namespace:::fun_Call() ## 38c object@fun_call() %>% object@fun_call() %>% object@fun_call() %>% object@fun_Call() ## 38d object$fun_call() %>% object$fun_call() %>% object$fun_call() %>% object$fun_Call() ## 39 x |> f1() |> f2() |> f3() ## 40 \(x) x + 2 ### Comments ## 1 # Side comment ## 2 { ## Hanging comment 1 fun_call( { ## Hanging comment 2 } ) } ## 3 { ### Section comment } ## 4 fun_call( ## Comment argument ) ## 5 object %>% ## comment, ## comment stuff ## 6a object <- function() { stuff ## comment } ## 6b object <- function() { ## comment } ## 7 { fun_call(lhs + ### Comment rhs ) } ## 8 "#" + # comment NULL ## 9 "* #" x ### Logical operators ## 1 stuff1 && stuff2 || stuff3 ## 2 (stuff1 && stuff2 || stuff3) ## 3 if (condition1 && condition2 || (condition3 && condition4) || (condition5 && condition6 && condition7) || condition8) { stuff } && condition8 || condition9 || condition10 ## 4 stuff1 == stuff2 || condition ## 5 (stuff1 == stuff2 || condition ) ## 6 (stuff1 != stuff2 || condition ) ## 7 object <- condition1 | condition2 | condition3 | condition4 ## 8 if (condition1 || object1 %op% object2 || condition3) { stuff } ## 9 any(condition1 | condition2) && all(condition3 & condition4) ### Specific situations and overrides ## 10 fun_call( ifelse(condition1, argument1, ifelse(condition2, argument2, ifelse)) ) ## 11 1:10 |> x => 2 ** x %>% sum() ESS-24.01.1/test/styles/RStudio-.R000066400000000000000000000307561455642170100164240ustar00rootroot00000000000000 ### Function declarations ## 1 { fun <- function(argument1, argument2) { body } } ## 2 { function( argument1, argument2 ) { body } } ## 3 function(argument_fun(sub_argument1, sub_argument2), argument) {} ## 4 function(argument1, parameter = fun_call( sub_argument), argument2) {} ## 5 function() function() body ## 6a object <- function() { body } ## 6b object <- function() { body } ## 6c object = function() { body } ## 6d fun_call(argument) <- function() { body } ## 7 { object <- function() { body } } ## 8 { fun_call(parameter = function() { body }) } ## 9 { fun_call(parameter = function() { body }) } ## 10 fun_call( function() { stuff } ) ## 11 { fun_call1(fun_call2(argument, function() { stuff }) ) } ## 12 { fun_call1(argument, fun_call2(function() { stuff }) ) } ## 13 fun_call(object := function() { body }) ## 14 fun_call(argument, function(x) stuff ) ## 15a `object` <- function() { body } ## 15b "object" <- function() { body } ## 15c 'object' <- function() { body } ### Function calls ## 1 fun_call(argument1, argument2) ## 2 fun_call( argument1, argument2 ) ## 3 fun_call(parameter = ( stuff ), argument) ## 4 fun_call(parameter = fun_argument( argument1 ), argument2) ## 5 fun_call(parameter = fun_argument(argument1, argument2 ) , argument3) ## 6 `fun_call`(argument1, argument2) ## 6b `:=`(argument1, argument2) ## 7 `fun_call`( argument1, argument2 ) ## 7b `:=`( argument1, argument2 ) ## 8 fun_call(argument1 , argument2 , argument3, argument4, ( stuff1 ), argument5, ( stuff2 ) , argument6 ) ## 9 fun_call(parameter = fun_argument( sub_argument ), argument ) ## 10 fun_call(parameter = fun_argument( sub_argument ), argument ) ## 11 { fun_call1( fun_call2 (argument1, argument2, parameter = fun_call3( argument3, argument4 ), function(x) { body }, argument5, fun_call4( argument6 ), argument7 ), { stuff }, argument8 ) } ## 12 object <- fun_call( arg1, arg2 ) ## 13 fun_call1(fun_call2( argument )) ## 14 some_function <- fun_call1(fun_call2( argument )) ## 15 object[, fun_call( argument )] ## 16 fun_call1(argument1, fun_call2(fun_call3( argument2 )) ) ## 17 fun_call({ stuff1 stuff2 stuff3 }) ## 18 fun_call(argument1 %>% stuff, argument2) ## 19 fun_call(argument, ) ## 20 fun_call(parameter1 = , parameter2 = argument) ### Blocks ## 1 { function() { body } } ## 2 { fun_call({ stuff1 }, { stuff2 } ) } ## 3 fun_call({ stuff1 }, { stuff2 }) ## 4 fun_call( parameter1 = { stuff1 }, parameter2 = { stuff2 } ) ## 5 fun_call(parameter1 = { stuff1 }, { stuff2 }, parameter2 = { stuff3 }, { stuff4 }, parameter3 = stuff5 ~ stuff6 + stuff7, argument) ## 6 fun <- fun_call({ stuff1 }, { stuff2 }, { stuff3 } ) ## 7 fun <- fun_call({ stuff }, argument ) ## 8 fun_call(function(x) { body1 }, function(x) { body2 }) ## 9 fun_call( { stuff }, { stuff } ) ## 10 object <- fun_call({ stuff }, { stuff }) ## 11 object <- fun_call( { body } ) ## 12 fun_call1( fun_call2({ stuff } ) ) ## 13 { stuff1 { stuff2 } } ## 14 {{ stuff } } ## 15 ({ stuff }) ## 16 ( { stuff } ) ## 17 fun_call(argument, function(argument1, argument2) { body } ) ## 18 fun_call( argument, function(argument1, argument2) { body } ) ## 19 fun_call1( fun_call2(argument, function(x) { body }) ) ## 20 fun_call1({ object1 <- fun_call2( argument) object2 }) ## 21 fun_call(argument, function() { stuff } } ## 22 function_call() stuff ### Bracket indexing ## 1 object[ argument1, argument2 ] ## 2 object[argument1, argument2 ] ## 3 object[( argument1 )] ## 4 { object[ fun_call( body ), argument[ ( sub_argument ) ] ] } ## 5 { object[ argument1, argument2, by = argument3 ][ argument4, fun_call1(argument1, argument2) argument5 ][ argument6, fun_call2( argument1, argument2 ) ] } ### Control flow ## 1 { if (condition) { stuff1 } else { stuff2 } } ## 2 { if (condition) { stuff1 } else { stuff2 } } ## 3 { if (condition) { stuff1 } else { stuff2 } } ## 4 { if (condition) { stuff1 } else { stuff2 } } ## 5 { for (sequence) { stuff } } ## 6 { for (sequence) { stuff } } ## 7 if (condition) stuff ## 8 for (sequence) stuff ## 9 object <- if (condition) { stuff1 } else { stuff2 } ## 10 { object <- if (condition) stuff1 else stuff2 } ## 10 { object <- if (condition) fun_call( argument1, argument2 ) else stuff } ## 11 { fun_call(parameter = if (condition) stuff1 else stuff2 ) } ## 12 { if (condition1) { stuff1 } else if (condition2) stuff2 else if (condition3) { stuff3 } else if (condition4) stuff4 else stuff5 } ## 13 fun_call( argument, parameter = if (condition1) { stuff1 } else if (condition2) { stuff3 } else { stuff2 } ) ## 14 fun_call( argument, parameter = if (condition1) stuff1 else if (condition2) stuff3 else stuff2 ) ## 15 object <- fun_call(argument, parameter = if (condition1) { stuff1 } else if (condition2) { stuff3 } else { stuff2 } ) ## 16 object <- fun_call(argument, if (condition) stuff1 else if (condition2) stuff2 ) ## 17 while(condition) stuff ## 18 if (condition1) stuff1 else if (condition2) { stuff2 } ## 19 object <- if (condition) fun_call()[index] else stuff ## 20 funcall({ if (test1) stuff1 if (test2) stuff2 }) ## 21 fun_call(argument, function() { if (cond) object1 <- object2 else object3 <- object4 }) ## 22 if (cond1) if (cond2) if (cond3) stuff1 else if (cond4) stuff2 else if (cond5) stuff3 else stuff4 else if (cond6) stuff5 else if (cond7) stuff6 else stuff7 else if (cond8) stuff8 else if (cond9) stuff9 else stuff10 ## 23 if (cond1) if (cond2) for (sequence1) if (cond3) stuff1 else stuff2 else if (cond4) for (sequence2) stuff3 else if (cond5) fun_call( argument ) else stuff5 else stuff6 ## 24 object <- if(cond) stuff1 else stuff2 ## 25 if (condition) { (stuff) } ## 26 { if (condition1) stuff1 else if (condition2) { stuff2 } else if (condition3) stuff3 } ## 27 object <- if (condition) { stuff1 } else { stuff2 } ## 28 if (condition) object <- stuff ## 29 if (condition1) object <- if (condition2) stuff1 else stuff2 else stuff3 ### Continuation lines ## 1 stuff1 %>% stuff2 %>% stuff3 ## 2 { stuff1 %>% stuff2 %>% stuff3 } %>% stuff4 %>% stuff5 ## 3 ( stuff1 %>% stuff2 %>% stuff3 ) %>% stuff4 %>% stuff5 ## 4 object[ stuff1 %>% stuff2 %>% stuff3 ] %>% stuff4 %>% stuff5 ## 5 stuff1 %>% stuff2 %>% if (condition) { stuff3 %>% stuff4 %>% stuff5 } else { stuff6 %>% stuff7 %>% stuff8 } %>% stuff9 %>% stuff10 ## 6 stuff[stuff1 %>% stuff2 %>% stuff3] %>% stuff4 %>% stuff5 ## 7 ggplot() + geom(lhs - rhs ) + geom() ## 8 { ggplot() + geom1(argument1, argument2 = ( stuff1 ) - stuff2) + geom2() + geom3() } ## 9 stuff + fun_call(parameter = argument1, fun_call((stuff1 - stuff2 + stuff3 ) / stuff4) ) / stuff5 fun_call(arg1 + arg2, arg3 + arg4) ## 10 fun_call(argument1 %>% stuff1, argument2 %>% stuff2, { stuff3 %>% stuff4 } %>% stuff5, argument3 ) ## 11 object1 <- object2 %>% fun_call1() %>% fun_call2() ## 12 object1 <- object2%>%fun_call1() %>% fun_call2()%>% fun_call3() ## 13 { (stuff) %>% fun_call() {stuff} %>% fun_call() } ## 14 { object + ( stuff ) %>% fun_call() object + { stuff } %>% fun_call() } ## 15 object <- stuff1 + stuff2 ~ stuff3 + stuff4 := stuff5 + stuff6 = stuff7 + stuff8 ## 16 object <- stuff1 + stuff2 + stuff3 + stuff4 ~ stuff5 + stuff6 + stuff7 + stuff8 := stuff9 + stuff10 + stuff11 + stuff12 = stuff13 + stuff14 + stuff15 + stuff16 ## 17 object %>% { stuff1 } %>% object[index] %>% {stuff2} %>% fun_call1() + {if (condition1) stuff3 else stuff4} + if (condition2) { stuff5 } else if (condition3) { stuff6 } else { stuff7 } %>% (fun_call2()) %>% fun_call3() %>% fun_call3() ## 18 `object`$`elem` <- stuff1 + stuff2 `object`@`elem` <- stuff1 + stuff2 ## 19 { ## comment object1 <- object2 } ## 20 fun_call(stuff1 + stuff2 + stuff3 + (stuff4 + stuff5 + stuff6) + object[stuff7 + stuff8] + {stuff9 + stuff10}) ## 21 object %>% fun_call({ stuff1 }) %>% stuff2 ## 22 "string1" %>% 'string2' %>% `stuff1` %>% stuff2 ## 23 object[index] %>% fun_call1( argument1 )[index2] %>% fun_call2( argument2 )[[index3]] %>% stuff ## 24 fun_call(argument) <- hop ## 25 fun_call1(argument, fun_call2( stuff1 ) + stuff2) ## 26 object <- { stuff1 } %>% ( stuff2 ) ## 27 fun_call1(fun_call2(fun_call3( argument ))) %>% fun_call2() ## 28 fun_call(argument1 %>% stuff, argument2) ## 29 fun_call(stuff1 := (stuff2), argument) ## 30 fun_call1(fun_call2( fun_call3()) %>% stuff) ## 31 fun_call(object1 + object2 ~ object3 + object4 + object5 := object6 + object7, argument) ## 32 fun_call(object ~ ) ## 33 fun_call(object + ) ## 34 fun_call(object[index1]$element[index2][index3]@attribute + stuff) ## 35a fun_call(argument <- object) ## 35b fun_call(argument <<- object) ## 36 funcall(!stuff1 || stuff2) ## 37 (issue #857) fun_call({ stuff <- namespace:::fun_call() %>% fun_call() stuff }) fun_call({ stuff <- namespace::fun_call() %>% fun_call() stuff }) ## 38a (issue #412) namespace::fun_call() %>% namespace::fun_call() %>% namespace::fun_call() %>% namespace::fun_Call() ## 38b namespace:::fun_call() %>% namespace:::fun_call() %>% namespace:::fun_call() %>% namespace:::fun_Call() ## 38c object@fun_call() %>% object@fun_call() %>% object@fun_call() %>% object@fun_Call() ## 38d object$fun_call() %>% object$fun_call() %>% object$fun_call() %>% object$fun_Call() ## 39 x |> f1() |> f2() |> f3() ## 40 \(x) x + 2 ### Comments ## 1 # Side comment ## 2 { ## Hanging comment 1 fun_call( { ## Hanging comment 2 } ) } ## 3 { ### Section comment } ## 4 fun_call( ## Comment argument ) ## 5 object %>% ## comment, ## comment stuff ## 6a object <- function() { stuff ## comment } ## 6b object <- function() { ## comment } ## 7 { fun_call(lhs + ### Comment rhs ) } ## 8 "#" + # comment NULL ## 9 "* #" x ### Logical operators ## 1 stuff1 && stuff2 || stuff3 ## 2 (stuff1 && stuff2 || stuff3) ## 3 if (condition1 && condition2 || (condition3 && condition4) || (condition5 && condition6 && condition7) || condition8) { stuff } && condition8 || condition9 || condition10 ## 4 stuff1 == stuff2 || condition ## 5 (stuff1 == stuff2 || condition ) ## 6 (stuff1 != stuff2 || condition ) ## 7 object <- condition1 | condition2 | condition3 | condition4 ## 8 if (condition1 || object1 %op% object2 || condition3) { stuff } ## 9 any(condition1 | condition2) && all(condition3 & condition4) ### Specific situations and overrides ## 10 fun_call( ifelse(condition1, argument1, ifelse(condition2, argument2, ifelse)) ) ## 11 1:10 |> x => 2 ** x %>% sum() ESS-24.01.1/test/styles/misc1.R000066400000000000000000000416611455642170100157670ustar00rootroot00000000000000 ### Function declarations ## 1 { fun <- function(argument1, argument2) { body } } ## 2 { function( argument1, argument2 ) { body } } ## 3 function(argument_fun(sub_argument1, sub_argument2), argument) {} ## 4 function(argument1, parameter = fun_call( sub_argument), argument2) {} ## 5 function() function() body ## 6a object <- function() { body } ## 6b object <- function() { body } ## 6c object = function() { body } ## 6d fun_call(argument) <- function() { body } ## 7 { object <- function() { body } } ## 8 { fun_call(parameter = function() { body }) } ## 9 { fun_call(parameter = function() { body }) } ## 10 fun_call( function() { stuff } ) ## 11 { fun_call1(fun_call2(argument, function() { stuff }) ) } ## 12 { fun_call1(argument, fun_call2(function() { stuff }) ) } ## 13 fun_call(object := function() { body }) ## 14 fun_call(argument, function(x) stuff ) ## 15a `object` <- function() { body } ## 15b "object" <- function() { body } ## 15c 'object' <- function() { body } ### Function calls ## 1 fun_call(argument1, argument2) ## 2 fun_call( argument1, argument2 ) ## 3 fun_call(parameter = ( stuff ), argument) ## 4 fun_call(parameter = fun_argument( argument1 ), argument2) ## 5 fun_call(parameter = fun_argument(argument1, argument2 ) , argument3) ## 6 `fun_call`(argument1, argument2) ## 6b `:=`(argument1, argument2) ## 7 `fun_call`( argument1, argument2 ) ## 7b `:=`( argument1, argument2 ) ## 8 fun_call(argument1 , argument2 , argument3, argument4, ( stuff1 ), argument5, ( stuff2 ) , argument6 ) ## 9 fun_call(parameter = fun_argument( sub_argument ), argument ) ## 10 fun_call(parameter = fun_argument( sub_argument ), argument ) ## 11 { fun_call1( fun_call2 (argument1, argument2, parameter = fun_call3( argument3, argument4 ), function(x) { body }, argument5, fun_call4( argument6 ), argument7 ), { stuff }, argument8 ) } ## 12 object <- fun_call( arg1, arg2 ) ## 13 fun_call1(fun_call2( argument )) ## 14 some_function <- fun_call1(fun_call2( argument )) ## 15 object[, fun_call( argument )] ## 16 fun_call1(argument1, fun_call2(fun_call3( argument2 )) ) ## 17 fun_call({ stuff1 stuff2 stuff3 }) ## 18 fun_call(argument1 %>% stuff, argument2) ## 19 fun_call(argument, ) ## 20 fun_call(parameter1 = , parameter2 = argument) ### Blocks ## 1 { function() { body } } ## 2 { fun_call({ stuff1 }, { stuff2 } ) } ## 3 fun_call({ stuff1 }, { stuff2 }) ## 4 fun_call( parameter1 = { stuff1 }, parameter2 = { stuff2 } ) ## 5 fun_call(parameter1 = { stuff1 }, { stuff2 }, parameter2 = { stuff3 }, { stuff4 }, parameter3 = stuff5 ~ stuff6 + stuff7, argument) ## 6 fun <- fun_call({ stuff1 }, { stuff2 }, { stuff3 } ) ## 7 fun <- fun_call({ stuff }, argument ) ## 8 fun_call(function(x) { body1 }, function(x) { body2 }) ## 9 fun_call( { stuff }, { stuff } ) ## 10 object <- fun_call({ stuff }, { stuff }) ## 11 object <- fun_call( { body } ) ## 12 fun_call1( fun_call2({ stuff } ) ) ## 13 { stuff1 { stuff2 } } ## 14 {{ stuff } } ## 15 ({ stuff }) ## 16 ( { stuff } ) ## 17 fun_call(argument, function(argument1, argument2) { body } ) ## 18 fun_call( argument, function(argument1, argument2) { body } ) ## 19 fun_call1( fun_call2(argument, function(x) { body }) ) ## 20 fun_call1({ object1 <- fun_call2( argument) object2 }) ## 21 fun_call(argument, function() { stuff } } ## 22 function_call() stuff ### Bracket indexing ## 1 object[ argument1, argument2 ] ## 2 object[argument1, argument2 ] ## 3 object[( argument1 )] ## 4 { object[ fun_call( body ), argument[ ( sub_argument ) ] ] } ## 5 { object[ argument1, argument2, by = argument3 ][ argument4, fun_call1(argument1, argument2) argument5 ][ argument6, fun_call2( argument1, argument2 ) ] } ### Control flow ## 1 { if (condition) { stuff1 } else { stuff2 } } ## 2 { if (condition) { stuff1 } else { stuff2 } } ## 3 { if (condition) { stuff1 } else { stuff2 } } ## 4 { if (condition) { stuff1 } else { stuff2 } } ## 5 { for (sequence) { stuff } } ## 6 { for (sequence) { stuff } } ## 7 if (condition) stuff ## 8 for (sequence) stuff ## 9 object <- if (condition) { stuff1 } else { stuff2 } ## 10 { object <- if (condition) stuff1 else stuff2 } ## 10 { object <- if (condition) fun_call( argument1, argument2 ) else stuff } ## 11 { fun_call(parameter = if (condition) stuff1 else stuff2 ) } ## 12 { if (condition1) { stuff1 } else if (condition2) stuff2 else if (condition3) { stuff3 } else if (condition4) stuff4 else stuff5 } ## 13 fun_call( argument, parameter = if (condition1) { stuff1 } else if (condition2) { stuff3 } else { stuff2 } ) ## 14 fun_call( argument, parameter = if (condition1) stuff1 else if (condition2) stuff3 else stuff2 ) ## 15 object <- fun_call(argument, parameter = if (condition1) { stuff1 } else if (condition2) { stuff3 } else { stuff2 } ) ## 16 object <- fun_call(argument, if (condition) stuff1 else if (condition2) stuff2 ) ## 17 while(condition) stuff ## 18 if (condition1) stuff1 else if (condition2) { stuff2 } ## 19 object <- if (condition) fun_call()[index] else stuff ## 20 funcall({ if (test1) stuff1 if (test2) stuff2 }) ## 21 fun_call(argument, function() { if (cond) object1 <- object2 else object3 <- object4 }) ## 22 if (cond1) if (cond2) if (cond3) stuff1 else if (cond4) stuff2 else if (cond5) stuff3 else stuff4 else if (cond6) stuff5 else if (cond7) stuff6 else stuff7 else if (cond8) stuff8 else if (cond9) stuff9 else stuff10 ## 23 if (cond1) if (cond2) for (sequence1) if (cond3) stuff1 else stuff2 else if (cond4) for (sequence2) stuff3 else if (cond5) fun_call( argument ) else stuff5 else stuff6 ## 24 object <- if(cond) stuff1 else stuff2 ## 25 if (condition) { (stuff) } ## 26 { if (condition1) stuff1 else if (condition2) { stuff2 } else if (condition3) stuff3 } ## 27 object <- if (condition) { stuff1 } else { stuff2 } ## 28 if (condition) object <- stuff ## 29 if (condition1) object <- if (condition2) stuff1 else stuff2 else stuff3 ### Continuation lines ## 1 stuff1 %>% stuff2 %>% stuff3 ## 2 { stuff1 %>% stuff2 %>% stuff3 } %>% stuff4 %>% stuff5 ## 3 ( stuff1 %>% stuff2 %>% stuff3 ) %>% stuff4 %>% stuff5 ## 4 object[ stuff1 %>% stuff2 %>% stuff3 ] %>% stuff4 %>% stuff5 ## 5 stuff1 %>% stuff2 %>% if (condition) { stuff3 %>% stuff4 %>% stuff5 } else { stuff6 %>% stuff7 %>% stuff8 } %>% stuff9 %>% stuff10 ## 6 stuff[stuff1 %>% stuff2 %>% stuff3] %>% stuff4 %>% stuff5 ## 7 ggplot() + geom(lhs - rhs ) + geom() ## 8 { ggplot() + geom1(argument1, argument2 = ( stuff1 ) - stuff2) + geom2() + geom3() } ## 9 stuff + fun_call(parameter = argument1, fun_call((stuff1 - stuff2 + stuff3 ) / stuff4) ) / stuff5 fun_call(arg1 + arg2, arg3 + arg4) ## 10 fun_call(argument1 %>% stuff1, argument2 %>% stuff2, { stuff3 %>% stuff4 } %>% stuff5, argument3 ) ## 11 object1 <- object2 %>% fun_call1() %>% fun_call2() ## 12 object1 <- object2%>%fun_call1() %>% fun_call2()%>% fun_call3() ## 13 { (stuff) %>% fun_call() {stuff} %>% fun_call() } ## 14 { object + ( stuff ) %>% fun_call() object + { stuff } %>% fun_call() } ## 15 object <- stuff1 + stuff2 ~ stuff3 + stuff4 := stuff5 + stuff6 = stuff7 + stuff8 ## 16 object <- stuff1 + stuff2 + stuff3 + stuff4 ~ stuff5 + stuff6 + stuff7 + stuff8 := stuff9 + stuff10 + stuff11 + stuff12 = stuff13 + stuff14 + stuff15 + stuff16 ## 17 object %>% { stuff1 } %>% object[index] %>% {stuff2} %>% fun_call1() + {if (condition1) stuff3 else stuff4} + if (condition2) { stuff5 } else if (condition3) { stuff6 } else { stuff7 } %>% (fun_call2()) %>% fun_call3() %>% fun_call3() ## 18 `object`$`elem` <- stuff1 + stuff2 `object`@`elem` <- stuff1 + stuff2 ## 19 { ## comment object1 <- object2 } ## 20 fun_call(stuff1 + stuff2 + stuff3 + (stuff4 + stuff5 + stuff6) + object[stuff7 + stuff8] + {stuff9 + stuff10}) ## 21 object %>% fun_call({ stuff1 }) %>% stuff2 ## 22 "string1" %>% 'string2' %>% `stuff1` %>% stuff2 ## 23 object[index] %>% fun_call1( argument1 )[index2] %>% fun_call2( argument2 )[[index3]] %>% stuff ## 24 fun_call(argument) <- hop ## 25 fun_call1(argument, fun_call2( stuff1 ) + stuff2) ## 26 object <- { stuff1 } %>% ( stuff2 ) ## 27 fun_call1(fun_call2(fun_call3( argument ))) %>% fun_call2() ## 28 fun_call(argument1 %>% stuff, argument2) ## 29 fun_call(stuff1 := (stuff2), argument) ## 30 fun_call1(fun_call2( fun_call3()) %>% stuff) ## 31 fun_call(object1 + object2 ~ object3 + object4 + object5 := object6 + object7, argument) ## 32 fun_call(object ~ ) ## 33 fun_call(object + ) ## 34 fun_call(object[index1]$element[index2][index3]@attribute + stuff) ## 35a fun_call(argument <- object) ## 35b fun_call(argument <<- object) ## 36 funcall(!stuff1 || stuff2) ## 37 (issue #857) fun_call({ stuff <- namespace:::fun_call() %>% fun_call() stuff }) fun_call({ stuff <- namespace::fun_call() %>% fun_call() stuff }) ## 38a (issue #412) namespace::fun_call() %>% namespace::fun_call() %>% namespace::fun_call() %>% namespace::fun_Call() ## 38b namespace:::fun_call() %>% namespace:::fun_call() %>% namespace:::fun_call() %>% namespace:::fun_Call() ## 38c object@fun_call() %>% object@fun_call() %>% object@fun_call() %>% object@fun_Call() ## 38d object$fun_call() %>% object$fun_call() %>% object$fun_call() %>% object$fun_Call() ## 39 x |> f1() |> f2() |> f3() ## 40 \(x) x + 2 ### Comments ## 1 # Side comment ## 2 { ## Hanging comment 1 fun_call( { ## Hanging comment 2 } ) } ## 3 { ### Section comment } ## 4 fun_call( ## Comment argument ) ## 5 object %>% ## comment, ## comment stuff ## 6a object <- function() { stuff ## comment } ## 6b object <- function() { ## comment } ## 7 { fun_call(lhs + ### Comment rhs ) } ## 8 "#" + # comment NULL ## 9 "* #" x ### Logical operators ## 1 stuff1 && stuff2 || stuff3 ## 2 (stuff1 && stuff2 || stuff3) ## 3 if (condition1 && condition2 || (condition3 && condition4) || (condition5 && condition6 && condition7) || condition8) { stuff } && condition8 || condition9 || condition10 ## 4 stuff1 == stuff2 || condition ## 5 (stuff1 == stuff2 || condition ) ## 6 (stuff1 != stuff2 || condition ) ## 7 object <- condition1 | condition2 | condition3 | condition4 ## 8 if (condition1 || object1 %op% object2 || condition3) { stuff } ## 9 any(condition1 | condition2) && all(condition3 & condition4) ### Specific situations and overrides ## 10 fun_call( ifelse(condition1, argument1, ifelse(condition2, argument2, ifelse)) ) ## 11 1:10 |> x => 2 ** x %>% sum()