+++ /dev/null
-;;; 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[cvu]\\|(setq\\|;;;;\\*")
- (indent-tabs-mode))
- (ess-r-mode . ((ess-style . RRR))))
+++ /dev/null
-This is allnews.info, produced by makeinfo version 6.5 from
-allnews.texi.
-
-Changes and New Features in 19.04 (unreleased):
-
- * 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
- <language>-mode-hook and <language>-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. See
- *Note (ess)Controlling buffer display:: for more information and
- examples.
-
- * '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.
-
- * 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.
-
- 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 <https://github.com/polymode/poly-R/>,
- <https://polymode.github.io/>, or markdown-mode with edit-indirect
- <https://jblevins.org/projects/markdown-mode>.
-
- * 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" <ess-config-here>)' 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. *Note (ess)Activating and Loading ESS:: for more
- information on this feature.
-
- * 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
-
- Changes 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 <https://github.com/emacs-ess/ESS/pull/65>
- * 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 softare, 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 sugested 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
- 'inferor-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 documention
- 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;
- <https://ess.r-project.org/Manual/ess.html>
- * 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 agressive.
- * 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.VehtariNOSPAMhut.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:brendanNOSPAMessex.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:brahmNOSPAMalum.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.
-
-
-\1f
-Tag Table:
-\1f
-End Tag Table
+++ /dev/null
-This is announc.info, produced by makeinfo version 6.5 from
-announc.texi.
-
-\1f
-File: announc.info, Node: Announce
-
-1 ANNOUNCING ESS
-****************
-
-The ESS Developers proudly announce the release of ESS 18.10.3snapshot
-
- 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.
-
-* Menu:
-
-* Latest Version::
-* Current Features::
-* Requirements::
-* Mailing List::
-* Reporting Bugs::
-* Authors::
-* License::
-* New Features::
-
-\1f
-File: announc.info, Node: Latest Version, Next: Current Features, Prev: Announce, Up: Announce
-
-1.1 Getting the Latest Version
-==============================
-
-ESS 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.
-
- 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 *note Activating and Loading ESS:: for more details.
-
-* Menu:
-
-* Installing from a third-party repository::
-* Installing from source::
-* Activating and Loading ESS::
-* Check Installation::
-
-\1f
-File: announc.info, Node: Installing from a third-party repository, Next: Installing from source
-
-1.2 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 MELPA's website (https://melpa.org/).
-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 *note Activating and Loading ESS::.
-Depending on install method, this may be taken care of automatically.
-
-\1f
-File: announc.info, Node: Installing from source, Next: Activating and Loading ESS, Prev: Installing from a third-party repository
-
-1.3 Installing from source
-==========================
-
-Stable versions of ESS are available at the ESS web page
-(https://ess.r-project.org) as a .tgz file or .zip file. ESS releases
-are GPG-signed, you should check the signature by downloading the
-accompanying '.sig' file and doing:
-
- gpg --verify ess-18.10.tgz.sig
-
- Alternatively, you may download the git repository. ESS is currently
-hosted on GitHub: <https://github.com/emacs-ess/ESS>. 'git clone
-https://github.com/emacs-ess/ESS.git' will download it to a new
-directory 'ESS' in the current working directory.
-
- We will refer to the location of the ESS source files as
-'/path/to/ESS/' hereafter.
-
- After installing, users should make sure they activate or load ESS in
-each Emacs session, see *note Activating and Loading ESS::
-
- Optionally, compile elisp files, build the documentation, and the
-autoloads:
- cd /path/to/ESS/
- make
- 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 'make install'. You might need
-administrative privileges:
-
- make install
-
- The files are installed into '/usr/share/emacs' directory. For this
-step to run correctly on macOS, you will need to adjust the 'PREFIX'
-path in 'Makeconf'. The necessary code and instructions are commented
-in that file.
-
-\1f
-File: announc.info, Node: Activating and Loading ESS, Next: Check Installation, Prev: Installing from source
-
-1.4 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 *note Check Installation::
-
- Otherwise, you may need to add the path to ESS to 'load-path' with:
-
- (add-to-list 'load-path "/path/to/ESS/lisp")
-
- 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 'make'):
-
- (load "ess-autoloads")
-
- To require ESS on startup, you can either put
-
- (require 'ess-site)
-
- or
-
- (require 'ess-r-mode)
-
- In your configuration file, depending on whether you want all ESS
-features or only R related features.
-
-\1f
-File: announc.info, Node: Check Installation, Prev: Activating and Loading ESS
-
-1.5 Check Installation
-======================
-
-Restart Emacs and check that ESS was loaded from a correct location with
-'M-x ess-version'.
-
-\1f
-File: announc.info, Node: Current Features, Next: Requirements, Prev: Latest Version, Up: Announce
-
-1.6 Current Features
-====================
-
- * Languages Supported:
- * S family (R, S, and S+ AKA S-PLUS)
- * SAS
- * BUGS/JAGS
- * Stata
- * Julia
- * Editing source code (S family, SAS, BUGS/JAGS, Stata, Julia)
- * Syntactic indentation and highlighting of source code
- * Partial evaluation of code
- * Loading and error-checking of code
- * Source code revision maintenance
- * Batch execution (SAS, BUGS/JAGS)
- * Use of imenu to provide links to appropriate functions
- * Interacting with the process (S family, SAS, Stata, Julia)
- * Command-line editing
- * Searchable Command history
- * Command-line completion of S family object names and file
- names
- * Quick access to object lists and search lists
- * Transcript recording
- * Interface to the help system
- * Transcript manipulation (S family, Stata)
- * Recording and saving transcript files
- * Manipulating and editing saved transcripts
- * Re-evaluating commands from transcript files
- * Interaction with Help Pages and other Documentation (R)
- * Fast Navigation
- * Sending Examples to running ESS process.
- * Fast Transfer to Further Help Pages
- * Help File Editing (R)
- * Syntactic indentation and highlighting of source code.
- * Sending Examples to running ESS process.
- * Previewing
-
-\1f
-File: announc.info, Node: Requirements, Next: Mailing List, Prev: Current Features, Up: Announce
-
-1.7 Requirements
-================
-
-ESS 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.
-
-\1f
-File: announc.info, Node: Mailing List, Next: Reporting Bugs, Prev: Requirements, Up: Announce
-
-1.8 Mailing List
-================
-
-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 <ess-help-requestNOSPAMr-project.org>; contributions
-to the list may be mailed to <ess-helpNOSPAMr-project.org>. Rest assured,
-this is a fairly low-volume mailing list.
-
- The purposes of the mailing list include
-
- * helping users of ESS to get along with it.
- * discussing aspects of using ESS.
- * suggestions for improvements.
- * announcements of new releases of ESS.
- * posting small patches to ESS.
-
-\1f
-File: announc.info, Node: Reporting Bugs, Next: Authors, Prev: Mailing List, Up: Announce
-
-1.9 Reporting Bugs
-==================
-
-Please send bug reports, suggestions etc. to <ESS-bugsNOSPAMr-project.org>,
-or post them on our github issue tracker
-(https://github.com/emacs-ess/ESS/issues)
-
- The easiest way to do this is within Emacs by typing
-
- '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.
-
-\1f
-File: announc.info, Node: Authors, Next: License, Prev: Reporting Bugs, Up: Announce
-
-1.10 Authors
-============
-
- * A.J. Rossini (mailto:blindglobeNOSPAMgmail.com)
- * Richard M. Heiberger (mailto:rmhNOSPAMtemple.edu)
- * Kurt Hornik (mailto:Kurt.HornikNOSPAMR-project.org)
- * Martin Maechler (mailto:maechlerNOSPAMstat.math.ethz.ch)
- * Rodney A. Sparapani (mailto:rsparapaNOSPAMmcw.edu)
- * Stephen Eglen (mailto:stephenNOSPAMgnu.org)
- * Sebastian P. Luque (mailto:spluqueNOSPAMgmail.com)
- * Henning Redestig (mailto:henning.redNOSPAMgooglemail.com)
- * Vitalie Spinu (mailto:spinuvitNOSPAMgmail.com)
- * Lionel Henry (mailto:lionel.hryNOSPAMgmail.com)
- * J. Alexander Branham (mailto:alex.branhamNOSPAMgmail.com)
-
-\1f
-File: announc.info, Node: License, Next: New Features, Prev: Authors, Up: Announce
-
-1.11 License
-============
-
-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.
-
-\1f
-File: announc.info, Node: New Features, Prev: License, Up: Announce
-
-1.12 New Features
-=================
-
-Changes and New Features in 19.04 (unreleased):
-
- * 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
- <language>-mode-hook and <language>-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. See
- *Note (ess)Controlling buffer display:: for more information and
- examples.
-
- * '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.
-
- * 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.
-
- 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 <https://github.com/polymode/poly-R/>,
- <https://polymode.github.io/>, or markdown-mode with edit-indirect
- <https://jblevins.org/projects/markdown-mode>.
-
- * 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" <ess-config-here>)' 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. *Note (ess)Activating and Loading ESS:: for more
- information on this feature.
-
- * 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
-
-
-\1f
-Tag Table:
-Node: Announce\7f75
-Node: Latest Version\7f1298
-Node: Installing from a third-party repository\7f2241
-Node: Installing from source\7f3192
-Node: Activating and Loading ESS\7f4788
-Node: Check Installation\7f5866
-Node: Current Features\7f6090
-Node: Requirements\7f7633
-Node: Mailing List\7f8068
-Node: Reporting Bugs\7f8774
-Node: Authors\7f9654
-Node: License\7f10338
-Node: New Features\7f10988
-\1f
-End Tag Table
+++ /dev/null
-This is authors.info, produced by makeinfo version 6.5 from
-authors.texi.
-
- * A.J. Rossini (mailto:blindglobeNOSPAMgmail.com)
- * Richard M. Heiberger (mailto:rmhNOSPAMtemple.edu)
- * Kurt Hornik (mailto:Kurt.HornikNOSPAMR-project.org)
- * Martin Maechler (mailto:maechlerNOSPAMstat.math.ethz.ch)
- * Rodney A. Sparapani (mailto:rsparapaNOSPAMmcw.edu)
- * Stephen Eglen (mailto:stephenNOSPAMgnu.org)
- * Sebastian P. Luque (mailto:spluqueNOSPAMgmail.com)
- * Henning Redestig (mailto:henning.redNOSPAMgooglemail.com)
- * Vitalie Spinu (mailto:spinuvitNOSPAMgmail.com)
- * Lionel Henry (mailto:lionel.hryNOSPAMgmail.com)
- * J. Alexander Branham (mailto:alex.branhamNOSPAMgmail.com)
-
-\1f
-Tag Table:
-\1f
-End Tag Table
+++ /dev/null
-This is bugrept.info, produced by makeinfo version 6.5 from
-bugrept.texi.
-
-Please send bug reports, suggestions etc. to <ESS-bugsNOSPAMr-project.org>,
-or post them on our github issue tracker
-(https://github.com/emacs-ess/ESS/issues)
-
- The easiest way to do this is within Emacs by typing
-
- '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.
-
-\1f
-Tag Table:
-\1f
-End Tag Table
+++ /dev/null
-This is credits.info, produced by makeinfo version 6.5 from
-credits.texi.
-
-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.
-
- * The multiple process code, and the idea for
- 'ess-eval-line-and-next-line' are by Rod Ball.
-
- * Thanks to Doug Bates for many useful suggestions.
-
- * Thanks to Martin Maechler for reporting and fixing bugs, providing
- many useful comments and suggestions, and for maintaining the ESS
- mailing lists.
-
- * Thanks to Frank Ritter for updates, particularly the menu code, and
- invaluable comments on the manual.
-
- * Thanks to Ken'ichi Shibayama for his excellent indenting code, and
- many comments and suggestions.
-
- * Thanks to Aki Vehtari for adding interactive BUGS support.
-
- * Thanks to Brendan Halpin for bug-fixes and updates to Stata-mode.
-
- * Last, but definitely not least, thanks to the many ESS users and
- contributors to the ESS mailing lists.
-
- _ESS_ is being developed and currently maintained by
-
- * A.J. Rossini (mailto:blindglobeNOSPAMgmail.com)
- * Richard M. Heiberger (mailto:rmhNOSPAMtemple.edu)
- * Kurt Hornik (mailto:Kurt.HornikNOSPAMR-project.org)
- * Martin Maechler (mailto:maechler@stat.math.ethz.ch)
- * Rodney A. Sparapani (mailto:rsparapaNOSPAMmcw.edu)
- * Stephen Eglen (mailto:stephenNOSPAMgnu.org)
- * Sebastian P. Luque (mailto:spluqueNOSPAMgmail.com)
- * Henning Redestig (mailto:henning.redNOSPAMgooglemail.com)
- * Vitalie Spinu (mailto:spinuvitNOSPAMgmail.com)
- * Lionel Henry (mailto:lionel.hryNOSPAMgmail.com)
- * J. Alexander Branham (mailto:alex.branhamNOSPAMgmail.com)
-
-\1f
-Tag Table:
-\1f
-End Tag Table
+++ /dev/null
-This is currfeat.info, produced by makeinfo version 6.5 from
-currfeat.texi.
-
- * Languages Supported:
- * S family (R, S, and S+ AKA S-PLUS)
- * SAS
- * BUGS/JAGS
- * Stata
- * Julia
- * Editing source code (S family, SAS, BUGS/JAGS, Stata, Julia)
- * Syntactic indentation and highlighting of source code
- * Partial evaluation of code
- * Loading and error-checking of code
- * Source code revision maintenance
- * Batch execution (SAS, BUGS/JAGS)
- * Use of imenu to provide links to appropriate functions
- * Interacting with the process (S family, SAS, Stata, Julia)
- * Command-line editing
- * Searchable Command history
- * Command-line completion of S family object names and file
- names
- * Quick access to object lists and search lists
- * Transcript recording
- * Interface to the help system
- * Transcript manipulation (S family, Stata)
- * Recording and saving transcript files
- * Manipulating and editing saved transcripts
- * Re-evaluating commands from transcript files
- * Interaction with Help Pages and other Documentation (R)
- * Fast Navigation
- * Sending Examples to running ESS process.
- * Fast Transfer to Further Help Pages
- * Help File Editing (R)
- * Syntactic indentation and highlighting of source code.
- * Sending Examples to running ESS process.
- * Previewing
-
-
-\1f
-Tag Table:
-\1f
-End Tag Table
+++ /dev/null
-This is the file .../info/dir, which contains the
-topmost node of the Info hierarchy, called (dir)Top.
-The first time you invoke Info you start off looking at this node.
-\1f
-File: dir, Node: Top, This is the top of the INFO tree
-
- This (the Directory node) gives a menu of major topics.
- Typing "q" exits, "?" lists all Info commands, "d" returns here,
- "h" gives a primer for first-timers,
- "mEmacs<Return>" visits the Emacs manual, etc.
-
- In Emacs, you can click mouse button 2 on a menu item or cross reference
- to select it.
-
-* Menu:
-
-Emacs
-* ESS: (ess). Emacs Speaks Statistics (R/S/S+, SAS,
- BUGS/JAGS and Stata).
+++ /dev/null
-;;; ess-autoloads.el --- automatically extracted autoloads
-;;
-;;; Code:
-(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
-\f
-;;;### (autoloads nil "ess" "ess.el" (23994 46764 990680 902000))
-;;; Generated autoloads from ess.el
-
-(autoload 'ess-version "ess" "\
-Return a string with ESS version information.
-
-\(fn)" t nil)
-
-(autoload 'ess-submit-bug-report "ess" "\
-Submit a bug report to the ESS maintainers.
-
-\(fn)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "ess-bugs-d" "ess-bugs-d.el" (23994 46764 917667
-;;;;;; 161000))
-;;; Generated autoloads from ess-bugs-d.el
-
-(autoload 'ess-bugs-mode "ess-bugs-d" "\
-Major mode for BUGS.
-
-\(fn)" t nil)
-
-(add-to-list 'auto-mode-alist '("\\.[Bb][Uu][Gg]\\'" . ess-bugs-mode))
-
-(add-to-list 'auto-mode-alist '("\\.[Bb][Oo][Gg]\\'" . ess-bugs-mode))
-
-(add-to-list 'auto-mode-alist '("\\.[Bb][Mm][Dd]\\'" . ess-bugs-mode))
-
-;;;***
-\f
-;;;### (autoloads nil "ess-custom" "ess-custom.el" (23994 46764 953959
-;;;;;; 908000))
-;;; Generated autoloads from ess-custom.el
-
-(defvar ess-lisp-directory (file-name-directory (or load-file-name buffer-file-name)) "\
-Directory containing ess-site.el(c) and other ESS Lisp files.")
-
-(custom-autoload 'ess-lisp-directory "ess-custom" t)
-
-(add-to-list 'load-path ess-lisp-directory)
-
-(add-to-list 'load-path (file-name-as-directory (expand-file-name "obsolete" ess-lisp-directory)))
-
-(put 'ess-indent-offset 'safe-local-variable #'numberp)
-
-(put 'ess-style 'safe-local-variable #'symbolp)
-
-;;;***
-\f
-;;;### (autoloads nil "ess-gretl" "ess-gretl.el" (23994 46764 949104
-;;;;;; 258000))
-;;; Generated autoloads from ess-gretl.el
-
-(autoload 'ess-gretl-mode "ess-gretl" "\
-Major mode for editing gretl source. See `ess-mode' for more help.
-
-\(fn)" t nil)
-
-(autoload 'gretl "ess-gretl" "\
-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'.
-
-\(fn &optional START-ARGS)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "ess-inf" "ess-inf.el" (23994 46764 956265
-;;;;;; 802000))
-;;; Generated autoloads from ess-inf.el
-
-(autoload 'ess-load-file "ess-inf" "\
-Load FILENAME into an inferior ESS process.
-This handles Tramp when working on a remote.
-
-\(fn &optional FILENAME)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "ess-jags-d" "ess-jags-d.el" (23994 46764 989659
-;;;;;; 375000))
-;;; Generated autoloads from ess-jags-d.el
-
-(autoload 'ess-jags-mode "ess-jags-d" "\
-Major mode for JAGS.
-
-\(fn)" t nil)
-
-(add-to-list 'auto-mode-alist '("\\.[Jj][Aa][Gg]\\'" . ess-jags-mode))
-
-;;;***
-\f
-;;;### (autoloads nil "ess-julia" "ess-julia.el" (23994 46764 987711
-;;;;;; 280000))
-;;; Generated autoloads from ess-julia.el
-
-(autoload 'ess-julia-mode "ess-julia" "\
-Major mode for julia files.
-
-\(fn)" t nil)
-
-(autoload 'run-ess-julia "ess-julia" "\
-Start an inferior julia process.
-Optional prefix START-ARGS (\\[universal-argument]) allows to set
-command line arguments, such as --load=<file>. 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'.
-
-\(fn &optional START-ARGS)" t nil)
-
-(defalias 'julia #'run-ess-julia)
-
-;;;***
-\f
-;;;### (autoloads nil "ess-mode" "ess-mode.el" (23994 46764 952949
-;;;;;; 668000))
-;;; Generated autoloads from ess-mode.el
-
-(autoload 'ess-mode "ess-mode" "\
-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.
-
-\(fn)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "ess-r-mode" "ess-r-mode.el" (23994 46764 919684
-;;;;;; 960000))
-;;; Generated autoloads from ess-r-mode.el
-
-(autoload 'run-ess-r "ess-r-mode" "\
-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.
-
-\(fn &optional START-ARGS)" t nil)
-
-(defalias 'R #'run-ess-r)
-
-(autoload 'ess-r-mode "ess-r-mode" "\
-Major mode for editing R source. See `ess-mode' for more help.
-
-\(fn)" t nil)
-
-(defalias 'R-mode 'ess-r-mode)
-
-(defalias 'r-mode 'ess-r-mode)
-
-(add-to-list 'auto-mode-alist '("/R/.*\\.q\\'" . ess-r-mode))
-
-(add-to-list 'auto-mode-alist '("\\.[rR]\\'" . ess-r-mode))
-
-(add-to-list 'auto-mode-alist '("\\.[rR]profile\\'" . ess-r-mode))
-
-(add-to-list 'auto-mode-alist '("NAMESPACE\\'" . ess-r-mode))
-
-(add-to-list 'auto-mode-alist '("CITATION\\'" . ess-r-mode))
-
-(autoload 'ess-r-transcript-mode "ess-r-mode" "\
-A Major mode for R transcript files.
-
-\(fn)" t nil)
-
-(add-to-list 'auto-mode-alist '("\\.[Rr]out" . ess-r-transcript-mode))
-
-(add-to-list 'interpreter-mode-alist '("Rscript" . ess-r-mode))
-
-(add-to-list 'interpreter-mode-alist '("r" . ess-r-mode))
-
-(add-to-list 'auto-mode-alist '("/Makevars\\(\\.win\\)?$" . makefile-mode))
-
-(add-to-list 'auto-mode-alist '("DESCRIPTION$" . conf-colon-mode))
-
-;;;***
-\f
-;;;### (autoloads nil "ess-rd" "ess-rd.el" (23994 46764 952078 13000))
-;;; Generated autoloads from ess-rd.el
-
-(autoload 'Rd-mode "ess-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)
-
-\(fn)" t nil)
-
-(add-to-list 'auto-mode-alist '("\\.Rd\\'" . Rd-mode))
-
-;;;***
-\f
-;;;### (autoloads nil "ess-rdired" "ess-rdired.el" (23994 46764 947244
-;;;;;; 10000))
-;;; Generated autoloads from ess-rdired.el
-
-(autoload 'ess-rdired "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.
-
-\(fn)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "ess-roxy" "ess-roxy.el" (23994 46764 944362
-;;;;;; 342000))
-;;; Generated autoloads from ess-roxy.el
-
-(autoload 'ess-roxy-mode "ess-roxy" "\
-Minor mode for editing ROxygen documentation.
-
-\(fn &optional ARG)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "ess-s-lang" "ess-s-lang.el" (23994 46764 906213
-;;;;;; 450000))
-;;; Generated autoloads from ess-s-lang.el
-
-(add-to-list 'auto-mode-alist '("\\.[Ss]t\\'" . S-transcript-mode))
-
-(add-to-list 'auto-mode-alist '("\\.Sout" . S-transcript-mode))
-
-;;;***
-\f
-;;;### (autoloads nil "ess-sas-d" "ess-sas-d.el" (23994 46764 991721
-;;;;;; 22000))
-;;; Generated autoloads from ess-sas-d.el
-
-(autoload 'SAS-mode "ess-sas-d" "\
-Major mode for editing SAS source. See `ess-mode' for more help.
-
-\(fn)" t nil)
-
-(add-to-list 'auto-mode-alist '("\\.[Ss][Aa][Ss]\\'" . SAS-mode))
-
-;;;***
-\f
-;;;### (autoloads nil "ess-sp6-d" "ess-sp6-d.el" (23994 46764 922686
-;;;;;; 856000))
-;;; Generated autoloads from ess-sp6-d.el
-
-(autoload 'S+-mode "ess-sp6-d" "\
-Major mode for editing S+ source. See `ess-mode' for more help.
-
-\(fn &optional PROC-NAME)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "ess-stata-mode" "ess-stata-mode.el" (23994
-;;;;;; 46764 927433 996000))
-;;; Generated autoloads from ess-stata-mode.el
-
-(autoload 'ess-stata-mode "ess-stata-mode" "\
-Major mode for editing Stata source.
-
-\(fn)" t nil)
-
-(add-to-list 'auto-mode-alist '("\\.do\\'" . ess-stata-mode))
-
-(add-to-list 'auto-mode-alist '("\\.ado\\'" . ess-stata-mode))
-
-;;;***
-\f
-;;;### (autoloads nil "ess-trns" "ess-trns.el" (23994 46764 942470
-;;;;;; 496000))
-;;; Generated autoloads from ess-trns.el
-
-(autoload 'ess-transcript-mode "ess-trns" "\
-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.
-
-\(fn)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "essd-els" "essd-els.el" (23994 46764 908205
-;;;;;; 460000))
-;;; Generated autoloads from essd-els.el
-
-(autoload 'ess-remote "essd-els" "\
-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
-
-\(fn &optional PROC-NAME DIALECT)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil nil ("ess-bugs-l.el" "ess-help.el" "ess-pkg.el"
-;;;;;; "ess-r-completion.el" "ess-r-flymake.el" "ess-r-package.el"
-;;;;;; "ess-r-syntax.el" "ess-r-xref.el" "ess-sas-a.el" "ess-sas-l.el"
-;;;;;; "ess-site.el" "ess-stata-lang.el" "ess-toolbar.el" "ess-tracebug.el"
-;;;;;; "ess-utils.el" "make-regexp.el") (23994 46764 993654 130000))
-
-;;;***
-\f
-;; Local Variables:
-;; version-control: never
-;; no-byte-compile: t
-;; no-update-autoloads: t
-;; End:
-;;; ess-autoloads.el ends here
+++ /dev/null
-;;; ess-bugs-d.el --- ESS[BUGS] dialect -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2008-2011 Rodney Sparapani
-
-;; Author: Rodney Sparapani
-;; Created: 13 March 2008
-;; Maintainer: ESS-help <ess-helpNOSPAMr-project.org>
-
-;; 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/
-
-;;; 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 "\\<d\\(bern\\|beta\\|bin\\|cat\\|chisq\\|"
- "dexp\\|dirch\\|exp\\|\\(gen[.]\\)?gamma\\|hyper\\|"
- "interval\\|lnorm\\|logis\\|mnorm\\|mt\\|multi\\|"
- "negbin\\|norm\\(mix\\)?\\|par\\|pois\\|sum\\|t\\|"
- "unif\\|weib\\|wish\\)[ \t\n]*(")
- font-lock-constant-face)
-
- (cons (concat "\\<\\(abs\\|cos\\|C\\|dim\\|\\(i\\)?cloglog\\|equals\\|"
- "exp\\|for\\|inprod\\|interp[.]line\\|inverse\\|length\\|"
- "\\(i\\)?logit\\|logdet\\|logfact\\|loggam\\|max\\|mean\\|"
- "mexp\\|min\\|phi\\|pow\\|probit\\|prod\\|rank\\|round\\|"
- "sd\\|sin\\|sort\\|sqrt\\|step\\|sum\\|t\\|trunc\\|T\\)[ \t\n]*(")
- font-lock-function-name-face)
-
- ;; .bmd files
- (cons (concat (regexp-opt '(
- "dicClear" "dicSet" "dicStats"
- "infoMemory" "infoModules" "infoNodeMethods"
- "infoNodeTypes" "infoNodeValues"
- "infoUpdatersbyDepth" "infoUpdatersbyName"
- "modelCheck" "modelCompile" "modelData"
- "modelDisable" "modelEnable" "modelGenInits"
- "modelInits" "modelPrecision" "modelQuit"
- "modelSaveState" "modelSetAP" "modelSetIts"
- "modelSetOR" "modelSetRN" "modelUpdate"
- "ranksClear" "ranksSet" "ranksStats"
- "samplesAutoC" "samplesBgr" "samplesCoda"
- "samplesDensity" "samplesHistory" "samplesSet"
- "sampleStats" "samplesThin"
- "summaryClear" "summarySet" "summaryStats"
- ) 'words) "(")
- font-lock-function-name-face)
-
- (cons (concat (regexp-opt '("Local Variables" "End") 'words) ":")
- font-lock-keyword-face)
- )
- "ESS[BUGS]: Font lock keywords."
- )
-
-(defun ess-bugs-switch-to-suffix (suffix &optional bugs-chains bugs-monitor bugs-thin
- bugs-burnin bugs-update)
- "ESS[BUGS]: Switch to file with suffix."
- (find-file (concat ess-bugs-file-dir ess-bugs-file-root suffix))
-
- (if (equal 0 (buffer-size)) (progn
- (if (equal ".bug" suffix) (progn
- ;(insert "var ;\n")
- (insert "model {\n")
- (insert " for (i in 1:N) {\n \n")
- (insert " }\n")
- (insert "}\n")
- (insert "#Local Variables" ":\n")
- ; (insert "#enable-local-variables: :all\n")
- (insert "#ess-bugs-chains:1\n")
- (insert "#ess-bugs-monitor:(\"\")\n")
- (insert "#ess-bugs-thin:1\n")
- (insert "#ess-bugs-burnin:10000\n")
- (insert "#ess-bugs-update:10000\n")
- (insert "#End:\n")
- ))
-
- (if (equal ".bmd" suffix) (let
- ((ess-bugs-temp-chains "") (ess-bugs-temp-monitor ""))
-
- (if bugs-chains (setq ess-bugs-chains bugs-chains))
- (if bugs-monitor (setq ess-bugs-monitor bugs-monitor))
- (if bugs-thin (setq ess-bugs-thin bugs-thin))
-
- (setq ess-bugs-temp-chains
- (concat "modelCompile(" (format "%d" ess-bugs-chains) ")\n"))
-
- (setq bugs-chains ess-bugs-chains)
-
- (while (< 0 bugs-chains)
- (setq ess-bugs-temp-chains
- (concat ess-bugs-temp-chains
- "modelInits('" ess-bugs-file-root
- ".##" (format "%d" bugs-chains) "', "
- (format "%d" bugs-chains) ")\n"))
- (setq bugs-chains (- bugs-chains 1)))
-
- (setq ess-bugs-temp-monitor "")
-
- (while (and (listp ess-bugs-monitor) (consp ess-bugs-monitor))
- (if (not (string-equal "" (car ess-bugs-monitor)))
- (setq ess-bugs-temp-monitor
- (concat ess-bugs-temp-monitor "samplesSet('"
- (car ess-bugs-monitor)
- ;", thin(" (format "%d" ess-bugs-thin)
- "')\n")))
- (setq ess-bugs-monitor (cdr ess-bugs-monitor)))
-
- (insert "modelCheck('" ess-bugs-file-root ".bug')\n")
- (insert "modelData('" ess-bugs-file-root ".bdt')\n")
- (insert (ess-replace-in-string ess-bugs-temp-chains "##" "in"))
- (insert "modelGenInits()\n")
- (insert "modelUpdate(" (format "%d" bugs-burnin) ")\n")
- ;(insert "modelUpdate(" (format "%d" (* bugs-thin bugs-burnin)) ")\n")
- (insert ess-bugs-temp-monitor)
- (insert "modelUpdate(" (format "%d" (* bugs-thin bugs-update)) ")\n")
- ; (insert (ess-replace-in-string
- ; (ess-replace-in-string ess-bugs-temp-chains
- ; "modelCompile([0-9]+)" "#") "##" "to"))
-
- (if (< 1 bugs-thin) (insert "samplesThin(" (format "%d" bugs-thin) ")\n"))
-
- (insert "samplesCoda('*', '" ess-bugs-file-root "')\n")
-
- ; (if ess-bugs-system (progn
- ; (insert "system rm -f " ess-bugs-file-root ".ind\n")
- ; (insert "system ln -s " ess-bugs-file-root "index.txt " ess-bugs-file-root ".ind\n")
-
- ; (setq bugs-chains ess-bugs-chains)
-
- ; (while (< 0 bugs-chains)
- ; (setq ess-bugs-temp-chain (format "%d" bugs-chains))
-
- ; ;.txt not recognized by BOA and impractical to over-ride
- ; (insert "system rm -f " ess-bugs-file-root ess-bugs-temp-chain ".out\n")
- ; (insert "system ln -s " ess-bugs-file-root "chain" ess-bugs-temp-chain ".txt "
- ; ess-bugs-file-root ess-bugs-temp-chain ".out\n")
- ; (setq bugs-chains (- bugs-chains 1)))))
-
- (insert "modelQuit()\n")
- (insert "Local Variables" ":\n")
- ; (insert "enable-local-variables: :all\n")
- (insert "ess-bugs-chains:" (format "%d" ess-bugs-chains) "\n")
- (insert "ess-bugs-command:\"" ess-bugs-command "\"\n")
- (insert "End:\n")
- ))
- ))
- )
-
-(defun ess-bugs-na-bmd (bugs-command)
- "ESS[BUGS]: Perform the Next-Action for .bmd."
- ;(ess-save-and-set-local-variables)
- (if (equal 0 (buffer-size)) (ess-bugs-switch-to-suffix ".bmd")
- ;else
- (shell)
- (ess-sleep)
-
- (when (and (when (fboundp 'w32-shell-dos-semantics)
- (w32-shell-dos-semantics))
- (string-equal ":" (substring ess-bugs-file 1 2)))
- (insert (substring ess-bugs-file 0 2)))
-
- (comint-send-input)
- (insert "cd \"" ess-bugs-file-dir "\"")
- (comint-send-input)
-
- ; (let ((ess-bugs-temp-chains ""))
- ;
- ; (while (< 0 bugs-chains)
- ; (setq ess-bugs-temp-chains
- ; (concat (format "%d " bugs-chains) ess-bugs-temp-chains))
- ; (setq bugs-chains (- bugs-chains 1)))
-
- ;; (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 "' > " 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
+++ /dev/null
-;;; ess-bugs-l.el --- ESS[BUGS] languages -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2006-2011 Rodney Sparapani
-
-;; Author: Rodney Sparapani
-;; Created: 16 August 2006
-;; Maintainer: ESS-help <ess-helpNOSPAMr-project.org>
-
-;; 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/
-
-
-;;; 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
+++ /dev/null
-;;; ess-custom.el --- Customize variables for ESS -*- lexical-binding: t; -*-
-
-;; Copyright (C) 1997--2010 A.J. Rossini, Richard M. Heiberger, Martin
-;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
-;; Copyright (C) 2011--2015 A.J. Rossini, Richard M. Heiberger, Martin Maechler,
-;; Kurt Hornik, Rodney Sparapani, Stephen Eglen and Vitalie Spinu.
-
-;; Author: A.J. Rossini <blindglobeNOSPAMgmail.com>
-;; Created: 05 June 2000
-;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
-
-;; Keywords: languages
-
-;; 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-Stata nil
- "ESS: Stata."
- :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-")
-
-
-\f ; 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 . "19.04"))
-
-(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 . "19.04"))
-
-;; 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 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 (file-name-as-directory (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 . "19.04"))
-
-(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. 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 . "19.04"))
-
-(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
- "Non-nil means request the process directory each time S is run."
- :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.")
-
-(defcustom ess-directory-function nil
- "Function to return the directory that ESS is run from.
-If nil or if the function returns nil then you get `ess-startup-directory'."
- :group 'ess
- :type '(choice (const nil) function))
-
-(defcustom ess-setup-directory-function nil
- "Function to setup the directory that ESS is run from.
-This function can be called to set environment variables or to create
-a workspace."
- :group 'ess
- :type '(choice (const nil) function))
-
-(defvaralias 'ess-directory 'ess-startup-directory)
-(defcustom ess-startup-directory nil
- "The directory ESS is run from. It must end in a slash.
-Provided as a default if `ess-ask-for-ess-directory' is non-nil.
-A nil value means use the current buffer's default directory."
- :group 'ess
- :type '(choice (const nil) directory))
-
-
-(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 . "18.10"))
-
-(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 "18.10"))
-(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 . "18.10"))
-
-;;*;; 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 . "19.04"))
-
-;;*;; 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 refexes 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 . "18.10"))
-
-(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.
-Good for evaluating ESS code."
- :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"
- "inheritParams"
- "importFrom" "importClassesFrom"
- "importMethodsFrom" "useDynLib"
- "rdname" "section" "slot" "description"
- "md" "eval")
- "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
- "Non-nil causes parameter descriptions to be filled (word-wrapped) upon `ess-roxy-update-entry'."
- :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-and-indent' makes newlines start with the roxy prefix.")
-
-\f ; 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 . "19.04"))
-
-
-(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
-
-;; -- Note: Some variables not-to-customize moved to ./ess-mode.el :
-;; ess-r-set-function-start
-
-;; Fixme: the following is just for S dialects :
-(defcustom ess-dumped-missing-re
- "\\(<-\nDumped\n\\'\\)\\|\\(<-\\(\\s \\|\n\\)*\\'\\)"
- "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)
-
-
-\f ; 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)
-
-(defcustom inferior-STA-start-args ""
- "String of switches used when starting Stata.
-Also see `inferior-STA-program'."
- :group 'ess-Stata
- :type 'string)
-
-(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)
- "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")))
- "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)))
-
-(define-obsolete-variable-alias 'inferior-STA-program-name
- 'inferior-STA-program "ESS 18.10")
-(defcustom inferior-STA-program "stata"
- "Program name for invoking an inferior ESS with stata().
-This is NOT Stata, because we need to call Stata with TERM=emacs in
-order for it to work right. And Emacs is too smart for it."
- :group 'ess-Stata
- :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 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 t
- "Non-nil means ess-eval- commands display commands in the process buffer.
-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 'nowait, ESS still shows the input commands, but don't wait
-for the process. Thus all the output is printed after the input
-lines.
-
-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
- :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)
-
-\f ; 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 <ess-lang>-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
- "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 "[-=+></]+" 'ess-operator-face)
- "Operators.")
-
-(defvar ess-S-fl-keyword:modifiers
- (cons (regexp-opt ess-S-modifiers 'words)
- 'ess-modifiers-face) ; modify search list or source (i.e. directives)
- "Font lock keyword R modifiers.")
-
-(defvar ess-S-fl-keyword:fun-defs
- (cons ess-S-function-name-regexp
- '(1 font-lock-function-name-face t))
- "Font-lock function definitions keyword.")
-
-(defvar ess-S-fl-keyword:keywords
- (cons (regexp-opt ess-S-keywords 'words) 'ess-keyword-face))
-
-(defvar ess-S-fl-keyword:assign-ops
- (cons (regexp-opt ess-S-assign-ops) 'ess-assignment-face)
- "Font-lock assign operators.")
-
-(defvar ess-S-fl-keyword:constants
- (cons (regexp-opt ess-S-constants 'words) 'ess-constant-face)
- "Font-lock constants keyword.")
-
-(defcustom ess-S-font-lock-keywords
- '((ess-S-fl-keyword:modifiers . t)
- (ess-S-fl-keyword:fun-defs . t)
- (ess-S-fl-keyword:keywords . t)
- (ess-S-fl-keyword:assign-ops . t)
- (ess-S-fl-keyword:constants . t)
- (ess-fl-keyword:fun-calls)
- (ess-fl-keyword:numbers)
- (ess-fl-keyword:operators)
- (ess-fl-keyword:delimiters)
- (ess-fl-keyword:=))
- "An alist of available font-lock keywords for the S mode.
-The key of each cons cell is a name of the keyword. The value
-should be t or nil to indicate if the keyword is activated by
-default or not."
- :group 'ess-S
- :group 'ess-faces
- :type '(repeat (cons symbol boolean)))
-
-(defvar ess-R-fl-keyword:modifiers
- '(eval . (cons (concat "\\(" (regexp-opt ess-R-modifiers 'words) "\\)\\s-*(")
- '(1 ess-modifiers-face)))
- "Font-lock keyword R modifiers.
-See `ess-R-modifiers' for the list of modifiers.")
-
-(defvar ess-R-fl-keyword:fun-defs
- '(eval . (cons ess-R-function-name-regexp
- '(1 font-lock-function-name-face nil)))
- "Font-lock keyword for function names in function definitions.
-When this keyword is on, function names on the left hand side of
-<- are highlighted with `font-lock-function-name-face'.")
-
-(defvar ess-R-fl-keyword:keywords
- '(ess-r--find-fl-keyword . ess-keyword-face)
- "Font lock keyword for `ess-R-keywords'.")
-
-(defvar ess-R-fl-keyword:assign-ops
- '(eval . (cons (regexp-opt ess-R-assign-ops) 'ess-assignment-face))
- "Font-lock assign operators.
-See `ess-R-assign-ops' for the ops.")
-
-(defvar ess-R-fl-keyword:constants
- '(eval . (cons (regexp-opt ess-R-constants 'words) 'ess-constant-face))
- "Font-lock constants keyword.
-See `ess-R-constants' for the list of constants.")
-
-(defvar ess-R-fl-keyword:F&T
- '("\\b[FT]\\b" . ess-constant-face)
- "Highlight T and F in addition to TRUE and FALSE in R.")
-
-(defvar ess-R-fl-keyword:%op% nil
- "Highlight %op% operators.")
-
-(defcustom ess-R-font-lock-keywords
- '((ess-R-fl-keyword:keywords . t)
- (ess-R-fl-keyword:constants . t)
- (ess-R-fl-keyword:modifiers . t)
- (ess-R-fl-keyword:fun-defs . t)
- (ess-R-fl-keyword:assign-ops . t)
- (ess-R-fl-keyword:%op% . t)
- (ess-fl-keyword:fun-calls)
- (ess-fl-keyword:numbers)
- (ess-fl-keyword:operators)
- (ess-fl-keyword:delimiters)
- (ess-fl-keyword:=)
- (ess-R-fl-keyword:F&T))
- "An alist of available font-lock keywords for the R mode.
-The key of each cons cell is a name of the keyword. The value
-should be t or nil to indicate if the keyword is active or not."
- :group 'ess-R
- :group 'ess-faces
- :type '(repeat (cons symbol boolean)))
-
-(defvar ess-S-fl-keyword:prompt
- (cons (concat "^" inferior-S-prompt) 'comint-highlight-prompt)
- "Highlight prompts missed by comint.")
-
-(defvar ess-fl-keyword:matrix-labels
- ;; also matches subsetting
- (cons "\\[,?[1-9][0-9]*,?\\]" 'ess-matrix-face)
- "Matrix and vector numeric labels.")
-
-(defvar ess-R-fl-keyword:messages
- (cons (regexp-opt ess-R-message-prefixes 'enc-paren)
- 'font-lock-warning-face)
- "Inferior-ess problems or errors.")
-
-(defvaralias 'inferior-R-font-lock-keywords 'inferior-ess-r-font-lock-keywords)
-(defcustom inferior-ess-r-font-lock-keywords
- '((ess-S-fl-keyword:prompt . t)
- (ess-R-fl-keyword:keywords . t)
- (ess-R-fl-keyword:constants . t)
- (ess-R-fl-keyword:modifiers . t)
- (ess-R-fl-keyword:messages . t)
- (ess-R-fl-keyword:fun-defs . t)
- (ess-R-fl-keyword:assign-ops . t)
- (ess-fl-keyword:matrix-labels . t)
- (ess-fl-keyword:fun-calls)
- (ess-fl-keyword:numbers)
- (ess-fl-keyword:operators)
- (ess-fl-keyword:delimiters)
- (ess-fl-keyword:=)
- (ess-R-fl-keyword:F&T))
- "Font-lock patterns used in `inferior-ess-r-mode' buffers.
-The key of each cons cell is a name of the keyword. The value
-should be t or nil to indicate if the keyword is active or not."
- :group 'ess-R
- :group 'ess-faces
- :type '(repeat (cons symbol boolean)))
-
-(defvar ess-S-fl-keyword:messages
- (cons (regexp-opt ess-S-message-prefixes 'enc-paren)
- 'font-lock-warning-face)
- "Inferior-ess problems or errors.")
-
-(defcustom inferior-S-font-lock-keywords
- '((ess-S-fl-keyword:prompt . t)
- (ess-S-fl-keyword:messages . t)
- (ess-S-fl-keyword:modifiers . t)
- (ess-S-fl-keyword:fun-defs . t)
- (ess-S-fl-keyword:keywords . t)
- (ess-S-fl-keyword:assign-ops . t)
- (ess-S-fl-keyword:constants . t)
- (ess-fl-keyword:fun-calls)
- (ess-fl-keyword:numbers)
- (ess-fl-keyword:operators)
- (ess-fl-keyword:delimiters)
- (ess-fl-keyword:=))
- "Font-lock patterns used in inferior-S-mode buffers.
-The key of each cons cell is a name of the keyword. The value
-should be t or nil to indicate if the keyword is active by
-default."
- :group 'ess-S
- :group 'ess-faces
- :type '(repeat (cons symbol boolean)))
-
-\f
-;;;*;;; ess-help variables
-
-;; This will never need to be loaded independently of any of the other modules,
-;; but they can all call it so we may as well put it here.
-
-(defcustom ess-help-pop-to-buffer t
- "If non-nil ess-help buffers are given focus during the display.
-If non-nil, `ess-display-help' uses `pop-to-buffer' to display
-help, otherwise it uses `display-buffer', which does not select
-the help window."
- :group 'ess-help
- :type 'boolean)
-
-(defcustom ess-help-own-frame nil
- "Controls whether ESS help buffers should start in a different frame.
-
-Possible values are:
- nil: Display help in current frame.
- 'one: All help buffers are shown in one dedicated frame.
- t: Each help buffer gets its own frame.
-
-If this is non-nil,`ess-help-reuse-window' is ignored. The
-parameters of the own frame are stored in
-`ess-help-frame-alist'."
- :group 'ess-help
- :type '(choice (const :tag "Display in current frame" nil)
- (const :tag "Display in one frame" one)
- (const :tag "Always display in a new frame" t)))
-
-(defcustom ess-help-reuse-window t
- "If t, ESS tries to display new help buffers in the existing help window.
-This variable is ignored if `ess-help-own-frame' is non-nil."
- :type 'boolean
- :group 'ess-help)
-
-(defcustom ess-help-frame-alist default-frame-alist
- "Alist of frame parameters used to create help frames.
-This defaults to `default-frame-alist' and is used only when
-the variable `ess-help-own-frame' is non-nil."
- :group 'ess-help
- :type 'alist
- :package-version '(ess . "18.10"))
-
-\f ; Faces
-;;;=====================================================
-
-(defconst comint-highlight-prompt 'comint-highlight-prompt)
-
-(defconst ess-function-call-face 'ess-function-call-face)
-(defface ess-function-call-face
- '((default (:slant normal :inherit font-lock-function-name-face)))
- "Font Lock face used to highlight function calls in ess buffers."
- :group 'ess-faces)
-
-(defconst ess-numbers-face 'ess-numbers-face)
-(defface ess-numbers-face
- '((default (:slant normal :inherit font-lock-type-face)))
- "Font Lock face used to highlight numbers in ess-mode buffers."
- :group 'ess-faces)
-
-(defconst ess-operator-face 'ess-operator-face)
-(defface ess-operator-face
- '((default (:inherit font-lock-constant-face)))
- "Font Lock face for operators."
- :group 'ess-faces)
-
-(defconst ess-%op%-face 'ess-%op%-face)
-(defface ess-%op%-face
- '((default (:inherit ess-operator-face)))
- "Font Lock face used to highlight %op% operators in ess-mode buffers."
- :group 'ess-faces)
-
-(defconst ess-assignment-face 'ess-assignment-face)
-(defface ess-assignment-face
- '((default (:inherit font-lock-constant-face)))
- "Font lock face used to highlight assignment operators."
- :group 'ess-faces)
-
-(defconst ess-paren-face 'ess-paren-face)
-(defface ess-paren-face
- '((default (:inherit font-lock-constant-face)))
- "Font lock face used to highlight parentheses."
- :group 'ess-faces)
-
-(defconst ess-operator-face 'ess-operator-face)
-(defface ess-operator-face
- '((default (:inherit font-lock-constant-face)))
- "Font lock face used to highlight operators."
- :group 'ess-faces)
-
-(defconst ess-modifiers-face 'ess-modifiers-face)
-(defface ess-modifiers-face
- '((default (:inherit font-lock-constant-face)))
- "Font lock face used to highlight modifiers.
-In `R-mode', for example, this includes \"library,\" \"attach,\"
-and others. See `ess-R-modifiers'."
- :group 'ess-faces)
-
-(defconst ess-constant-face 'ess-constant-face)
-(defface ess-constant-face
- '((default (:inherit font-lock-type-face)))
- "Font lock face used to highlight constants.
-In `ess-r-mode', for example, this includes TRUE, FALSE, Inf and
-others. See `ess-R-constants'."
- :group 'ess-faces)
-
-(defconst ess-matrix-face 'ess-matrix-face)
-(defface ess-matrix-face
- '((default (:inherit font-lock-constant-face)))
- "Font lock face used to highlight row/column labels in matrices."
- :group 'ess-faces)
-
-(defconst ess-keyword-face 'ess-keyword-face)
-(defface ess-keyword-face
- '((default (:inherit font-lock-keyword-face)))
- "Font lock face used to highlight reserved keywords.
-In `ess-r-mode', for example, this includes \"while,\" \"if/else\",
-\"function,\" and others. See `ess-R-keywords'."
- :group 'ess-faces)
-
-(defconst ess-r-control-flow-keyword-face 'ess-r-control-flow-keyword-face)
-(defface ess-r-control-flow-keyword-face
- '((default (:inherit ess-keyword-face)))
- "Font lock face used to highlight control flow keywords.
-In `R-mode', for example, this includes \"switch(),\"
-\"tryCatch()\", and \"stop(),\". See
-`ess-R-control-flow-keywords'. By default, these keywords are
-highlighted with the same face as `ess-R-keywords'"
- :group 'ess-faces)
-
-(defcustom ess-help-kill-bogus-buffers t
- "Non-nil means kill ESS help buffers immediately if they are \"bogus\"."
- :group 'ess-help
- :type 'boolean)
-
-(defvar ess-execute-screen-options-command nil
- "Dialect specific command run by `ess-execute-screen-options'.")
-
-(defvar-local ess-funargs-command nil
- "Dialect specific command to return a list of function arguments.
-See `ess-function-arguments' and .ess_funargs command in R and
-S+ for details of the format that should be returned.")
-
-\f ; System variables
-;;;=====================================================
-;;; Users note: You will rarely have to change these
-;;; variables.
-
-;;*;; Variables relating to ess-help-mode
-
-;;-- ess-help-S-.. and ess-help-R-.. : in ess-s-lang.el (are used in ess-inf).
-
-(defvar-local ess-help-sec-keys-alist nil
- "Alist of (key . string) pairs for use in section searching.")
-
-(defvar-local ess-help-sec-regex nil
- "Reg(ular) Ex(pression) of section headers in help file.")
-
-\f ; julia-mode
-(define-obsolete-variable-alias 'inferior-julia-program-name
- 'inferior-julia-program "ESS 18.10")
-(defcustom inferior-julia-program (or (executable-find "julia-basic")
- "julia")
- "Executable for Julia.
-Should be an absolute path to the julia executable."
- :group 'ess-Julia
- :type '(choice (string) (file)))
-
-;; FIXME
-(defvar-local ess-mode-completion-syntax-table nil "Completion and help syntax table for `ess-mode'.")
-
-\f ; Buffer local customization stuff
-
-(defcustom ess-error-buffer-name "*ESS-errors*"
- "Name of buffer to keep process error messages in.
-Created for each process."
- :group 'ess-proc
- :type 'string)
-
-(defvar ess-error-regexp-alist nil
- "List of symbols which are looked up in `compilation-error-regexp-alist-alist'.")
-
-(defcustom ess-write-to-dribble t
- "Non-nil means write to `ess-dribble-buffer'.
-See also `ess-verbose'."
- :group 'ess-proc
- :type 'boolean
- :package-version '(ess . "18.10"))
-
-(defcustom ess-verbose nil
- "Non-nil means write more information to `ess-dribble-buffer' than usual."
- :group 'ess-proc
- :type 'boolean)
-
-(defvar ess-dribble-buffer "*ESS*"
- "Buffer or name of buffer for printing debugging information.")
-
-(defvar-local ess-local-customize-alist nil
- "Buffer local settings for proper behavior.
-Used to store the values for passing on to newly created buffers.")
-
-(defvar ess-mode-editing-alist nil
- "Variable settings for `ess-mode'.")
-
-(defvar-local ess-transcript-minor-mode nil
- "Non-nil if using `ess-transcript-mode' as a minor mode of some other mode.")
-
-(defvar-local ess-listing-minor-mode nil
- "Non-nil if using `ess-listing-minor-mode'.")
-
-(defvar ess--enable-experimental-projects nil
- "Enable experimental project support in ESS.")
-
-(defvar ess-STERM nil
- "Placeholder for dialect-specific STERM.")
-
-(make-obsolete-variable 'ess-S-loop-timeout "It is ignored." "ESS 18.10")
-(make-obsolete-variable 'ess-mode-load-hook "It is ignored." "ESS 18.10")
-(make-obsolete-variable 'ess-speedbar-use-p "It is ignored." "ESS 18.10")
-(make-obsolete-variable 'ess-synchronize-evals "It is ignored." "ESS 18.10")
-(make-obsolete-variable 'ess-eval-visibly-at-end "It is ignored." "ESS 18.10")
-(make-obsolete-variable 'ess-font-lock-mode 'global-font-lock-mode "ESS 18.10")
-(provide 'ess-custom)
-
-;;; ess-custom.el ends here
+++ /dev/null
-This is ess-defs.info, produced by makeinfo version 6.5 from
-ess-defs.texi.
-
-
-\1f
-Tag Table:
-\1f
-End Tag Table
+++ /dev/null
-;; ess-gretl.el --- ESS gretl mode and inferior interaction -*- lexical-binding: t; -*-
-;;
-;; Copyright (C) 2012 Allin Cottrell
-;; Copyright (C) 2012 Ahmadou DICKO
-;; Copyright (C) 2013 ESS core team
-;;
-;; Filename: ess-gretl.el
-;; Author: Ahmadou DICKO, Spinu Vitalie and Allin Cottrell (based on ess-julia.el and gretl.el)
-;; Maintainer: Ahmadou DICKO
-;; Created: 01-10-2012 (ESS 12.09)
-;; Keywords: ESS, gretl, econometrics
-;;
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-
-;; This file is *NOT* part of GNU Emacs.
-;;
-;; This program is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License as
-;; published by the Free Software Foundation; either version 3, 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.
-;;
-;; A copy of the GNU General Public License is available at
-;; https://www.r-project.org/Licenses/
-;;
-;;
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;;; Commentary:
-;; start the inferior with M-x gretl.
-;;
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-(require 'compile); for compilation-* below
-(require 'ess-r-mode)
-
-;;; Code:
-(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 "\\<\\("
- (mapconcat 'identity gretl-keywords "\\|")
- "\\)\\>")
- 'font-lock-keyword-face)
- ;; Fontify all option flags.
- (cons (concat "[ \t]--\\("
- (mapconcat 'identity gretl-option-flags "\\|")
- "\\)")
- 'font-lock-constant-face)
- ;; Fontify all command words.
- (cons (concat "\\<\\("
- (mapconcat 'identity 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 "\\$\\("
- (mapconcat 'identity gretl-internal-vars "\\|")
- "\\)\\>")
- 'font-lock-variable-name-face)
-
- ;; Fontify all genr functions.
- (cons (concat "\\<\\("
- (mapconcat 'identity 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 "\\<\\("
- (mapconcat 'identity gretl-block-start-keywords "\\|")
- "\\)\\>"))
-
-(defvar gretl-block-else-regexp
- (concat "\\<\\("
- (mapconcat 'identity gretl-block-other-keywords "\\|")
- "\\)\\>"))
-
-(defvar gretl-block-end-regexp
- (concat "\\<\\("
- (mapconcat 'identity 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 (point-at-bol)) 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
+++ /dev/null
-;;; ess-help.el --- Support for viewing ESS help files -*- lexical-binding: t; -*-
-
-;; Copyright (C) 1989-1994, 2017 Bates, Kademan, Ritter and Smith
-;; Copyright (C) 1997, A.J. Rossini <rossiniNOSPAMstat.sc.edu>
-;; Copyright (C) 1998--2001 A.J. Rossini, Martin Maechler, Kurt Hornik and
-;; Richard M. Heiberger <rmhNOSPAMtemple.edu>.
-;; Copyright (C) 2001--2010 A.J. Rossini, Richard M. Heiberger, Martin
-;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
-;; Copyright (C) 2011--2012 A.J. Rossini, Richard M. Heiberger, Martin Maechler,
-;; Kurt Hornik, Rodney Sparapani, Stephen Eglen and Vitalie Spinu.
-
-;; Author: David Smith <dsmithNOSPAMstats.adelaide.edu.au>
-;; Created: 7 Jan 1994
-;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
-
-;; 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:
-
-;; Code for dealing with ESS help files. See README.<LANGUAGE> where
-;; <LANGUAGE> is one of `S', `SAS', `Stata' or `XLispStat'.
-
-;;; Code:
-
-\f ; 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.")
-
-\f ; 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 ;update cache if prefix
- (ess-process-put 'sp-for-help-changed? t))
- (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-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)
- ;; Three ways to find HTML help, 1) ask sub-process 2) get URL/file from subprocess
- ;; 3) call elisp function to get the file path
- ;; For 2 and 3 call browse-url on the output
- (let (com-html-help ;1) command for sub-process to trigger
- ;help, must contain %s for help obj
- com-get-file-path ;2) command for sub-process to return a
- ; location for the help page, must
- ; contain %s for help obj
- fun-get-file-path ;3) elisp function to return the
- ;location, gets one argument, help topic
- not-implemented
- )
- (cond
- ((string-match "^R" ess-dialect)
- (setq com-html-help "help('%s', help_type='html')\n"))
- (t (setq not-implemented t))
- )
- (if not-implemented
- (message "Sorry, not implemented for %s " ess-dialect)
- (if (or (not ess-help-object)
- (not (eq ess-help-type 'help)))
- (message "No help topic found")
- (if com-html-help
- (ess-command (format com-html-help ess-help-object))
- (require 'browse-url)
- (if com-get-file-path
- (browse-url (car (ess-get-words-from-vector
- (format com-get-file-path ess-help-object))))
- (when (functionp fun-get-file-path)
- (browse-url (funcall fun-get-file-path 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))
- (setq ess-help-object help-object
- ess-help-sec-regex "\\(^\\s-.*\n\\)\\|\\(^\n\\)")
- (ess-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)
- 'appropos)))
-
-(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 <TEACH> 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))
-
-\f
-;;*;; 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))))
-
-\f
-;;*;; 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")
- (prog1 (ess-get-words-from-vector ".ess.getHelpAliases()\n")
- (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 "_\b" 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)))
-
-\f
-;; 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 wan 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
+++ /dev/null
-;;; ess-inf.el --- Support for running S as an inferior Emacs process -*- lexical-binding: t; -*-
-
-;; Copyright (C) 1989-1994 Bates, Kademan, Ritter and Smith
-;; Copyright (C) 1997-1999 A.J. Rossini <rossiniNOSPAMu.washington.edu>,
-;; Martin Maechler <maechlerNOSPAMstat.math.ethz.ch>.
-;; Copyright (C) 2000--2010 A.J. Rossini, Richard M. Heiberger, Martin
-;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
-;; Copyright (C) 2011--2012 A.J. Rossini, Richard M. Heiberger, Martin Maechler,
-;; Kurt Hornik, Rodney Sparapani, Stephen Eglen and Vitalie Spinu.
-
-;; Author: David Smith <dsmithNOSPAMstats.adelaide.edu.au>
-;; Created: 7 Jan 1994
-;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
-
-;; 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:
-
-;; 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))))
- (inferior-ess-mode)))))
-
-\f ;;*;; 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.")
-
-(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))))
- (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))
- (cur-dir (inferior-ess--maybe-prompt-startup-directory proc-name temp-dialect))
- (default-directory cur-dir))
- (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 cur-dir)
- (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))
- (when ess-setwd-command
- (ess-set-working-directory cur-dir))
- (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 3): waiting for process after hook")
- (ess-wait-for-process proc)))
- 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)
- (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-<lang>-objects-command
-and then made buffer local."); and the *-<lang>-* 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."
- (let* ((buffer-undo-list t)
- (inhibit-point-motion-hooks 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)
- "Function to generate 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)
- "Function to generate 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.
-PROJECT-ROOT is directory name returned by `project-roots'. 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 (car (project-roots 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 `project-roots' 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 (car (project-roots 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 (and ess-local-process-name
- (get-process ess-local-process-name)))))
- (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 inferior-ess-mark-as-busy (proc)
- (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)
- (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 <--
- --> string:%s\n"
- (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)
- (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.
-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
- (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
-
-;; FIXME EMACS 25.1:
-;; Deprecate `ess-directory-function' in favor of `project-find-functions'?
-(defun inferior-ess--get-startup-directory ()
- (let ((dir (or (and ess--enable-experimental-projects
- (fboundp 'project-current)
- (cdr (project-current)))
- (and ess-directory-function
- (funcall ess-directory-function))
- ess-startup-directory
- 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 (if (fboundp 'inferior-ess-r--adjust-startup-directory)
- (inferior-ess-r--adjust-startup-directory
- (inferior-ess--get-startup-directory) dialect)
- (inferior-ess--get-startup-directory))))
- (if ess-ask-for-ess-directory
- (let ((prompt (format "%s starting project directory? " procname)))
- (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 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")))))
-
-(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))
- (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 ()
- (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-<ESSlang>-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'"
- (and (or proc ess-local-process-name)
- (let ((proc (or proc (get-process ess-local-process-name))))
- (and (processp proc)
- (process-live-p proc)))))
-
-(defun ess-process-get (propname &optional proc)
- "Return the variable PROPNAME (symbol) from the plist 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 plist of 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 LANGUAGE (and DIALECT)."
- (save-current-buffer
- (let ((dsymb (intern dialect)))
- (ess-write-to-dribble-buffer
- (format " ..start-process-specific: lang:dialect= %s:%s, current-buf=%s\n"
- language dialect (current-buffer)))
- (cond ;; ((string= dialect "R") (R))
- ;; ((string= language "S") ;
- ;; (message "ESS process not running, trying to start R, since language = 'S")
- ;; (R))
- ;; ((string= dialect STA-dialect-name) (stata))
- ;;general case
- ((fboundp dsymb)
- (funcall dsymb))
- (t ;; else: ess-dialect is not a function
-
- ;; Typically triggered from
- ;; ess-force-buffer-current("Process to load into: ")
- ;; \--> ess-request-a-process("Process to load into: " no-switch)
- (error "No ESS processes running; not yet implemented to start (%s,%s)"
- language dialect))))))
-
-(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."
- (interactive
- (list "Switch to which ESS process? " current-prefix-arg))
- ; prefix sets 'noswitch
- (ess-write-to-dribble-buffer "ess-request-a-process: {beginning}\n")
- (update-ess-process-name-list)
-
- (setq 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" "XLS" "ViSta")))))
-
- (let* ((pname-list (delq nil ;; keep only those matching dialect
- (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))
- (auto-started?))
- (if (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
- (progn
- (ess-write-to-dribble-buffer
- (concat " ... request-a-process:\n "
- (format
- "major mode %s; current buff: %s; ess-language: %s, ess-dialect: %s\n"
- major-mode (current-buffer) ess-language ess-dialect)))
- (ess-start-process-specific ess-language ess-dialect)
- (ess-write-to-dribble-buffer
- (format " ... request-a-process: buf=%s\n" (current-buffer)))
- (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))
- (proc
- (if (or auto-started?
- (and (not ask-if-1) (= 1 num-processes)))
- (progn
- (message "using process '%s'" (car proc-buffers))
- (car pname-list))
- ;; else
- (unless (and ess-current-process-name
- (get-process ess-current-process-name))
- (setq ess-current-process-name nil))
- (when message
- (setq message (replace-regexp-in-string ": +\\'" "" message))) ;; <- why is this here??
- ;; 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 (equal buf "*new*")
- (progn
- (ess-start-process-specific ess-language ess-dialect) ;; switches to proc-buff
- (caar ess-process-name-list))
- (process-name (get-buffer-process buf))
- ))
- )))
- (if noswitch
- (pop-to-buffer (current-buffer)) ;; VS: this is weird, but is necessary
- (pop-to-buffer (buffer-name (process-buffer (get-process proc)))))
- 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-next-available-process (&optional dialect ignore-busy)
- "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."
- (setq dialect (or dialect ess-dialect))
- (when dialect
- (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)))
- (or ignore-busy
- (inferior-ess-available-p proc)))
- (throw 'found proc))))))))
-
-
-;;*;;; 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))
- (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)))
-
-\f
-;;; 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."
- (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))))))
-
-(defun inferior-ess-ordinary-filter (proc string)
- (inferior-ess--set-status proc string)
- (ess--if-verbose-write-process-state proc string "ordinary-filter")
- (inferior-ess-run-callback proc string)
- (with-current-buffer (process-buffer proc)
- (insert string)))
-
-(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 distructs
- 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)))))
-
-\f
-;;*;; 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))
-
-\f
-;;*;; 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-check-modifications))
- (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)
-
-(defun ess-command (cmd &optional out-buffer _sleep no-prompt-check wait proc force-redisplay)
- "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.
-
-SLEEP is deprecated and no longer has any effect. WAIT and
-FORCE-REDISPLAY are as in `ess-wait-for-process' and are passed
-to `ess-wait-for-process'.
-
-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))
- ;; Set `inhibit-quit' to t to avoid dumping R output to the
- ;; process buffer if `ess-command' gets interrupted for some
- ;; reason. See bugs #794 and #842
- (inhibit-quit t))
- (with-current-buffer (process-buffer proc)
- (let ((primary-prompt inferior-ess-primary-prompt)
- (oldpb (process-buffer proc))
- (oldpf (process-filter proc))
- (oldpm (marker-position (process-mark proc))))
- (ess-if-verbose-write (format "(ess-command %s ..)" cmd))
- ;; Swap the process buffer with the output buffer before
- ;; sending the command
- (unwind-protect
- (progn
- (set-process-buffer proc out-buffer)
- (set-process-filter proc 'inferior-ess-ordinary-filter)
- (with-current-buffer out-buffer
- (setq inferior-ess-primary-prompt primary-prompt)
- (setq buffer-read-only nil)
- (erase-buffer)
- (set-marker (process-mark proc) (point-min))
- (inferior-ess-mark-as-busy proc)
- (process-send-string proc cmd)
- ;; Need time for ess-create-object-name-db on PC
- (if no-prompt-check
- (sleep-for 0.02) ; 0.1 is noticeable!
- (ess-wait-for-process proc nil wait force-redisplay)
- ;; Should (almost) never be incomplete unless the message
- ;; contains "> " and was accidentally split by the process
- ;; right there.
- (while (eq :incomplete (ess-mpi-handle-messages (current-buffer)))
- (ess-wait-for-process proc nil wait force-redisplay))
- ;; Remove prompt
- ;; If output is cat(..)ed this deletes the output
- (goto-char (point-max))
- (delete-region (point-at-bol) (point-max)))
- (ess-if-verbose-write " .. ok{ess-command}")))
- (ess-if-verbose-write " .. exiting{ess-command}\n")
- ;; Restore the process buffer in its previous state
- (set-process-buffer proc oldpb)
- (set-process-filter proc oldpf)
- (set-marker (process-mark proc) oldpm))))
- out-buffer))
-
-(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."
- (let ((prompt inferior-ess-prompt))
- (with-current-buffer (ess-command com buf nil nil wait)
- (goto-char (point-min))
- ;; remove leading prompt
- (when (and prompt (re-search-forward (concat "^" prompt) (point-at-eol) t))
- (delete-region (point-min) (match-end 0)))
- (ess-kill-last-line)
- (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.")
-
-\f
-;;*;; 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 go to end of 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."
- (unless (numberp wait-sec)
- (setq wait-sec 0.001))
- (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}
- (sprocess (ess-get-process ess-current-process-name))
- (sbuffer (process-buffer sprocess))
- (win (get-buffer-window sbuffer t)))
- (setq text (ess--concat-new-line-maybe
- (ess--run-presend-hooks sprocess text)))
- (with-current-buffer sbuffer
- (setq text (propertize text 'field 'input 'front-sticky t))
- (goto-char (marker-position (process-mark sprocess)))
- (if (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 sprocess)))
- (if win (set-window-point win (process-mark sprocess)))
- (unless invisibly
- ;; for consistency with comint :(
- (insert (propertize input 'font-lock-face 'comint-highlight-input))
- (set-marker (process-mark sprocess) (point)))
- (inferior-ess-mark-as-busy sprocess)
- (process-send-string sprocess input))
- (when (or (> (length text) 0)
- wait-last-prompt)
- (ess-wait-for-process sprocess t wait-sec)))
- (if eob (with-temp-buffer (buffer-name sbuffer)))
- (goto-char (marker-position (process-mark sprocess)))
- (when win
- (with-selected-window win
- (goto-char (point))
- ;; this is crucial to avoid resetting window-point
- (recenter (- -1 scroll-margin))))))
- (if (numberp sleep-sec)
- (sleep-for sleep-sec)))
-
-\f
-;;;*;;; 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))))
-
-(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."
- (ess-eval-region--normalise-region start end)
- (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) (point-at-eol)))))
- (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 (= (point-at-bol) (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 (point-at-bol))
- (end (point-at-eol))
- (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")
-
-\f
-;;;*;;; 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))
-
-\f ; 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))
-
-
-\f
-;;*;; 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) (point-at-eol)))
- (when inferior-ess-secondary-prompt
- (while (progn (forward-line 1)
- (looking-at inferior-ess-secondary-prompt))
- (re-search-forward inferior-ess-secondary-prompt (point-at-eol) t)
- (setq command (concat command "\n"
- (buffer-substring-no-properties (point) (point-at-eol))))))
- (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)))
-
-\f
-;;;*;;; 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 to the `ess-language' process.
-[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)
- (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)))))
-
-(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 ((integerp opt)
- (setq command (format ess-execute-screen-options-command opt)))
- ((eql 'window 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)))))
- (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))))))
-
-\f
-;;;*;;; Quitting
-
-(cl-defgeneric ess-quit--override (_arg)
- "Stops the inferior process"
- (let ((proc (ess-get-process)))
- (ess-cleanup)
- (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))
-
-(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)))
- ;; Interrupt current task before reloading. Useful if the process is
- ;; prompting for input, for instance in R in case of a crash
- (interrupt-process proc comint-ptyp)
- ;; Workaround for Windows terminals
- (unless (memq system-type '(gnu/linux darwin))
- (process-send-string nil "\n"))
- (ess-wait-for-process proc)
- ;; Quit debugging session before reloading
- (when (ess-debug-active-p)
- (ess-debug-command-quit)
- (ess-wait-for-process proc))))
-
-(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)
- (save-window-excursion
- ;; Make sure we don't ask for directory again
- ;; Use current working directory as default
- (let ((project-find-functions nil)
- (ess-directory-function nil)
- (ess-startup-directory (ess-get-working-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 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) 1)
- (error "Timeout while quitting process")))))
-
-\f
-;;;*;;; 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,
-using `ess-object-list' if that is non-nil.
-If exclude-first is non-nil, don't return objects in first positon (.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)
- "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, and PROC 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)
- (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-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)))))
- (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/objects in variable `ess-search-list' to form 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."
- (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.
- (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)))))))
-
-\f
-;;*;; 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))))
-
-\f
-;;; 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 `ess-handy-commands' list."
- (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 ",")))))
-
-\f ; 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))
- ;; use set instead of setq to take effect even when let bound
- (set '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")
- (setq default-directory
- (car (ess-get-words-from-vector ess-getwd-command)))
- 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"))))
- (message "(ESS / default) directory: %s" dir)
- (setq default-directory (file-name-as-directory dir))))
-
-;; 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)))))
-
-\f
-;;*;; 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 \f 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 "^\f" 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."
- ;; FIXME: this should really cycle through all top-level assignments in
- ;; the buffer
- ;;VS[02-04-2012|ESS 12.03]: this is sooo ugly
- (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)))
-
-\f
-;;*;; 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
+++ /dev/null
-;;; ess-jags-d.el --- ESS[JAGS] dialect -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2008-2011 Rodney Sparapani
-
-;; Author: Rodney Sparapani
-;; Created: 13 March 2008
-;; Maintainer: ESS-help <ess-helpNOSPAMr-project.org>
-
-;; 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/
-
-;;; 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 "\\<d\\(bern\\|beta\\|bin\\|cat\\|chisq\\|"
- "dexp\\|dirch\\|exp\\|\\(gen[.]\\)?gamma\\|hyper\\|"
- "interval\\|lnorm\\|logis\\|mnorm\\|mt\\|multi\\|"
- "negbin\\|norm\\(mix\\)?\\|par\\|pois\\|sum\\|t\\|"
- "unif\\|weib\\|wish\\)[ \t\n]*(")
- font-lock-constant-face)
-
- (cons (concat "\\<\\(abs\\|cos\\|dim\\|\\(i\\)?cloglog\\|equals\\|"
- "exp\\|for\\|inprod\\|interp[.]line\\|inverse\\|length\\|"
- "\\(i\\)?logit\\|logdet\\|logfact\\|loggam\\|max\\|mean\\|"
- "mexp\\|min\\|phi\\|pow\\|probit\\|prod\\|rank\\|round\\|"
- "sd\\|sin\\|sort\\|sqrt\\|step\\|sum\\|t\\|trunc\\|T\\)[ \t\n]*(")
- font-lock-function-name-face)
-
- ;; .jmd files
- (cons (concat "\\<\\(adapt\\|cd\\|clear\\|coda\\|data\\|dir\\|"
- "exit\\|in\\(itialize\\)?\\|load\\|model\\|monitors\\|parameters\\|"
- "pwd\\|run\\|s\\(amplers\\|ystem\\)\\|to\\|update\\)[ \t\n]")
- font-lock-keyword-face)
-
- (cons "\\<\\(compile\\|monitor\\)[, \t\n]"
- font-lock-keyword-face)
-
- (cons "[, \t\n]\\(by\\|chain\\|nchains\\|stem\\|thin\\|type\\)[ \t\n]*("
- font-lock-function-name-face)
- )
- "ESS[JAGS]: Font lock keywords."
- )
-
-(defun ess-jags-switch-to-suffix (suffix &optional jags-chains jags-monitor jags-thin
- jags-burnin jags-update)
- "ESS[JAGS]: Switch to file with suffix."
- (find-file (concat ess-bugs-file-dir ess-bugs-file-root suffix))
-
- (if (equal 0 (buffer-size)) (progn
- (if (equal ".jag" suffix) (progn
- (insert "var ;\n")
- (insert "model {\n")
- (insert " for (i in 1:N) {\n \n")
- (insert " }\n")
- (insert "}\n")
- (insert "#Local Variables" ":\n")
- (insert "#ess-jags-chains:1\n")
- (insert "#ess-jags-monitor:(\"\")\n")
- (insert "#ess-jags-thin:1\n")
- (insert "#ess-jags-burnin:10000\n")
- (insert "#ess-jags-update:10000\n")
- (insert "#End:\n")
- ))
-
- (if (equal ".jmd" suffix) (let
- ((ess-jags-temp-chains "") (ess-jags-temp-monitor "") (ess-jags-temp-chain ""))
-
- (if jags-chains (setq ess-jags-chains jags-chains))
- (if jags-monitor (setq ess-jags-monitor jags-monitor))
- (if jags-thin (setq ess-jags-thin jags-thin))
-
- (setq ess-jags-temp-chains
- (concat "compile, nchains(" (format "%d" ess-jags-chains) ")\n"))
-
- (setq jags-chains ess-jags-chains)
-
- (while (< 0 jags-chains)
- (setq ess-jags-temp-chains
- (concat ess-jags-temp-chains
- "parameters ## \"" ess-bugs-file-root
- ".##" (format "%d" jags-chains) "\", chain("
- (format "%d" jags-chains) ")\n"))
- (setq jags-chains (- jags-chains 1)))
-
- (setq ess-jags-temp-monitor "")
-
- (while (and (listp ess-jags-monitor) (consp ess-jags-monitor))
- (if (not (string-equal "" (car ess-jags-monitor)))
- (setq ess-jags-temp-monitor
- (concat ess-jags-temp-monitor "monitor "
- (car ess-jags-monitor) ", thin(" (format "%d" ess-jags-thin) ")\n")))
- (setq ess-jags-monitor (cdr ess-jags-monitor)))
-
- (insert "model in \"" ess-bugs-file-root ".jag\"\n")
- (insert "data in \"" ess-bugs-file-root ".jdt\"\n")
- (insert (ess-replace-in-string ess-jags-temp-chains "##" "in"))
- (insert "initialize\n")
- ;(insert "update " (format "%d" (* jags-thin jags-burnin)) "\n")
- (insert "update " (format "%d" jags-burnin) "\n")
- (insert ess-jags-temp-monitor)
- (insert "update " (format "%d" (* jags-thin jags-update)) "\n")
- (insert (ess-replace-in-string
- (ess-replace-in-string ess-jags-temp-chains
- "compile, nchains([0-9]+)" "#") "##" "to"))
- (insert "coda "
- ;(if ess-microsoft-p (if (w32-shell-dos-semantics) "*" "\\*") "\\*")
- "*, stem(\"" ess-bugs-file-root "\")\n")
-
- (if ess-jags-system (progn
- (insert "system rm -f " ess-bugs-file-root ".ind\n")
- (insert "system ln -s " ess-bugs-file-root "index.txt " ess-bugs-file-root ".ind\n")
-
- (setq jags-chains ess-jags-chains)
-
- (while (< 0 jags-chains)
- (setq ess-jags-temp-chain (format "%d" jags-chains))
-
- ;.txt not recognized by BOA and impractical to over-ride
- (insert "system rm -f " ess-bugs-file-root ess-jags-temp-chain ".out\n")
- (insert "system ln -s " ess-bugs-file-root "chain" ess-jags-temp-chain ".txt "
- ess-bugs-file-root ess-jags-temp-chain ".out\n")
- (setq jags-chains (- jags-chains 1)))))
-
- (insert "exit\n")
- (insert "Local Variables" ":\n")
- (insert "ess-jags-chains:" (format "%d" ess-jags-chains) "\n")
- (insert "ess-jags-command:\"jags\"\n")
- (insert "End:\n")
- ))
- ))
- )
-
-(defun ess-jags-na-jmd (jags-command)
- "ESS[JAGS]: Perform the Next-Action for .jmd."
- ;(ess-save-and-set-local-variables)
- (if (equal 0 (buffer-size)) (ess-jags-switch-to-suffix ".jmd")
- ;else
- (shell)
- (ess-sleep)
-
- (if (when (fboundp 'w32-shell-dos-semantics)
- (w32-shell-dos-semantics))
- (if (string-equal ":" (substring ess-bugs-file 1 2))
- (progn
- (insert (substring ess-bugs-file 0 2))
- (comint-send-input)
- )
- )
- )
-
- (insert "cd \"" ess-bugs-file-dir "\"")
- (comint-send-input)
-
- ; (let ((ess-jags-temp-chains ""))
- ;
- ; (while (< 0 jags-chains)
- ; (setq ess-jags-temp-chains
- ; (concat (format "%d " jags-chains) ess-jags-temp-chains))
- ; (setq jags-chains (- jags-chains 1)))
-
- (insert ess-bugs-batch-pre-command " " jags-command " "
- ess-bugs-file-root ".jmd "
-
- (if (or (equal shell-file-name "/bin/csh")
- (equal shell-file-name "/bin/tcsh")
- (equal shell-file-name "/bin/zsh")
- (equal shell-file-name "/bin/bash"))
- (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
+++ /dev/null
-;; ess-julia.el --- ESS julia mode and inferior interaction -*- lexical-binding: t; -*-
-;;
-;; Copyright (C) 2012-2015 Vitalie Spinu and the ESS Core team.
-;;
-;; Author: Vitalie Spinu
-;; Maintainer: Vitalie Spinu
-;; Created: 02-04-2012 (ESS 12.03)
-;; Keywords: ESS, julia
-;;
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;; 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:
-;;
-;; 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)
-(require 'julia-mode)
-
-(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))))
-
-\f
-;;; HELP
-(cl-defmethod ess-help-get-topics (proc &context (ess-dialect "julia"))
- (append (with-current-buffer (ess-command "ESS.all_help_topics()\n")
- (split-string (buffer-string) "\n"))
- (ess-julia--get-objects proc)))
-
-(defun ess-julia--retrive-topics (url)
- (with-current-buffer (url-retrieve-synchronously url)
- (require 'url)
- (goto-char (point-min))
- (let (out)
- (while (re-search-forward
- "toctext[ \"]+href=\"\\([^>]+\\)\">\\([^<]+\\)</a" nil t)
- (push (propertize (match-string 2)
- :manual (concat url (match-string 1)))
- out))
- (kill-buffer)
- (nreverse out))))
-
-(defvar ess-julia--manual-topics nil)
-(cl-defmethod ess--manual-lookup-override (&context (ess-dialect "julia"))
- "Look up topics at https://docs.julialang.org/en/latest/manual/."
- (let* ((pages (or ess-julia--manual-topics
- (setq ess-julia--manual-topics
- (ess-julia--retrive-topics
- "https://docs.julialang.org/en/latest/"))))
- (page (ess-completing-read "Lookup:" pages nil t)))
- (browse-url (get-text-property 1 :manual page))))
-
-(defun ess-julia-input-sender (proc string)
- "Function to send PROC STRING submitted by user.
-See `comint-input-sender'."
- (save-current-buffer
- (let* ((help-?-regexp "^ *\\(?:\\(?1: *?\\? *\\)\\(?2:.+\\)\\)")
- (help-?-match (string-match help-?-regexp string)))
- (cond (help-?-match
- (ess-display-help-on-object (match-string 2 string))
- (process-send-string proc "\n"))
- (t ;; normal command
- (inferior-ess-input-sender proc string))))))
-
-(cl-defmethod ess-installed-packages (&context (ess-dialect "julia"))
- "Return list of installed julia packages."
- ;; FIXME: This doesn't work if the user hasn't done "using Pkg" yet
- (ess-get-words-from-vector "keys(Pkg.installed())\n"))
-
-(cl-defmethod ess-load-library--override (pack &context (ess-dialect "julia"))
- (ess-eval-linewise (format "using %s\n" pack)))
-
-\f
-;;; COMPLETION
-(defun ess-julia-latexsub-completion ()
- "Complete latex input, and return format required by `completion-at-point-functions'."
- (if (julia-latexsub) ; julia-latexsub returns nil if it performed a completion, the point otherwise
- nil
- (lambda () t) ;; bypass other completion methods
- ))
-
-(defun ess-julia-object-completion ()
- "Return completions at point in a format required by `completion-at-point-functions'."
- (let ((proc (ess-get-next-available-process ess-dialect t))
- (beg (ess-symbol-start)))
- (if proc
- (when beg
- (let* ((prefix (buffer-substring-no-properties beg (point)))
- (obj (and (string-match "\\(.*\\)\\..*$" prefix)
- (match-string 1 prefix)))
- (beg (if obj
- (+ beg 1 (length obj))
- beg)))
- (list beg (point)
- (nreverse (mapcar 'car (ess-julia--get-objects proc obj)))
- :exclusive 'no)))
- (when (string-match "complet" (symbol-name last-command))
- (message "No ESS process of dialect %s started" ess-dialect)
- nil))))
-
-(defun ess-julia-objects (prefix &optional proc)
- "Given PREFIX get all cached objects from PROC."
- (when prefix
- (let ((proc (or proc (ess-get-next-available-process nil t))))
- (if (string-match "\\(.*\\)\\..*$" prefix)
- (let ((module (match-string 1 prefix)))
- (mapcar (lambda (el) (concat module "." (car el)))
- (ess-julia--get-objects proc module)))
- (ess-julia--get-objects proc)))))
-
-(defun ess-julia--get-objects (&optional proc obj)
- "Return all available objects.
-Local caching might be used. If MODULE is givven, return only
-objects from that MODULE."
- (setq proc (or proc (ess-get-process)))
- (when (stringp proc)
- (setq proc (get-process proc)))
- (when (process-live-p proc)
- (let ((objects (process-get proc 'objects)))
- (if (process-get proc 'busy)
- (if obj
- (assoc obj objects)
- (process-get proc 'objects))
- (if obj
- (or (cdr (assoc obj objects))
- ;; don't cache composite objects and datatypes
- (ess-julia--get-components proc obj))
- ;; this segment is entered when user completon at top level is
- ;; requested, either Tab or AC. Hence Main is always updated.
- (let ((modules (ess-get-words-from-vector
- "ESS.main_modules()\n" nil nil proc))
- (loc (process-get proc 'last-objects-cache))
- (lev (process-get proc 'last-eval)))
- (prog1
- (apply #'nconc
- (mapcar
- (lambda (mod)
- ;; we are caching all modules, and reinit Main every
- ;; time user enters commands
- (copy-sequence
- (or (and (or (not (equal mod "Main"))
- (ignore-errors (time-less-p lev loc)))
- (cdr (assoc mod objects)))
- (ess-julia--get-components proc mod t))))
- modules))
- (process-put proc 'last-objects-cache (current-time)))))))))
-
-(defun ess-julia--get-components (proc obj &optional cache?)
- (with-current-buffer (ess-command (format "ESS.components(%s)\n" obj)
- nil nil nil nil proc)
- (goto-char (point-min))
- (let (list)
- (while (re-search-forward
- "^\\([^ \t\n]+\\) +\\([^ \t\n]+\\)$" nil t)
- (push (cons (match-string 1) (match-string 2)) list))
- (when cache?
- (let ((objects (process-get proc 'objects)))
- (push (cons obj list) objects)
- (process-put proc 'objects objects)))
- list)))
-
-(defun ess-julia-get-object-help-string (sym)
- "Help string for ac."
- (let ((proc (ess-get-next-available-process nil t)))
- (if (null proc)
- "No free ESS process found"
- (let ((buf (get-buffer-create " *ess-command-output*")))
- (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))))))
-
-(defvar ac-source-ess-julia-objects
- '((prefix . ess-symbol-start)
- (requires . 2)
- (candidates . ess-ac-julia-objects)
- (document . ess-julia-get-object-help-string))
- "Auto-completion source for julia objects.")
-
-(defun ess-ac-julia-objects ()
- (require 'auto-complete)
- (ess-julia-objects ac-prefix))
-
-(declare-function company-begin-backend "company.el")
-
-(defun company-ess-julia-objects (command &optional arg &rest ignored)
- (interactive (list 'interactive))
- (cl-case command
- (interactive (company-begin-backend 'company-ess-julia-objects))
- (prefix (unless (company-in-string-or-comment)
- (let ((start (ess-symbol-start)))
- (when start (buffer-substring-no-properties start (point))))))
- (candidates (let ((proc (ess-get-next-available-process)))
- (when proc
- (all-completions arg (mapcar (lambda (x) (or (car-safe x) x))
- (ess-julia-objects arg proc))))))
- (doc-buffer (company-doc-buffer (ess-julia-get-object-help-string arg)))))
-
-\f
-;;; ERRORS
-(defvar ess-julia-error-regexp-alist '(ess-julia-in ess-julia-at ess-julia-while-load)
- "List of symbols which are looked up in `compilation-error-regexp-alist-alist'.")
-
-(add-to-list 'compilation-error-regexp-alist-alist
- '(ess-julia-in "^\\s-*in [^ \t\n]* \\(at \\(.*\\):\\([0-9]+\\)\\)" 2 3 nil 2 1))
-(add-to-list 'compilation-error-regexp-alist-alist
- '(ess-julia-at "^\\S-+\\s-+\\(at \\(.*\\):\\([0-9]+\\)\\)" 2 3 nil 2 1))
-(add-to-list 'compilation-error-regexp-alist-alist
- '(ess-julia-while-load "^\\s-*\\(while loading\\s-\\(.*\\), in .* on line +\\([0-9]+\\)\\)" 2 3 nil 2 1))
-
-\f
-;;; ELDOC
-(defun ess-julia-eldoc-function ()
- "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 (and ess-can-eval-in-background
- (ess-process-live-p)
- (not (ess-process-get 'busy)))
- (let ((funname (or (and ess-eldoc-show-on-symbol ;; aggressive completion
- (symbol-name (ess-symbol-at-point)))
- (car (ess--fn-name-start)))))
- (when funname
- (let* ((args (copy-sequence (nth 2 (ess-function-arguments funname))))
- (W (- (window-width (minibuffer-window)) (+ 4 (length funname))))
- (doc (concat (propertize funname 'face font-lock-function-name-face) ": ")))
- (when args
- (setq args (sort args (lambda (s1 s2)
- (< (length s1) (length s2)))))
- (setq doc (concat doc (pop args)))
- (while (and args (< (+ (length doc) (length (car args))) W))
- (setq doc (concat doc " "
- (pop args))))
- (when (and args (< (length doc) W))
- (setq doc (concat doc " {--}")))
- doc))))))
-
-\f
-;;; CORE
-(defvar ess-julia-customize-alist
- '((inferior-ess-primary-prompt . "\\w*> ")
- (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
- (add-function :before-until (local 'eldoc-documentation-function)
- #'ess-julia-eldoc-function)
- (when ess-use-eldoc (eldoc-mode))
- ;; 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
- (add-function :before-until (local 'eldoc-documentation-function)
- #'ess-julia-eldoc-function)
- (when ess-use-eldoc (eldoc-mode))
- ;; 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=<file>. 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
+++ /dev/null
-;;; ess-mode.el -- Emacs Speaks Statistics root mode. -*- lexical-binding: t; -*-
-;;
-;; Copyright (C) 1994-2018 ESS Core Team
-;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
-;;
-;; Keywords: languages
-;;
-;; 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:
-;;
-;;; Code:
-
-(require 'ess)
-
-(eval-when-compile
- (require 'cl-lib)
- (require 'subr-x))
-(require 'ess-inf)
-
-;; Silence the byte compiler
-(declare-function run-ess-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-<up>") #'ess-eval-buffer-from-beg-to-here)
- (define-key map (kbd "C-c C-<down>") #'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 substituted commands
-(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-exisiting" 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 <tabs> out of the code.
- (setq-local indent-tabs-mode nil)
-
- (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 'eval ess--mode-line-process-indicator))
- "none"))
- "none"))
-
-\f
-;;; 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")
-
-(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))))
-
-\f
-;;; 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))
-
-\f
-;;; 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))))
-
-\f
-;;; 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)
- (run-ess-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
+++ /dev/null
-(define-package "ess" "20191014.1343" "Emacs Speaks Statistics"
- '((emacs "25.1")
- (julia-mode "0.3"))
- :authors
- '(("David Smith" . "dsmithNOSPAMstats.adelaide.edu.au")
- ("A.J. Rossini" . "blindglobeNOSPAMgmail.com")
- ("Richard M. Heiberger" . "rmhNOSPAMtemple.edu")
- ("Kurt Hornik" . "Kurt.HornikNOSPAMR-project.org")
- ("Martin Maechler" . "maechlerNOSPAMstat.math.ethz.ch")
- ("Rodney A. Sparapani" . "rsparapaNOSPAMmcw.edu")
- ("Stephen Eglen" . "stephenNOSPAMgnu.org")
- ("Sebastian P. Luque" . "spluqueNOSPAMgmail.com")
- ("Henning Redestig" . "henning.redNOSPAMgooglemail.com")
- ("Vitalie Spinu" . "spinuvitNOSPAMgmail.com")
- ("Lionel Henry" . "lionel.hryNOSPAMgmail.com")
- ("J. Alexander Branham" . "alex.branhamNOSPAMgmail.com"))
- :maintainer
- '("ESS Core Team" . "ESS-coreNOSPAMr-project.org")
- :url "https://ess.r-project.org/")
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
+++ /dev/null
-;;; ess-r-completion.el --- R completion -*- lexical-binding: t; -*-
-;;
-;; Copyright (C) 2015 A.J. Rossini, Richard M. Heiberger, Martin Maechler, Kurt
-;; Hornik, Rodney Sparapani, Stephen Eglen and Vitalie Spinu.
-;;
-;; Author: Vitalie Spinu
-;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
-;;
-;; Keywords: languages, statistics
-;;
-;; 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:
-;;
-;;; Code:
-
-\f
-;;; ElDoc
-
-(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)
-
-(defun ess-r-eldoc-function ()
- "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 (and eldoc-mode ess-can-eval-in-background)
- (let* ((proc (ess-get-next-available-process))
- (funname (and proc (or (and ess-eldoc-show-on-symbol ;; Aggressive completion
- (thing-at-point 'symbol))
- (car (ess--fn-name-start))))))
- (when funname
- (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))))
- doc1)
- (when doc
- (setq doc (ess-eldoc-docstring-format funname doc))
- (when (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)
- (save-match-data
- (let* (;; (name (symbol-name sym))
- (truncate (or (not (eq t eldoc-echo-area-use-multiline-p))
- (eq ess-eldoc-abbreviation-style 'aggressive)))
- ;; 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))))
-
-\f
-;;; OBJECTS
-
-(defun ess-r-object-completion ()
- "Return completions at point in a format required by `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)))))
-
-\f
-;;; 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.")
-
-\f
-;;; HELP
-
-(defun ess-r-get-object-help-string (sym)
- "Help string for ac."
- (let ((proc (ess-get-next-available-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 (or proc (ess-get-next-available-process))))
- (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)))))))
-
-\f
-;;; 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 (let ((proc (ess-get-next-available-process)))
- (when proc
- (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 (let* ((proc (ess-get-next-available-process))
- (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)))
- (meta (let ((proc (ess-get-next-available-process)))
- (when (and proc
- (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 (all-completions arg (ess-installed-packages)))
- (annotation "<pkg>")
- (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 (member (car (ess--fn-name-start))
- '("library" "require"))
- (list (ess-symbol-start)
- (point)
- (ess-installed-packages)
- :annotation-function
- (lambda (_) " <pkg>"))))
-
-\f
-;;; 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
+++ /dev/null
-;;; ess-r-flymake.el --- A ess-r Flymake backend -*- lexical-binding: t; -*-
-;;
-;; Copyright (C) 2018 J. Alexander Branham (alex DOT branham AT gmail DOT com)
-;; Copyright (C) 2018 ESS-core team
-;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
-;;
-;; This file is NOT part of GNU Emacs.
-;;
-;; This 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 is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-;; for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
-;; MA 02110-1301 USA.
-;;
-;;; 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.
-;;
-;; It is enabled by default.
-;;
-;;; 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")
-
-(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 user's home directory. Return nil if we couldn't find a .lintr file."
- (let ((cur-dir-file (expand-file-name ".lintr" default-directory))
- (ess-proj-file (and (fboundp 'ess-r-package-project)
- (ess-r-package-project)
- (expand-file-name ".lintr" (cdr (ess-r-package-project)))))
- (proj-file (and (project-current)
- (project-roots (project-current))
- (expand-file-name ".lintr" (car (project-roots (project-current))))))
- (home-file (expand-file-name ".lintr" (getenv "HOME"))))
- (cond (;; current directory
- (file-readable-p cur-dir-file)
- cur-dir-file)
- ;; Project root according to `ess-r-package-project'
- ((and ess-proj-file
- (file-readable-p ess-proj-file))
- ess-proj-file)
- ;; Project root according to `project-roots'
- ((and proj-file
- (file-readable-p proj-file)))
- ;; Home directory
- ((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 "<text>:"
- ;; 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
+++ /dev/null
-;;; ess-r-mode.el --- R customization
-
-;; Copyright (C) 1997--2010 A.J. Rossini, Richard M. Heiberger, Martin
-;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
-;; Copyright (C) 2011--2017 A.J. Rossini, Richard M. Heiberger, Martin Maechler,
-;; Kurt Hornik, Rodney Sparapani, Stephen Eglen and Vitalie Spinu.
-
-;; Author: A.J. Rossini
-;; Created: 12 Jun 1997
-;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
-
-;; Keywords: languages, statistics
-
-;; 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 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" ())
-
-(define-obsolete-variable-alias 'R-mode-hook 'ess-r-mode-hook "19.04")
-(defcustom ess-r-mode-hook nil
- "Hook run when entering `ess-r-mode'."
- :options '(electric-layout-local-mode)
- :type 'hook
- :group 'ess-R)
-
-
-(defcustom ess-r-fetch-ESSR-on-remotes nil
- "If non-nil, fetch ESSR from the GitHub repository.
-Otherwise source from local ESS installation. When 'ess-remote,
-fetch only with `ess-remote'. When t, always fetch from remotes.
-Change this variable when loading ESSR code on remotes fails
-systematically.
-
-Fetching happens once per new ESSR version. The archive is stored
-in ~/.config/ESSR/ folder. 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 block)
-(defvar containing-sexp)
-(defvar indent-point)
-(defvar infinite)
-(defvar last-newline)
-(defvar last-pos)
-(defvar offset)
-(defvar prefix-break)
-(defvar prev-containing-sexp)
-(defvar start-pos)
-(defvar style)
-(defvar type)
-
-(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-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
- :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)
-
-
-\f
-;;*;; 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 "\ 4" #'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 "\ 2" #'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)
- 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.")
-
-(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
- 'default)))
- ((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) ?`)
- 'default)
- (t
- 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")
-
-(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-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 style (stl_numeric.h:183)
- (R1 "(\\([^ ):\n]+\\):\\([0-9]+\\)?)" 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-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")
-(defvar ess-r-post-run-hook nil
- "Functions run in process buffer after the initialization of R process.")
-
-;;;###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)
- (and ess-startup-directory
- (file-remote-p 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-wait-for-process)
- (R-initialize-on-start)
- (comint-goto-process-mark))
- (ess-write-to-dribble-buffer
- (format "(R): inferior-ess-language-start=%s\n"
- inferior-ess-language-start)))
- ;; FIXME: Current ob-R expects current buffer set to process buffer
- (set-buffer inf-buf))))
-
-;;;###autoload
-(defalias 'R #'run-ess-r)
-
-(defun inferior-ess-r--adjust-startup-directory (dir dialect)
- "Adjust startup directory DIR if DIALECT is R.
-If in a package project, prefer the tests directory but only if
-the package directory was selected in the first place."
- (if (string= dialect "R")
- (let* ((project-dir (cdr (ess-r-package-project)))
- (tests-dir (expand-file-name (file-name-as-directory "tests")
- project-dir)))
- (if (and project-dir
- (string= project-dir dir)
- (string= default-directory tests-dir))
- tests-dir
- dir))
- dir))
-
-(defun inferior-ess-r--init-callback (_proc _name)
- (R-initialize-on-start))
-
-(defun R-initialize-on-start ()
- "This function is run after the first R prompt.
-Executed in process buffer."
- (ess-command (format
- "if(identical(getOption('pager'),
- file.path(R.home(), 'bin', 'pager')))
- options(pager='%s')\n"
- inferior-ess-pager))
- (ess-r-load-ESSR)
- (when inferior-ess-language-start
- (ess-command (concat inferior-ess-language-start "\n")))
- ;; tracebug
- (when ess-use-tracebug (ess-tracebug 1))
- (add-hook 'ess-presend-filter-functions 'ess-R-scan-for-library-call nil 'local)
- (run-hooks 'ess-r-post-run-hook))
-
-(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
- (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 electric-layout-rules '((?{ . after)))
- ;; indentation
- (add-hook 'hack-local-variables-hook #'ess-set-style nil t)
- ;; eldoc
- (add-function :before-until (local 'eldoc-documentation-function)
- #'ess-r-eldoc-function)
- (when ess-use-eldoc (eldoc-mode))
- ;; 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)
-
- (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))
-
-\f
-;;*;; 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\" will return \"R-x.y.z-32bit\", for R-2.12.x and newer.
-\"R-x.y.z/bin/x64/Rterm.exe\" will 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)))
-
-(defalias 'R-newest 'run-ess-r-newest)
-
-;; (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 "as.character(.ess.Rversion)\n")))
-
-(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 "as.character(.ess.Rversion >= \"%s\")\n" 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))))
-
-(cl-defmethod ess-font-lock-keywords (&context (major-mode ess-r-transcript-mode))
- 'ess-R-font-lock-keywords)
-
-;;;###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") (?' . ".")))))
-
-(fset '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 "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 "print(.packages(T), 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"))
-
-\f
-;;*;; 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)))
-
-(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 (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 (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."
- (or ess-r-evaluation-env
- (and ess-current-process-name
- (ess-get-process-variable '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)))
- ;; fixme: does not work if env is set at process level
- (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
-
-(defun ess-r-namespaced-object-p (object)
- (string-match "^[[:alnum:].]+::" object))
-
-(defun ess-r-build-help-command--qualified (object)
- (when (ess-r-namespaced-object-p object)
- (let* ((pkg-name (substring object (match-beginning 0) (- (match-end 0) 2)))
- (object (concat "'" (substring object (match-end 0)) "'"))
- (pkg (ess-r-arg "package" pkg-name t)))
- (concat ".ess.help(" object pkg ")\n"))))
-
-(defun ess-r-build-help-command--get-package-dir (object)
- ;; Ugly hack to avoid tcl/tk dialogues
- (let ((pkgs (ess-get-words-from-vector
- (format "as.character(utils::help('%s'))\n" object))))
- (when (> (length pkgs) 1)
- (ess-completing-read "Choose location" pkgs nil t))))
-
-(defun ess-r-build-help-command--unqualified (object)
- (if (eq ess-help-type 'index)
- ;; we are in index page, qualify with namespace
- (ess-r-build-help-command--qualified (format "%s::%s" ess-help-object object))
- (let ((pkg-dir (ess-r-build-help-command--get-package-dir object))
- (command (format inferior-ess-r-help-command object)))
- (if pkg-dir
- ;; Invoking `print.help_files_with_topic'
- (format "do.call(structure, c('%s', attributes(%s)))\n" pkg-dir command)
- command))))
-
-(cl-defmethod ess-build-help-command (object &context (ess-dialect "R"))
- (or (ess-r-build-help-command--qualified object)
- (ess-r-build-help-command--unqualified object)))
-
-(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))
- 'appropos))
- ((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."
- (cond
- ((file-remote-p (ess-get-process-variable 'default-directory))
- (if (eq ess-r-fetch-ESSR-on-remotes t)
- (ess-r--fetch-ESSR-remote)
- (ess-r--load-ESSR-remote)))
- ((and (bound-and-true-p ess-remote))
- (if ess-r-fetch-ESSR-on-remotes
- (ess-r--fetch-ESSR-remote)
- (ess-r--load-ESSR-remote t)))
- (t (ess-r--load-ESSR-local))))
-
-(defun ess-r--load-ESSR-local ()
- (let* ((src-dir (expand-file-name "ESSR/R" ess-etc-directory))
- (cmd (format "local({
- source('%s/.load.R', local=TRUE) #define load.ESSR
- .ess.load.ESSR('%s')
- })\n"
- src-dir src-dir)))
- (with-current-buffer (ess-command cmd)
- (let ((msg (buffer-string)))
- (when (> (length msg) 1)
- (message (format "Messages while loading ESSR: %s" msg)))))))
-
-(defun ess-r--load-ESSR-remote (&optional chunked)
- (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)))))
-
-(defun ess-r--fetch-ESSR-remote ()
- (let ((loader (ess-file-content (expand-file-name "ESSR/LOADREMOTE" ess-etc-directory))))
- (unless (ess-boolean-command (format loader essr-version) nil 0.1)
- (let* ((errmsg (with-current-buffer " *ess-command-output*" (buffer-string)))
- (src-dir (expand-file-name "ESSR/R" ess-etc-directory))
- (files (directory-files src-dir t "\\.R$")))
- (message (format "Couldn't load ESSR.rds. Injecting from local.\n Error: %s\n" errmsg))
- (ess-r--load-ESSR-remote)))))
-
-(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 t)))
-
-(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))
-
-\f
-;;*;; 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 (eval (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 (eval (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))
- ;; Indent from previous line indentation
- ((eq type 'prev-line)
- (ess-calculate-indent--args-prev-line))
- (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 ()
- ;; 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 ()
- (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))
- (current-indentation))
- ;; Function blocks need special treatment
- ((and (eq type 'prev-line)
- (eq block 'fun-decl))
- (goto-char containing-sexp)
- (ess-climb-block-prefix)
- (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.
- (when (and block
- containing-sexp
- (not (eq block 'unbraced))
- (save-excursion
- (/= (line-number-at-pos)
- (progn (goto-char containing-sexp)
- (line-number-at-pos)))))
- (setq offset 0))
- (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))
- prefix-break)
- (goto-char (car bounds))
- (goto-char (ess-code-end-position))
- (while (and (/= (point) last-pos)
- (< (line-end-position)
- (cadr bounds))
- (not prefix-break))
- (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)
-
-(defun ess-fill-args (&optional style)
- (let ((start-pos (point-min))
- (bounds (ess-args-bounds 'marker))
- ;; Set undo boundaries manually
- (undo-inhibit-record-point t)
- last-pos last-newline prefix-break
- 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)
- ;; 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 ()
- (while (and (not (looking-at "[])]"))
- (/= (point) (or last-pos 1))
- (not infinite))
- (setq prefix-break nil)
- ;; Record start-pos as future breaking point to avoid breaking
- ;; at `=' sign
- (while (looking-at "[ \t]*[\n#]")
- (forward-line)
- (back-to-indentation))
- (setq start-pos (point))
- (while (and (< (current-column) fill-column)
- (not (looking-at "[])]"))
- (/= (point) (or last-pos 1))
- ;; Break after one pass if prefix is active
- (not prefix-break))
- (when (memq style '(2 3))
- (setq prefix-break t))
- (ess-jump-token ",")
- (setq 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 last-newline nil))
- ((ess-token-after= ",")
- (setq last-newline nil)
- (setq 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)
- prefix-break
- ;; Ensures closing delim on a newline
- (and (= style 4)
- (looking-at "[ \t]*[])]")
- (setq last-pos (point))))
- (if (and last-pos (/= last-pos start-pos))
- (goto-char last-pos)
- (ess-jump-char ","))
- (cond ((looking-at "[ \t]*[#\n]")
- (forward-line)
- (funcall indent-line-function)
- (setq 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 last-newline))
- (newline-and-indent)
- ;; Prevent indenting infinitely
- (setq last-newline t)))
- ((not last-newline)
- (newline-and-indent)
- (setq last-newline t))
- (t
- (setq 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))))
-
-\f
-
-;;;*;;; 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 comint-process-echoes (eql ess-eval-visibly t))
- (setq-local comint-prompt-regexp inferior-S-prompt)
- (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)
- ;; eldoc
- (add-function :before-until (local 'eldoc-documentation-function)
- #'ess-r-eldoc-function)
- (when ess-use-eldoc (eldoc-mode))
- ;; 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))
-
-\f
-
-;;;*;;; 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))
-
-(defun ess-r-help-usage-objects ()
- "Return a list of objects in the usage section for the current help buffer.
-In other words, if in the help buffer for \"qt\", return
-
-'((\"dt\" \"x\" \"df\" \"ncp\" \"log\")
- (\"pt\" \"q\" \"df\" \"ncp\" \"lower.tail\" \"log.p\")
- (\"qt\" \"p\" \"df\" \"ncp\" \"lower.tail\" \"log.p\")
- (\"rt\" \"n\" \"df\" \"ncp\")).
-
-If the current buffer does not have a usage section, return nil."
- (unless (derived-mode-p 'ess-r-help-mode)
- (error "Not an R help buffer"))
- (save-excursion
- (save-restriction
- (let (usage-objects)
- (widen)
- (goto-char (point-min))
- ;; Narrow the buffer to just the "Usage" section
- (when-let ((usage-beg (re-search-forward "^Usage:" nil t))
- (usage-end (re-search-forward "^[^[:space:]]" nil t)))
- (forward-line -1)
- (narrow-to-region usage-beg (point))
- (goto-char (point-min))
- ;; Match objects until a parens
- (while (re-search-forward (rx bol (0+ whitespace) (not (syntax comment-delimiter))
- (group (1+ (not (any "(")))))
- usage-end t)
- (push (match-string-no-properties 1) usage-objects)
- ;; Skip past function arguments
- (forward-list)))
- (when usage-objects
- ;; Get arguments:
- (setq usage-objects
- (mapcar (lambda (u) (cons u (ess-get-words-from-vector (concat "names(formals(" u "))\n"))))
- usage-objects)))
- (nreverse usage-objects)))))
-
-(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 ((help-topics (when (ess-process-live-p)
- (ess-help-get-topics ess-local-process-name)))
- (inhibit-read-only t)
- (usage-objects (ess-flatten-list (ess-r-help-usage-objects))))
- (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 (if (string-match-p ".*()\\'" text)
- (substring text nil (- (length text) 2))
- text)))
- (when (and (member text help-topics)
- (not (member text usage-objects))
- (not (member text usage-objects)))
- (delete-region (match-beginning 0) (match-end 0))
- (insert-text-button text
- 'ess-r-help-link-text text
- '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)))))))
- (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))
- (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 "Pdf"
- '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 "Rnw"
- '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)))
-
-\f
-
-;; 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 "o" #'ess-rdired)
- (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+ (point-at-eol)))
- ;; 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 (point-at-eol))
- ;; 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 (concat ".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-wkspc (file)
- "Load workspace FILE into R."
- (interactive "fFile with workspace to load: ")
- (ess-execute (concat "load('" file "')") 'buffer))
-
-(defun ess-rutils-save-wkspc (file)
- "Save FILE workspace as file.RData."
- (interactive "FSave workspace to file (no extension): ")
- (ess-execute (concat "save.image('" file ".RData')") 'buffer))
-
-(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)))
- (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:decending" 5)
- ("field:from:ascending" 6) ("field:from:decending" 7)
- ("field:size:ascending" 8) ("field:size:decending" 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="))))
- (browse-url (concat site okstring mpp format sortby restrict)))
- (browse-url (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)
-
-;;; Local variables:
-;;; mode: emacs-lisp
-;;; byte-compile-warnings: (not lexical)
-;;; End:
-
-;;; ess-r-mode.el ends here
+++ /dev/null
-;;; ess-r-package.el --- Package development mode for R. -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2011-2015 Lionel Henry, Vitalie Spinu, A.J. Rossini, Richard
-;; M. Heiberger, Martin Maechler, Kurt Hornik, Rodney Sparapani, and
-;; Stephen Eglen.
-
-;; Author: Lionel Henry, Vitalie Spinu
-;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
-
-;; Keywords: languages, tools
-
-;; 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:
-
-;; 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 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.")
-
-(define-obsolete-variable-alias 'ess-r-package-library-path 'ess-r-package-library-paths "v18.04")
-(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."
- :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.")
-
-\f
-;;;*;;; 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)))))
-
-(cl-defmethod project-roots ((project (head ess-r-package)))
- "Return the project root for ESS R packages"
- (list (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)))
- (info (if name
- (list :name name
- :root path)
- '(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'. If the path looks like a tramp file,
-remove the remote information."
- (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)))))
- (if (file-remote-p pkg-path)
- (tramp-file-name-localname (tramp-dissect-file-name pkg-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))))))
-
-\f
-;;;*;;; 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"))))
-
-\f
-;;;*;;; 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 (error "Invalid action")))))
- (if (string= "" args)
- args
- (concat ", " args))))
-
-\f
-;;;*;;; 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::buildwin()'.
-With prefix ARG build with R-devel instead of R-patched."
- (interactive "P")
- (ess-r-package-eval-linewise
- "devtools::build_win(%s)\n" "Checking %s on CRAN's Windows server" arg
- '("" "version = 'R-devel'")))
-
-(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 run with `valgrind = TRUE'."
- (interactive "P")
- (inferior-ess-r-force)
- (ess-r-check-install-package "rhub")
- (let* ((platforms (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 (format "rhub::check_for_cran(%%s, platform = '%s')\n" platform))
- (msg (format "Checking %%s on RHUB (%s)" platform)))
- (ess-r-package-eval-linewise cmd msg arg '("" "valgrind = TRUE"))))
-
-(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: ")))))
-
-\f
-;;;*;;; 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)))))
- vars))
- (add-hook 'project-find-functions #'ess-r-package-project)
- (run-hooks 'ess-r-package-enter-hook))
- (remove-hook 'project-find-functions #'ess-r-package-project)
- (run-hooks 'ess-r-package-exit-hook)))
-
-(add-hook 'after-change-major-mode-hook 'ess-r-package-auto-activate)
-
-\f
-;;;*;;; 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)
-(when (fboundp 'advice-add)
- (require 'shell)
- (advice-add 'shell-resync-dirs :after 'ess-r-package-re-activate))
-
-\f
-;;;*;;; 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)
-(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")
-
-\f
-(provide 'ess-r-package)
-
-;;; ess-r-package.el ends here
+++ /dev/null
-;;; ess-r-syntax.el --- Utils to work with R code
-
-;; Copyright (C) 2015 Lionel Henry
-
-;; Author: Lionel Henry <lionel.hryNOSPAMgmail.com>
-;; Created: 12 Oct 2015
-;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
-
-;; 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:
-
-;; API is not yet stable.
-
-;;; Code:
-
-(require 'ess-utils)
-(require 'regexp-opt)
-
-(eval-when-compile
- (require 'cl-lib))
-
-\f
-;;*;; 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 'eval forms))))
-
-(defun ess-char-syntax (string)
- (char-to-string (char-syntax (string-to-char string))))
-
-\f
-;;*;; 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 ?-)
- (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-escape-token ()
- (ess-escape-comment)
- (ess-skip-blanks-forward)
- (or (ess-escape-string)
- (when (ess-token-delimiter-p (ess-token-after))
- (prog1 t
- (mapc (lambda (delims)
- (while (and (ess-token-after= nil delims)
- (eq (char-before) (string-to-char
- (car delims))))
- (ess-backward-char)))
- '(("[" "[[") ("]" "]]")))))
- (ess-token-after= '("," ";"))
- (and (ess-token-after= "identifier")
- (not (memq (char-syntax (char-before)) '(?w ?_))))
- (progn (skip-syntax-backward ".")
- (ess-token-operator-p (ess-token-after)))
- (/= (skip-syntax-backward "w_") 0)))
-
-(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)))
-
-(defun ess-token-balancing-delim (token)
- (pcase (ess-token-type 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))
-
-
-;;;*;;; Tokens properties and accessors
-
-(defun ess-token-make-hash (&rest specs)
- (let ((table (make-hash-table :test #'equal)))
- (mapc (lambda (spec)
- ;; alist
- (if (listp (cdr spec))
- (mapc (lambda (cell)
- (puthash (car cell) (cdr cell) table))
- spec)
- ;; Cons cell
- (mapc (lambda (token)
- (puthash token (cdr spec) table))
- (car spec))))
- specs)
- table))
-
-(defvar ess-token-r-powers-delimiters
- '(("(" . 100)
- ("[" . 100)
- ("[[" . 100)))
-
-(defvar ess-token-r-powers-operator
- '(("?" . 5)
- ("else" . 8)
- ("<-" . 10)
- ("<<-" . 10)
- ("=" . 15)
- ("->" . 20)
- ("->>" . 20)
- ("~" . 25)
- ("|" . 30)
- ("||" . 30)
- ("&" . 35)
- ("&&" . 35)
- ("!" . 40)
- ("<" . 45)
- (">" . 45)
- ("<=" . 45)
- (">=" . 45)
- ("==" . 45)
- ("+" . 50)
- ("-" . 50)
- ("*" . 55)
- ("/" . 55)
- ("%infix%" . 60)
- (":" . 65)
- ("^" . 70)
- ("$" . 75)
- ("@" . 75)
- ("::" . 80)
- (":::" . 80)))
-
-(defvar ess-token-r-power-table
- (ess-token-make-hash ess-token-r-powers-operator
- ess-token-r-powers-delimiters))
-
-(defvar ess-token-r-right-powers-operator
- '((")" . 1)))
-
-(defvar ess-token-r-right-power-table
- (ess-token-make-hash ess-token-r-powers-operator
- ess-token-r-right-powers-operator))
-
-(defvar ess-token-r-nud-table
- (ess-token-make-hash
- '(("identifier" . identity)
- ("literal" . identity)
- ("number" . identity)
- ("function" . identity)
- ("if" . identity)
- ("while" . identity)
- ("for" . identity))
- '(("(" . ess-parser-nud-block)
- ("{" . ess-parser-nud-block))))
-
-(defvar ess-token-r-rnud-table
- (ess-token-make-hash
- '(("identifier" . identity)
- ("literal" . identity)
- ("number" . identity))
- '((")" . ess-parser-rnud-paren)
- ("}" . ess-parser-nud-block))))
-
-(defvar ess-token-r-leds-operator
- (let ((operators-list (append '("%infix%" "else") ess-r-operators-list)))
- (cons operators-list #'ess-parser-led-lassoc)))
-
-(defvar ess-token-r-leds-delimiter
- '(("(" . ess-parser-led-funcall)
- ("[" . ess-parser-led-funcall)
- ("[[" . ess-parser-led-funcall)))
-
-(defvar ess-token-r-led-table
- (ess-token-make-hash ess-token-r-leds-operator
- ess-token-r-leds-delimiter))
-
-(defvar ess-token-r-rid-table
- (ess-token-make-hash
- '((")" . ess-parser-rid-expr-prefix))))
-
-
-;;;*;;; Nud, led and rid functions
-
-(defun ess-parser-nud-block (prefix-token)
- (let ((right (list (cons "TODO" nil))))
- (ess-parser-advance-pair nil prefix-token)
- (ess-node (cons "block" nil)
- (cons (ess-token-start prefix-token) (point))
- (list prefix-token right))))
-
-(defun ess-parser-led-lassoc (start infix-token)
- (let* ((power (ess-parser-power infix-token))
- (end (ess-parse-expression power)))
- (ess-node (cons "binary-op" nil)
- (cons (ess-parser-token-start start) (point))
- (list start infix-token end))))
-
-(defun ess-parser-led-funcall (left infix-token)
- (when (ess-token= left (append '("identifier" "string" "node")
- ess-r-prefix-keywords-list))
- (let* ((power (ess-parser-power infix-token))
- (right (ess-parse-arglist power infix-token))
- (type (if (ess-token= left ess-r-prefix-keywords-list)
- "prefixed-expr"
- "funcall")))
- (when (string= type "prefixed-expr")
- (setq right (list right (ess-parse-expression 0))))
- (ess-node (cons type nil)
- (cons (ess-parser-token-start left) (point))
- (list left right)))))
-
-(defun ess-parser-rid-expr-prefix (right suffix-token)
- (when (ess-refined-token= suffix-token "prefixed-expr-delimiter")
- (ess-parser-rnud-paren suffix-token right)))
-
-(defun ess-parser-rnud-paren (suffix-token &optional prefixed-expr)
- (let* ((infix-token (save-excursion
- (ess-parser-advance-pair nil suffix-token)))
- (power (ess-parser-power infix-token))
- (args (ess-parse-arglist power suffix-token))
- (left (if prefixed-expr
- (ess-parser-advance)
- (ess-parse-expression power)))
- (type (cond (prefixed-expr "prefixed-expr")
- (left "funcall")
- (t "enclosed-expr"))))
- (when prefixed-expr
- (setcdr (car prefixed-expr) (list infix-token suffix-token)))
- (ess-node (cons type nil)
- (cons (ess-parser-token-start suffix-token) (point))
- (if prefixed-expr
- (list prefixed-expr args left)
- (list args left)))))
-
-
-;;;*;;; Parsing
-
-(defun ess-parser-advance (&optional type value)
- (if (bound-and-true-p ess-parser--backward)
- (ess-climb-token type value)
- (ess-jump-token type value)))
-
-(defun ess-parser-advance-pair (&optional type token)
- (if (bound-and-true-p ess-parser--backward)
- (ess-climb-paired-delims type token)
- (ess-jump-paired-delims type token)))
-
-(defun ess-parser-next-token ()
- (if (bound-and-true-p ess-parser--backward)
- (ess-token-before)
- (ess-token-after)))
-
-(defun ess-parser-token-start (token)
- (if (bound-and-true-p ess-parser--backward)
- (ess-token-end token)
- (ess-token-start token)))
-
-(defun ess-parser-power (token)
- (or (if (bound-and-true-p ess-parser--backward)
- (gethash (ess-token-type token) ess-token-r-right-power-table)
- (gethash (ess-token-type token) ess-token-r-power-table))
- 0))
-
-(defun ess-node (type pos contents)
- (let ((pos (if (bound-and-true-p ess-parser--backward)
- (cons (cdr pos) (car pos))
- pos))
- (contents (if (bound-and-true-p ess-parser--backward)
- (nreverse contents)
- contents)))
- (list type pos contents)))
-
-(defalias 'ess-node-start #'ess-token-start)
-(defalias 'ess-node-end #'ess-token-end)
-
-(defun ess-parse-start-token (token)
- (let* ((table (if (bound-and-true-p ess-parser--backward)
- ess-token-r-rnud-table
- ess-token-r-nud-table))
- (nud (gethash (ess-token-type token) table)))
- (when (fboundp nud)
- (funcall nud token))))
-
-(defun ess-parse-infix-token (infix-token left)
- (let ((infix-power (ess-parser-power infix-token))
- (led (or (when (bound-and-true-p ess-parser--backward)
- (gethash (ess-token-type infix-token) ess-token-r-rid-table))
- (gethash (ess-token-type infix-token) ess-token-r-led-table))))
- (funcall led left infix-token)))
-
-(defun ess-parse-expression (&optional power)
- (let ((current (ess-parse-start-token (ess-parser-advance)))
- (power (or power 0))
- (next (ess-parser-next-token))
- (last-sucessful-pos (point))
- last-success)
- (setq last-success current)
- (while (and current (< power (ess-parser-power next)))
- (ess-parser-advance)
- (when (setq current (ess-parse-infix-token next current))
- (setq last-sucessful-pos (point))
- (setq last-success current))
- (setq next (ess-parser-next-token)))
- (goto-char last-sucessful-pos)
- last-success))
-
-(defun ess-parse-arglist (power start-token)
- (let ((start-pos (point))
- (arg-start-pos (point))
- (arglist (list start-token))
- (closing-delim (ess-token-balancing-delim start-token))
- expr)
- (while (and (setq expr (ess-parse-expression))
- (push (ess-node (cons "arg" nil)
- (cons arg-start-pos (point))
- (list expr))
- arglist)
- (ess-parser-advance ","))
- (setq arg-start-pos (point)))
- (push (ess-parser-advance closing-delim) arglist)
- (ess-node (cons "arglist" nil)
- (cons start-pos (1- (point)))
- (nreverse arglist))))
-
-(defun forward-ess-r-expr ()
- (interactive)
- (ess-save-excursion-when-nil
- (ess-escape-token)
- (ess-parse-expression)))
-
-(defun forward-ess-r-sexp ()
- (interactive)
- (ess-save-excursion-when-nil
- (ess-escape-token)
- (let* ((orig-token (ess-token-after))
- (tree (ess-parse-expression))
- (sexp-node (ess-parser-tree-assoc orig-token tree)))
- (when sexp-node
- (goto-char (ess-token-end sexp-node))
- sexp-node))))
-
-(defun backward-ess-r-expr ()
- (interactive)
- (let ((ess-parser--backward t))
- (ess-parse-expression)))
-
-(defun backward-ess-r-sexp ()
- (interactive)
- (error "Todo"))
-
-(defun ess-parser-tree-assoc (key tree)
- (let ((next tree)
- stack last-node result)
- (while (and next (null result))
- (cond ((eq next 'node-end)
- (pop last-node))
- ((nth 2 next)
- (push 'node-end stack)
- (dolist (node (nth 2 next))
- (push node stack))
- (push next last-node))
- ((equal next key)
- (setq result (car last-node))))
- (setq next (pop stack)))
- result))
-
-\f
-;;*;; 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)))
-
-\f
-;;*;; 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))))))
-
-\f
-;;;*;;; 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))))))
-
-\f
-;;;*;;; 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))))
-
-\f
-;;;*;;; 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))
-
-\f
-;;;*;;; 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)))))
-
-\f
-;;;*;;; 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)))))
-
-\f
-;;;*;;; 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
+++ /dev/null
-;;; ess-r-xref.el --- An xref backend for R. -*- lexical-binding: t -*-
-;;
-;; Author: Aaron Jacobs
-;; Created: 21 January 2018
-;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
-;;
-;; Keywords: languages, statistics, xref
-;;
-;; 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 contains an xref backend for `ess-r-mode'.
-
-;;; Code:
-
-(require 'xref)
-(require 'ess-inf)
-(require 'ess-r-package)
-(require 'ess-tracebug)
-
-;; 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.
-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)))
- (let ((sym (ess-symbol-at-point)))
- (when sym
- (symbol-name sym))))
-
-(cl-defmethod xref-backend-definitions ((_backend (eql ess-r)) symbol)
- (let ((xref (ess-r-xref--xref symbol)))
- (when xref
- (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 ".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))
- (when (re-search-forward "(" nil 'noerror)
- (goto-char (match-beginning 0))
- (read (current-buffer))))))
-
-(defun ess-r-xref--pkg-srcfile (symbol r-src-file)
- "Look in the source directory of the R package containing symbol SYMBOL for R-SRC-FILE."
- (let* ((env-name (ess-string-command (format ".ess_fn_pkg(\"%s\")\n" symbol)))
- (pkg (if (string-equal env-name "")
- (user-error "Can't find package for symbol %s" symbol)
- env-name))
- (dir (or (assoc-default pkg ess-r-xref-pkg-sources)
- (cond ((stringp ess-r-package-library-paths)
- (expand-file-name pkg ess-r-package-library-paths))
- ((listp ess-r-package-library-paths)
- (cl-loop for d in ess-r-package-library-paths
- for p = (expand-file-name pkg d)
- when (file-exists-p p) return p))
- (t (user-error "Invalid value of `ess-r-package-library-paths'")))))
- (file (when dir (expand-file-name r-src-file dir))))
- (when file
- (unless (file-readable-p file)
- (user-error "Can't read %s" file))
- ;; Cache package's source directory.
- (unless (assoc pkg ess-r-xref-pkg-sources)
- (push `(,pkg . ,dir) ess-r-xref-pkg-sources))
- file)))
-
-(defun ess-r-xref--xref (symbol)
- "Create an xref for the source file reference of R symbol SYMBOL."
- (let ((ref (ess-r-xref--srcref symbol)))
- (when ref
- (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) Actual file location
- (when (file-readable-p file)
- (xref-make symbol (xref-make-file-location file line col)))
- ;; 3) Temporary sources - truncate and locate in ess-r-package-library-paths
- (when (string-match "/\\(R/.*\\)$" file)
- (let ((pkg-file (ess-r-xref--pkg-srcfile symbol (match-string 1 file))))
- (when pkg-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
+++ /dev/null
-;; ess-rd.el --- Support for editing R documentation (Rd) source -*- lexical-binding: t; -*-
-
-;; Copyright (C) 1997--2005 A.J. Rossini, Richard M. Heiberger, Martin
-;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
-
-;; Author: KH <Kurt.HornikNOSPAMci.tuwien.ac.at>
-;; Created: 25 July 1997
-;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
-
-;; This file is part of ESS (Emacs Speaks Statistics).
-
-;; This file is free software; you may 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 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 on the World
-;; Wide Web at https://www.gnu.org/copyleft/gpl.html. You can also
-;; obtain it by writing to the Free Software Foundation, Inc., 675 Mass
-;; Ave, Cambridge, MA 02139, USA.
-
-
-;;; 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"
- ;;
- "R" "RdOpts" "S3method" "S4method" "Sexpr" "acronym"
- "bold" "cite" "code" "command" "cr" "dQuote" "deqn" "dfn" "dontrun"
- "dontshow" "donttest" "dots" "email" "emph" "enc" "env" "eqn" "figure" "file"
- "href" "if" "ifelse"
- "item" "kbd" "ldots" "linkS4class" "link" "method"
- "newcommand" "option" "out"
- "pkg" "sQuote" "renewcommand"
- "samp" "strong" "tab" "url" "var" "verb"
- ;; System macros (from <R>/share/Rd/macros/system.Rd ):
- "CRANpkg" "PR" "sspace" "doi"
- "packageTitle" "packageDescription" "packageAuthor"
- "packageMaintainer" "packageDESCRIPTION" "packageIndices"
- ))
-
-(defvar Rd-font-lock-keywords
- (list
- (cons
- (concat "\\\\\\("
- (mapconcat 'identity Rd-section-names "\\|")
- "\\>\\)")
- 'font-lock-reference-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-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]
- "-"
- ["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)*" (point-at-eol) 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)*" (point-at-eol) 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"))
-
-;; 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-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
+++ /dev/null
-;;; ess-rdired.el --- prototype object browser for R, looks like dired mode. -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2002--2019 A.J. Rossini, Richard M. Heiberger, Martin
-;; Maechler, Kurt Hornik, Rodney Sparapani, Stephen Eglen, and J. Alexander Branham.
-
-;; Author: Stephen Eglen <stephenNOSPAManc.ed.ac.uk>
-;; Created: Thu 24 Oct 2002
-;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
-
-;; This file is part of ESS
-
-;; This file is not part of GNU Emacs.
-
-;; ess-rdired.el 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-rdired.el 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 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.
-
-;;; Commentary:
-
-;; 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 "local({.rdired.objects <- function(objs) {
- if (length(objs)==0) {
- \"No objects to view!\"
- } else {
- mode <- sapply(objs, function(my.x) {
- eval( parse( text=sprintf('data.class(get(\"%s\"))', my.x))) })
- length <- sapply(objs, function(my.x) {
- eval( parse( text=sprintf('length(get(\"%s\"))', my.x))) })
- size <- sapply(objs, function(my.x) {
- eval( parse( text=sprintf('format(object.size(get(\"%s\")), units=\"b\")', my.x))) })
- 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='')
- d
- }
-}; cat('\n'); print(.rdired.objects(ls(envir = .GlobalEnv)))})\n"
- "Function to call within R to print information on objects.
-The last line of this string should be the instruction to call
-the function which prints the output for rdired.")
-
-(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-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+ (point-at-eol 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
+++ /dev/null
-;;; ess-roxy.el --- convenient editing of in-code roxygen documentation
-;;
-;; Copyright (C) 2009--2018 Henning Redestig, A.J. Rossini, Richard
-;; M. Heiberger, Martin Maechler, Kurt Hornik, Rodney Sparapani, Stephen
-;; Eglen, Vitalie Spinu, and J. Alexander Branham.
-;;
-;; Author: Henning Redestig <henning.red * go0glemail c-m>
-;; Keywords: convenience, tools
-;;
-;; 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 of the
-;; License, or (at your option) any later version.
-;;
-;; This program is distributed in the hope that it will be useful, but
-;; WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-;; General Public License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with this program. If not, see
-;; <https://www.gnu.org/licenses/>.
-
-
-;;; 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.")
-
-\f
-;;*;; 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-and-indent)
- (define-key map [remap newline-and-indent] #'ess-roxy-newline-and-indent)
- (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)))
-
-
-\f
-;;*;; 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-overwiew))
- (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)))))
-
-(when (featurep 'outline-magic)
- (substitute-key-definition 'outline-cyle
- 'ess-roxy-cyle-example
- ess-roxy-mode-map outline-mode-menu-bar-map))
-
-(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)
-
-\f
-;;*;; Function definitions
-
-(defun ess-back-to-roxy ()
- "Go to roxy prefix."
- (end-of-line)
- (re-search-backward (concat ess-roxy-re " ?") (point-at-bol))
- (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)))" ))
- (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 (point-at-bol))
- (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 (point-at-eol))
- (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*\\)" (point-at-bol) 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'."
- ;; Only strip the prefix in the @examples field, and only when
- ;; STRING is entirely contained inside it. This allows better
- ;; behavior for evaluation of regions.
- (let ((roxy-re ess-roxy-re))
- (if (and (ess-roxy-entry-p "examples")
- ;; don't send just @examples if we're looking at a line
- ;; like: ##' @examples
- (not (string-match-p (concat roxy-re "[[:space:]]*@") string))
- ;; (with-temp-buffer
- ;; ;; Need to carry the buffer-local value of
- ;; ;; `ess-roxy-re' into the temp buffer:
- ;; (setq ess-roxy-re roxy-re)
- ;; (insert string)
- ;; (ess-roxy-entry-p))
- )
- (replace-regexp-in-string (concat ess-roxy-re "\\s-*") "" string)
- string)))
-
-(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)))
-
-\f
-;;*;; 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 " *") (point-at-bol) 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)))
-
-(defun ess-roxy-newline-and-indent ()
- "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-and-indent)))
-
-(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))
-
-(provide 'ess-roxy)
-
-;;; ess-roxy.el ends here
+++ /dev/null
-;;; ess-s-lang.el --- Support for editing S source code -*- lexical-binding: t; -*-
-
-;; Copyright (C) 1989-1997 D. Bates, Kademan, Ritter, D.M. Smith, K. Hornik,
-;; R.M. Heiberger, M. Maechler, and A.J. Rossini.
-;; Copyright (C) 1998-2015 A.J. Rossini, Richard M. Heiberger, Martin
-;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
-
-;; Author: A.J. Rossini <rossiniNOSPAMbiostat.washington.edu>
-;; Created: 26 Aug 1997
-;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
-
-;; This file is part of ESS (Emacs Speaks Statistics).
-
-;; 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:
-
-;; Code for general editing S source code (specializes to S, S+, R).
-
-;;; Code:
-
-\f ; Requires and autoloads
-
-(require 'ess-mode)
-(require 'ess-help)
-(require 'ess-inf)
-
-(declare-function speedbar-add-supported-extension "speedbar" (extension))
-
-\f ; 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 <dialect>-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.")
-
-\f ; 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]\\)\\(<<?-\\)" "\\1 \\2" nil nil verbose)
- (goto-char from)(ess-rep-regexp "<-\\([^ \t\n]\\)" "<- \\1" nil nil verbose)
- ;; ensure space around "<" (not in "<-","<=","<<-") and ">" (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))))))))
- (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 (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."
- (interactive "sFunction ? ")
- (declare (obsolete 'ess-execute "ESS 19.04"))
- (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"))
-
-(define-obsolete-function-alias 'ess-imenu-R 'ess-imenu-S "ESS 19.04")
-
-
-\f ;;; 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))))
-
-(defalias 'S 'S+)
-(defalias 's-mode 'S+-mode)
-(defalias 's-transcript-mode 'S+-transcript-mode)
-(defalias 'S-transcript-mode 's-transcript-mode)
-(defalias 'S-mode 's-mode)
-
-
-(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")
-
-(define-obsolete-function-alias 'ess-toggle-underscore 'ess-disable-smart-S-assign "ESS 18.10")
-(define-obsolete-function-alias 'ess-toggle-S-assign 'ess-disable-smart-S-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
+++ /dev/null
-;;; ess-sas-a.el --- clean-room implementation of many SAS-mode features
-
-;; Copyright (C) 1997--2009 A.J. Rossini, Richard M. Heiberger, Martin
-;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
-
-;; Author: Rodney A. Sparapani
-;; Maintainer: ESS-coreNOSPAMr-project.org
-;; Created: 17 November 1999
-;; Keywords: languages
-
-;; 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/
-
-;;; Code:
-
-(require 'ess-mode)
-;; 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]?\\)"
- "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-alist nil)
- (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")))
-
- (if (and ess-tmp-ps ess-tmp-pdf)
- (setq ess-tmp-alist (list (cons "[eE]?[pP][sS]" ess-tmp-ps)
- (cons "[pP][dD][fF]" ess-tmp-pdf)))
-
- (if ess-tmp-ps
- (setq ess-tmp-alist (list (cons "[eE]?[pP][sS]" ess-tmp-ps)
- (cons "[pP][dD][fF]" ess-tmp-ps))))))
-
- "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)))
-
- ;;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-sas-file-path t)
- (ess-revert-wisely)
-
- (set-visited-file-name (concat (buffer-name) ".rtf"))
-; (ess-sas-goto "rtf" t)
- (if '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"))
-
- (if '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\\|\f\\|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)
-
- (if arg
- (progn
- (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))
- ;;else
- (define-key sas-mode-local-map [return] 'newline-and-indent)
- (define-key sas-mode-local-map "\t" 'sas-indent-line)))
-
-(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 recieve: " 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 recieve: " 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
+++ /dev/null
-;;; ess-sas-d.el --- SAS customization
-
-;; Copyright (C) 1997--2001 Richard M. Heiberger and A. J. Rossini
-;; Copyright (C) 2002--2004 A.J. Rossini, Richard M. Heiberger, Martin
-;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
-
-;; Author: Richard M. Heiberger <rmhNOSPAMtemple.edu>
-;; Created: 20 Aug 1997
-;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
-
-;; Keywords: languages
-
-;; 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 defines all the SAS customizations for ESS behaviors. See
-;; ess-sas-l and ess-sas-a for the underlying general modifications.
-
-;;; Code:
-
-;;; Autoloads:
-
-(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
- (shell)
- (accept-process-output (get-buffer-process (current-buffer)))
- (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
- (shell)
- (accept-process-output (get-buffer-process (current-buffer)))
- (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)))
- (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 ";") (let (insertpos)
- (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
- (if insertpos (goto-char (1+ insertpos)))
- (delete-char -1))))
- (if insertpos
- (save-excursion
- (goto-char insertpos)
- (self-insert-command (prefix-numeric-value arg)))
- (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))
-
-\f ; Provide package
-
-(provide 'ess-sas-d)
-
-;;; ess-sas-d.el ends here
+++ /dev/null
-;;; ess-sas-l.el --- SAS customization
-
-;; Copyright (C) 1997--2009 A.J. Rossini, Richard M. Heiberger, Martin
-;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
-
-;; Authors: Richard M. Heiberger
-;; A.J. Rossini
-;; Rodney Sparapani
-;; Created: 20 Aug 1997
-;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
-
-;; Keywords: languages
-
-;; This file is part of ESS (Emacs Speaks Statistics).
-
-;; 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 is based upon Version 1.4 of SAS mode:
-
-
-;;; sas-mode: indent, run etc, SAS programs.
-;;; Copyright (C) 1994--1997 Tom Cook
-;;; Author: Tom Cook
-;;; Dept. of Biostatistics
-;;; University of Wisconsin - Madison
-;;; Madison, WI 53706
-;;; cookNOSPAMbiostat.wisc.edu
-;;;
-;;; Acknowledgements:
-;;; Menu code for XEmacs/Lucid emacs and startup mods
-;;; contributed by arossiniNOSPAMbiostats.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))
-
-(fset 'sas-log-mode 'SAS-log-mode)
-(fset 'SAS-transcript-mode 'SAS-log-mode)
-(fset 'sas-transcript-mode 'SAS-log-mode)
-(fset 'sas-mode 'SAS-mode)
-(fset '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 "\\<and(" font-lock-function-name-face)
- (cons "\\<data=" font-lock-keyword-face)
- (cons "\\<in:(" font-lock-function-name-face)
- (cons "\\<index(" font-lock-function-name-face)
- (cons "\\<input(" font-lock-function-name-face)
- (cons "\\<libname(" font-lock-function-name-face)
- (cons "\\<not(" font-lock-function-name-face)
- (cons "\\<or(" font-lock-function-name-face)
- (cons "\\<put(" font-lock-function-name-face)
- (cons "\\<sum(" font-lock-function-name-face)
-
- ; other idiosyncratic keywords
- ;(cons "key=" font-lock-keyword-face)
- ;(cons "/unique" font-lock-keyword-face)
-
- ;; SAS execution blocks: DATA, %MACRO/%MEND, %DO/%END, etc.
- (cons (regexp-opt '(
- "data" "start" "return" ;"proc"
- "%macro" "%mend"
- "%do" "%to" "%by" "%end"
- "%goto" "%go to"
- "%if" "%then" "%else"
- "%global" "%inc" "%include" "%input" "%local" "%let" "%put" "%sysexec"
- ) 'words) font-lock-constant-face)
-
- ;; SAS execution blocks that must be followed by a semi-colon
- (cons (concat "\\<"
- (regexp-opt
- '(
- "run;" "quit;" "endsas;" "finish;"
- "cards;" "cards4;" "datalines;" "datalines4;" "lines;" "lines4;"
- )))
- font-lock-constant-face)
-
- ;; SAS statements that must be followed by a semi-colon
- (cons (concat "\\<"
- (regexp-opt
- '(
- "end;" "list;" "lostcard;" "page;" "stop;" ;"return;"
- )))
- font-lock-keyword-face)
-
- ;; SAS statements that must be followed by an equal sign
- (cons (concat "\\<"
- (regexp-opt
- '(
- "compress=" "in=" "out=" "sortedby="
- )))
- font-lock-keyword-face)
-
-;;; ;; SAS procedure names
- (cons (concat "\\<proc[ ]+"
- (regexp-opt '(
- ;; SAS base and SAS/Graph
- "append"
- "calendar" "catalog" "chart" "cimport" "cport" "compare" "contents" "copy" "corr"
- "datasets" "dbcstab" "display"
- "explode" "export"
- "fcmp" "format" "forms" "freq" "fsbrowse" "fsedit" "fsletter" "fslist" "fsview"
- "ganno" "gchart" "gcontour" "gdevice" "geocode" "gfont" "gimport" "ginside"
- "gkeymap" "gmap" "goptions" "gplot" "gprint" "gproject" "greduce" "gremove"
- "greplay" "gslide" "gtestit" "g3d" "g3grid"
- "iml" "import" "insight"
- "mapimport" "means"
- "options"
- "plot" "pmenu" "print" "printto"
- "rank" "registry" "report"
- "setinit" "sgdesign" "sgmap"
- "sgpanel" "sgplot" "sgrender" "sgscatter" "sort" "sql" "standard" "summary"
- "tabulate" "template" "timeplot" "transpose" "trantab"
- "univariate"
-
- ;;SAS/Stat and SAS/ETS
- "aceclus" "anova" "arima" "autoreg"
- "bgenmod" "blifereg" "boxplot" "bphreg"
- "calis" "cancorr" "candisc" "catmod" "citibase" "cluster" "computab" "corresp" "countreg"
- "discrim" "distance"
- "entropy" "expand"
- "factor" "fastclus" "forecast"
- "gam" "gee" "genmod" "glimmix" "glm" "glmmod" "glmpower" "glmselect"
- "hpmixed"
- "inbreed"
- "kde" "krige2d"
- "lattice" "lifereg" "lifetest" "loess" "logistic"
- "mcmc" "mdc" "mds" "mi" "mianalyze" "mixed" "modeclus" "model" "mortgage" "multtest"
- "nested" "nlin" "nlmixed" "npar1way"
- "orthoreg"
- "panel" "pdlreg" "phreg" "plan" "plm" "pls" "power" "princomp" "prinqual" "probit"
- "qlim" "quantreg"
- "reg" "risk" "robustreg" "rsreg"
- "score" "seqdesign" "seqtest" "severity" "sim2d" "similarity" "simlin" "simnormal"
- "spectra" "statespace" "stdize" "stepdisc"
- "surveyfreq" "surveylogistic" "surveymeans" "surveyphreg" "surveyreg" "surveyselect" "syslin"
- "tcalis" "timeid" "timeseries" "tphreg" "tpspline" "transreg" "tree" "ttest"
- "ucm"
- "varclus" "varcomp" "variogram" "varmax"
- "x11" "x12"
- ) 'words)) font-lock-constant-face)
-
- ; (cons (concat
- ; "\\<"
- ; "do[ \t]*" (regexp-opt '("over" "until" "while") t) "?"
- ; "\\>")
- ; 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 "\\<call[ \t]+[a-z]+(" font-lock-function-name-face)
-
- (cons (concat ;"\\<"
- (regexp-opt
- '(
- "abs" "arcos" "arsin" "atan"
- "betainv" "byte"
- "call execute" "call label" "call module" "call modulei"
- "call poke" "call ranbin" "call rancau" "call ranexp"
- "call rangam" "call rannor" "call ranpoi" "call rantbl"
- "call rantri" "call ranuni" "call rxchange" "call rxfree"
- "call rxsubstr" "call set" "call streaminit" "call symput" "call system"
- "cdf" "ceil" "cinv" "collate" "compress" "convx" "convxp" "cos" "cosh" "css" "cv"
- "daccdb" "daccdbsl" "daccsl" "daccsyd" "dacctab"
- "depdb" "depdbsl" "depsl" "depsyd" "deptab"
- "date" "datejul" "datepart" "datetime" "day" "dhms" "dif" "digamma" "dim"
- "erf" "erfc" "exp"
- "finv" "fipname" "fipnamel" "fipstate" "floor" "fuzz"
- "gaminv" "gamma"
- "hbound" "hms" "hour"
- "in" "index" "indexc" "input" "int" "intck" "intnx" "intrr" "irr"
- "juldate"
- "kurtosis"
- "lag" "lbound" "left" "length" "lgamma" "log" "log10" "log2"
- "logcdf" "logpdf" "logsdf"
- "max" "mdy" "mean" "min" "minute" "mod" "month" "mort"
- "n" "netpv" "nmiss" "normal" "npv"
- "ordinal"
- "pdf"
- "probbeta" "probbnml" "probchi" "probf" "probgam" "probhypr" "probit" "probnegb" "probnorm" "probt"
- "poisson" "put"
- "qtr" "quantile"
- "rand" "range" "rank" "repeat" "reverse" "right" "round" "rxmatch" "rxparse"
- "ranbin" "rancau" "ranexp" "rangam" "rannor" "ranpoi" "rantbl" "rantri" "ranuni"
- "saving" "scan" "sdf" "second" "sign" "sin" "sinh" "sqrt" "squantile"
- "std" "stderr" "stfips" "stname" "stnamel" "substr" "sum" "symget"
- "tan" "tanh" "time" "timepart" "tinv" "today" "translate" "trigamma" "trim" "trunc"
- "uniform" "until" "upcase" "uss"
- "var" "verify"
- "weekday" "when" "while"
- "year" "yyq"
- "zipfips" "zipname" "zipnamel" "zipstate"
-
-;;; ;; SAS/IML functions
- "all" "allcomb" "allperm" "any" "apply" "armasim"
- "bin" "blankstr" "block" "branks" "bspline" "btran" "byte"
- "char" "choose" "col" "colvec" "concat" "contents" "convexit" "corr" "corr2cov"
- "countmiss" "countn" "countunique" "cov" "cov2corr" "covlag" "cshape" "cusum"
- "cuprod" "cv" "cvexhull"
- "datasets" "design" "designf" "det" "diag" "dimension" "distance" "do" "duration"
- "echelon" "eigval" "eigvec" "expmatrix" "expandgrid"
- "fft" "fftc" "forward" "froot" "full"
- "gasetup" "geomean" "ginv"
- "hadamard" "half" "hankel" "harmean" "hdir" "hermite" "homogen"
- "i" "ifft" "ifftc" "importtablefromr" "insert" "inv" "invupdt" "isempty" "isskipped"
- "j" "jroot"
- "kurtosis"
- "lambertw" "listgetallnames" "listgetitem" "listgetname" "listgetsubitem" "listindex"
- "listlen" "loc" "logabsdet"
- "mad" "magic" "mahalanobis" "moduleic" "modulein"
- "name" "ncol" "nrow" "ndx2sub" "nleng" "norm" "num"
- "opscal" "orpol"
- "parentname" "palette" "polyroot" "prod" "product" "pv"
- "quartile"
- "rancomb" "randdirichlet" "randfun" "randmultinomial" "randmvt" "randnormal" "randwishart"
- "ranperk" "ranperm" "ranktie" "rates" "ratio" "remove" "repeat" "root" "row"
- "rowcat" "rowcatc" "rowvec" "rsubstr"
- "sample" "setdif" "shape" "shapecol" "skewness" "solve" "sparse" "splinev" "spot"
- "sqrsym" "sqrvech" "ssq" "standard" "storage" "sub2ndx" "sweep" "symsqr"
- "t" "tablecreate" "tablecreatefromdataset" "tablegetvardata" "tablegetvarformat"
- "tablegetvarindex" "tablegetvarinformat" "tablegetvarlabel" "tablegetvarname"
- "tablegetvartype" "tableisexistingvar" "tableisvarnumeric" "tfhilbert" "tfpwv"
- "tfstft" "tfwindow" "toeplitz" "trace" "trisolv" "type"
- "union" "unique" "uniqueby"
- "value" "vecdiag" "vech"
- "xmult" "xsect"
- "yield"
-
-;;; ;; SAS functions introduced in Technical Report P-222
- "airy"
- "band" "blshift" "brshift" "bnot" "bor" "bxor"
- "cnonct" "compbl"
- "dairy" "dequote"
- "fnonct"
- "ibessel" "indexw" "inputc" "inputn"
- "jbessel"
- "lowcase"
- "putc" "putn"
- "quote"
- "resolve"
- "soundex" "sysprod"
- "tnonct" "tranwrd" "trimn"
-
-;;; ;; SCL functions that are known to work with SAS macro function %sysfunc
- "attrc" "attrn"
- "cexist" "close"
- "dclose" "dnum" "dopen" "dread"
- "exist"
- "fclose" "fetchobs" "fileexist" "finfo" "fopen" "fput" "fwrite"
- "getoption" "getvarc" "getvarn"
- "libname" "libref"
- "open" "optgetn" "optsetn"
- "pathname"
- "sysmsg"
- "varfmt" "varlabel" "varnum" "vartype"
- ) 'words) ;"\\>"
- "("); "[ \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 "\\<call[ \t]+[a-z_][a-z_0-9]*[ \t]*("
- font-lock-function-name-face)
-
- (cons (concat
- "\\<"
- "\\(a\\(bs\\|r\\(cos\\|sin\\)\\|tan\\)\\|b\\(etainv\\|yte\\)"
- "\\|c\\(eil\\|inv\\|o\\(llate\\|mpress\\|sh?\\)\\|ss\\|v\\)"
- "\\|dacc\\(db\\(\\|sl\\)\\|s\\(l\\|yd\\)\\|tab\\)"
- "\\|dep\\(db\\(\\|sl\\)\\|s\\(l\\|yd\\)\\|tab\\)"
- "\\|d\\(a\\(te\\(\\|jul\\|part\\|time\\)\\|y\\)\\|hms\\|i\\(f[0-9]*\\|m\\|gamma\\)\\)"
- "\\|e\\(rfc?\\|xp\\)"
- "\\|f\\(i\\(nv\\|p\\(namel?\\|state\\)\\)\\|loor\\|uzz\\)\\|gam\\(inv\\|ma\\)"
- "\\|h\\(bound\\|ms\\|our\\)\\|i\\(n\\(dexc?\\|put\\|t\\(\\|ck\\|nx\\|rr\\)\\)\\|rr\\)"
- "\\|juldate\\|kurtosis\\|l\\(ag[0-9]*\\|bound\\|e\\(ft\\|ngth\\)\\|gamma\\|og\\(\\|10\\|2\\)\\)"
- "\\|m\\(ax\\|dy\\|ean\\|in\\(\\|ute\\)\\|o\\(d\\|nth\\|rt\\)\\)"
- "\\|n\\(\\|etpv\\|miss\\|o\\(rmal\\|t\\)\\|pv\\)"
- "\\|prob\\([ft]\\|b\\(eta\\|nml\\)\\|chi\\|gam\\|hypr\\|it\\|n\\(egb\\|orm\\)\\)"
- "\\|ordinal\\|p\\(oisson\\|ut\\)\\|qtr\\|r\\(e\\(peat\\|verse\\)\\|ight\\|ound\\)"
- "\\|ran\\(bin\\|cau\\|exp\\|g\\(am\\|e\\)\\|k\\|nor\\|poi\\|t\\(bl\\|ri\\)\\|uni\\)"
- "\\|s\\(aving\\|can\\|econd\\|i\\(gn\\|nh?\\)\\|qrt\\|t\\(d\\(\\|err\\)\\|fips\\|namel?\\)\\|u\\(bstr\\|m\\)\\|ymget\\)"
- "\\|t\\(anh?\\|i\\(me\\(\\|part\\)\\|nv\\)\\|oday\\|r\\(anslate\\|i\\(gamma\\|m\\)\\|unc\\)\\)"
- "\\|u\\(niform\\|pcase\\|ss\\)\\|v\\(ar\\|erify\\)"
- "\\|weekday\\|y\\(ear\\|yq\\)\\|zip\\(fips\\|namel?\\|state\\)"
-
-;;; ;; SAS functions introduced in Technical Report P-222
-
- "\\|airy\\|b\\(and\\|lshift\\|not\\|or\\|rshift\\|xor\\)"
- "\\|c\\(nonct\\|ompbl\\)\\|d\\(airy\\|equote\\)\\|fnonct\\|tnonct"
- "\\|i\\(bessel\\|n\\(dexw\\|put[cn]\\)\\)\\|jbessel\\|put[cn]"
- "\\|lowcase\\|quote\\|resolve\\|s\\(oundex\\|ysprod\\)\\|tr\\(anwrd\\|imn\\)"
-
-;;; ;; IML functions that are not also Datastep functions
- "\\|a\\(ll\\|ny\\|pply\\|rmasim\\)\\|b\\(lock\\|ranks\\|tran\\)"
- "\\|c\\(har\\|hoose\\|on\\(cat\\|tents\\|vexit\\|vmod\\)\\|ovlag\\|shape\\|usum\\|vexhull\\)"
- "\\|d\\(atasets\\|esignf?\\|et\\|iag\\|o\\|uration\\)"
- "\\|e\\(chelon\\|igv\\(al\\|ec\\)\\)\\|f\\(ft\\|orward\\)\\|ginv"
- "\\|h\\(alf\\|ankel\\|dir\\|ermite\\|omogen\\)"
- "\\|i\\(\\|fft\\|nsert\\|nv\\(updt\\)?\\)\\|j\\(\\|root\\)\\|loc\\|mad"
- "\\|n\\(ame\\|col\\|leng\\|row\\|um\\)\\|o\\(pscal\\|rpol\\)"
- "\\|p\\(olyroot\\|roduct\\|v\\)\\|r\\(anktie\\|ates\\|atio\\|emove\\|eturn\\|oot\\|owcatc?\\)"
- "\\|s\\(etdif\\|hape\\|olve\\|plinev\\|pot\\|qrsym\\|ssq\\|torage\\|weep\\|ymsqr\\)"
- "\\|t\\(\\|eigv\\(al\\|ec\\)\\|oeplitz\\|race\\|risolv\\|ype\\)"
- "\\|uni\\(on\\|que\\)\\|v\\(alue\\|ecdiag\\)\\|x\\(mult\\|sect\\)\\|yield"
-
-;;; ;; SCL functions that are known to work with SAS macro function %sysfunc
-
- "\\|attr[cn]\\|c\\(exist\\|lose\\)\\|d\\(close\\|num\\|open\\|read\\)"
- "\\|exist\\|f\\(close\\|etchobs\\|i\\(leexist\\|nfo\\)\\|open\\|put\\|write\\)"
- "\\|get\\(option\\|var[cn]\\)\\|lib\\(name\\|ref\\)\\|op\\(en\\|t\\(getn\\|setn\\)\\)"
- "\\|pathname\\|sysmsg\\|var\\(fmt\\|l\\(abel\\|en\\)\\|n\\(ame\\|um\\)\\|type\\)\\)"
- "[ \t]*(") font-lock-function-name-face)
- ))
- "Font Lock regexs for SAS.")
-
-(defun beginning-of-sas-statement (arg &optional comment-start)
- "Move point to beginning of current sas statement."
- (interactive "P")
- (let ((pos (point))
- )
- (if (search-forward ";" nil 1) (forward-char -1))
- (re-search-backward ";[ \n*/]*$" (point-min) 1 arg)
- (skip-chars-forward sas-comment-chars)
- (if comment-start nil
- (if (looking-at "\\*/")
- (progn (forward-char 2)
- (skip-chars-forward sas-comment-chars)))
- (while (looking-at "/\\*")
- (if (not (search-forward "*/" pos t 1)) ;;(;; (point-max) 1 1)
- (forward-char 2))
- (skip-chars-forward sas-white-chars)))))
-
-(defun sas-indent-line ()
- "Indent function for SAS mode."
- (interactive)
- (let (indent prev-end
- (pos (- (point-max) (point)))
- (case-fold-search t)
- (cur-ind (current-indentation))
- (comment-col (sas-comment-start-col))) ;; 2/1/95 TDC
- (save-excursion
- (cond ((progn
- (back-to-indentation)
- (or (bobp)
- (looking-at
- "data[ ;]\\|proc[ ;]\\|run[ ;]\\|quit[ ;]\\|endsas[ ;]\\|g?options[ ;]\\|%macro[ ;]\\|%mend[ ;]")))
- ;; Case where current statement is DATA, PROC, etc...
- (setq prev-end (point))
- (goto-char (point-min))
- ;; Added 6/27/94
- ;; May get fooled if %MACRO, %DO, etc embedded in comments
- (setq indent
- (+ (* (- (sas-how-many "^[ \t]*%macro\\|[ \t]+%do"
- prev-end)
- (sas-how-many "^[ \t]*%mend\\|%end" prev-end))
- sas-indent-width) comment-col))) ;; 2/1/95 TDC
- ;; Case where current line begins with sas-indent-ignore-comment
- ;; added 6/27/94 to leave "* ;" comments alone.
- ((progn
- (back-to-indentation)
- (and (not (looking-at "\\*/"))
- (looking-at (concat sas-indent-ignore-comment "\\|/\\*"))))
- (setq indent (current-indentation)))
- ;; Case where current statement not DATA, PROC etc...
- (t (beginning-of-line 1)
- (skip-chars-backward sas-white-chars)
- (if (bobp) nil
- (backward-char 1))
- (cond
- ((looking-at ";") ; modified 1/31/95
- (setq indent (sas-next-statement-indentation)))
- ((save-excursion;; added 4/28/94 to properly check
- (if (bobp) () (backward-char 1));; for end of comment
- (setq prev-end (point))
- (looking-at "\\*/"));; improved 1/31/95
- (save-excursion
- (search-backward "*/"
- (point-min) 1 1); comment start is first /*
- (search-forward "/*"
- prev-end 1 1) ; after previous */
- (backward-char 2) ; 2/1/95 TDC
- (skip-chars-backward sas-white-chars)
- (setq indent
- (if (bobp) 0
- (if (looking-at ";")
- (sas-next-statement-indentation)
- ;;(+ (current-indentation) sas-indent-width)
- (current-indentation))))))
-
- ;; added 6/27/94 to leave "* ;" comments alone
- ((save-excursion
- (progn
- (beginning-of-sas-statement 1 t)
- (and (not (looking-at "\\*/"))
- (looking-at sas-indent-ignore-comment))))
- (setq indent cur-ind))
- ((progn
- (beginning-of-sas-statement 1)
- (bobp));; added 4/13/94
- (setq indent sas-indent-width));; so the first line works
- ((save-excursion
- (beginning-of-sas-statement 2)
- (looking-at "cards4?;\\|datalines4?;\\|lines4?;"))
- (setq indent (current-indentation))) ; So cards keep indentation.
- (t
- (if (progn
- (save-excursion
- (beginning-of-line 1)
- (skip-chars-backward sas-white-chars)
- (if (bobp) nil (backward-char 1))
- (or (looking-at ";")
- (bobp) (backward-char 1) (looking-at "\\*/"))))
- (setq indent (+ (current-indentation) sas-indent-width))
- (setq indent (current-indentation))))))))
- (save-excursion
- (let (beg end)
- (back-to-indentation)
- (setq end (point))
- (beginning-of-line 1)
- (setq beg (point))
- (delete-region beg end)
- (indent-to indent)))
- (if (> (- (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 ;
-"))))
-
-
-
-;;-*-emacs-lisp-*-
-;;; file name: sas-data.el
-;;;
-;;; Version 1.0
-;;;
-;;; sas-data-mode: manage sas datasets
-;;; Copyright (C) 1994 Tom Cook
-;;;
-;;; 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 2 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.
-;;;
-;;; A copy of the GNU General Public License is available at
-;;; https://www.r-project.org/Licenses/
-;;;
-;;; Author: Tom Cook
-;;; Dept. of Biostatistics
-;;; University of Wisconsin - Madison
-;;; Madison, WI 53706
-;;; cookNOSPAMbiostat.wisc.edu
-;; Created: 8/11/94
-\f
-;; 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
-\f
-;; keymaps etc...
-
-(if sas-dir-mode-map ()
- (setq sas-dir-mode-map (make-sparse-keymap))
- ;;(define-key sas-dir-mode-map "c" 'sas-contents)
- (define-key sas-dir-mode-map "p" 'sas-print)
- (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 [mouse-2] 'sas-mouse-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 "g" 'sas-revert-library)
- (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 (arg)
- "Move up one line."
- (interactive "p")
- (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-contents ()
-;; "Run proc contents on current file."
-;; (interactive)
-;; (let ((buffer-read-only nil) (sas-get-options "linesize=70"))
-;; (sas-get-dataset (sas-get-filename) 2 t t (buffer-name))
-;; (end-of-buffer)
-;; (backward-page-top-of-window 1)))
-;;
-;;(defun sas-print ()
-;; "Run proc contents on current file."
-;; (interactive)
-;; (sas-get-dataset (sas-get-filename) 1 nil nil nil
-;; (sas-create-var-string)))
-
-(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-mouse-goto-dataset (event)
-;; (interactive "e")
-;; (let (page buf)
-;; (save-window-excursion
-;; (save-excursion
-;; (set-buffer (window-buffer (posn-window (event-end event))))
-;; (save-excursion
-;; (goto-char (posn-point (event-end event)))
-;; (setq page (sas-get-file-number)))
-;; (sas-goto-dataset page)
-;; (setq buf (buffer-name))))
-;; (set-buffer buf)
-;; (goto-char (point-min))
-;; (display-buffer buf)))
-
-
-(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=]\\([a-zA-Z_][a-zA-Z_0-9]*[.][a-zA-Z_][a-zA-Z_0-9]*\\)[ ,()\t\n;]" 1)))
- (imenu-add-to-menubar "SAS Datasets"))
-
-;;(defun sas-revert-library ()
-;; "Update current library."
-;; (interactive)
-;; (if sas-directory-name
-;; (sas-make-library sas-directory-name t)))
-
-(provide 'ess-sas-l)
-
-;;; ess-sas-l.el ends here
+++ /dev/null
-;;; ess-site.el --- user customization of ESS -*- lexical-binding: t; -*-
-
-;; Copyright (C) 1993 David M. Smith
-;; Copyright (C) 1997--2010 A.J. Rossini, Richard M. Heiberger, Martin
-;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
-;; Copyright (C) 2011--2018 A.J. Rossini, Richard M. Heiberger, Martin
-;; Maechler, Kurt Hornik, Rodney Sparapani, Stephen Eglen,
-;; Vitalie Spinu, and Lionel Henry.
-
-;; Author: David Smith <D.M.SmithNOSPAMlancaster.ac.uk>
-;; Created: 12 Nov 1993
-;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
-;; Keywords: local
-
-;; 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:
-
-;; 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 ess-lisp-directory))
-
-;;; Loading popular dialects (they should become optional in the future)
-
-(require 'ess-r-mode)
-(require 'ess-julia)
-(require 'essd-els) ;; ess-remote
-(require 'ess-stata-mode)
-(require 'ess-sas-d)
-(require 'ess-bugs-d)
-(require 'ess-jags-d)
-(require 'ess-toolbar)
-
-(provide 'ess-site)
-
-;;; ess-site.el ends here
+++ /dev/null
-;;; ess-sp6-d.el --- S-Plus 6 & 7 & 8 customization
-
-;; Copyright (C) 2001--2005 A.J. Rossini, Richard M. Heiberger, Martin
-;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
-
-;; Author: A.J. Rossini <rossiniNOSPAMu.washington.edu>
-;; Created: 2001/02/06
-;; Maintainer: ESS Core Team <ESS-coreNOSPAMr-project.org>
-
-;; Keywords: languages
-
-;; 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:
-
-;; 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-directory-function . S+-directory-function)
- (ess-setup-directory-function . S+-setup-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")
-
-
-
-\f ; Provide package
-
-(provide 'ess-sp6-d)
-
-;;; ess-sp6-d.el ends here
+++ /dev/null
-;;; ess-stata-lang.el --- Stata customization -*- lexical-binding: t; -*-
-
-;; Copyright (C) 1999--2000, Thomas Lumley, A. J. Rossini, Brendan Halpin.
-;; Copyright (C) 1997--2004 A.J. Rossini, Richard M. Heiberger, Martin
-;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
-
-;; Author: Thomas Lumley <thomasNOSPAMbiostat.washington.edu>,
-;; Brendan Halpin <brendanNOSPAMessex.ac.uk>
-;; Created: 2 Nov 1997
-;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
-
-;; Keywords: languages
-
-;; This file is part of ESS (Emacs Speaks Statistics).
-
-;; 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 is based upon Version 0.4 of Stata mode.
-
-;; Stata modes. Emacs modes for using the Stata statistical package
-;; Modified from S-mode, comint-mode
-;;
-;; (c) Thomas Lumley 1997
-;;
-;; version 0.4 20/7/97
-;;
-;; 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.
-;;
-;; (for the GNU GPL see above)
-
-
-;;; Code:
-
-(declare-function ess-help-mode "ess-help")
-
-(require 'make-regexp) ; it's now local to the directory.
-;;(load-library "make-regexp") ;; this is necessary for
-;; ado-set-font-lock-keywords
-;; only needed in Emacs >= 22.x
-(require 'comint)
-(require 'ess-trns)
-
-(defconst ess-help-STA-sec-keys-alist
- '((?d . "Description")
- (?e . "Examples")
- (?o . "Options")
- (?s . "Also see")
- (?S . "Syntax")
- (?r . "Remarks")
- (?t . "Title"))
- "Help section keys.
-`key' indicates the keystroke to use to search for the section heading
-`string' in an Stata help file. `string' is used as part of a
-regexp-search, and so specials should be quoted.
-")
-
-(defconst ess-help-STA-sec-regex "^[A-Z a-z]+:?\n-+\\|http:"
- "Reg(ular) Ex(pression) of section headers in help file.")
-
-(defun ado-set-font-lock-keywords ()
- "Create font lock keywords for Stata syntax. This is from the
-ado-mode of Bill Rising <brisingNOSPAMjhsph.edu>, and uses make-regexp."
- ;; (make-local-variable 'ado-font-lock-keywords)
- (interactive)
- (list
- ;; special highlighting
- ;; program definitions
- (eval-when-compile
- (make-regexps
- '(("^\\*!.*") font-lock-keyword-face)
- ))
- (eval-when-compile
- (make-regexps
- "^"
- '((
- "pr" "pro" "prog" "progr" "progra" "program"
- ) font-lock-keyword-face)
- "[ \t]+"
- '((
- "de" "def" "defi" "defin" "define"
- "di" "dir"
- "drop"
- "l" "li" "lis" "list"
- ) font-lock-type-face nil)
- "[ \t]+"
- '(("[_a-z]+[_a-z0-9]*") font-lock-keyword-face nil)
- ))
- (eval-when-compile
- (make-regexps
- '(("^[ \t]*version") font-lock-reference-face)
- "[ \t]*"
- '(("1.0 2.0 2.1 3.0 3.1 4.0 5.0 6 6.0") font-lock-type-face)
- ))
- (eval-when-compile
- (make-regexps
- "^"
- '(("end" "pause"
- ) font-lock-keyword-face)
- "[ /t]*.*$"
- ))
- ;; delimit command
- (eval-when-compile
- (make-regexps
- '(("^[ \t]*#delimit") font-lock-reference-face)
- "\\s-*"
- '(("\\(cr\\|;\\)\\s-*$") font-lock-type-face nil)
- ))
- ;; set command (with endless options!)
- (eval-when-compile
- (make-regexps
- '(("^[ \t]*set") font-lock-reference-face)
- "[ \t]+"
- '(("adosize" "ANSI"
- "b" "be" "bee" "beep" "checksum" "contents"
- "d" "di" "dis" "disp" "displ" "displa" "display"
- "g" "gr" "gra" "grap" "graph" "graphi" "graphic" "graphics"
- "help"
- "IBM"
- "l" "le" "lev" "leve" "level"
- "linesize"
- "lo" "log"
- "mat" "mats" "matsi" "matsiz" "matsize"
- "maxobs" "maxvar"
- "mem" "memo" "memor" "memory"
- "mo" "mor" "more"
- "obs"
- "ou" "out" "outp" "outpu" "output"
- "pagesize"
- "r" "rm" "rms" "rmsg"
- "se" "see" "seed" "seed0" "shell"
- "te" "tex" "text" "texts" "textsi" "textsiz" "textsize"
- "tr" "tra" "trac" "trace"
- "t" "ty" "typ" "type" "video"
- "vir" "virt" "virtu" "virtua" "virtual"
- )
- font-lock-reference-face t)
- "[ \t]*"
- '(("[a-zA-Z0-9]*") font-lock-type-face)
- ))
- ;; the constraint commands
- (eval-when-compile
- (make-regexps
- "[ \t]+"
- '((
- "cons" "const" "constr" "constra" "constrai" "constrain" "constraint"
- ) font-lock-reference-face)
- "[ \t]+"
- '((
- "d"
- "de" "def" "defi" "defin" "define"
- "di" "dir"
- "drop"
- "l" "li" "lis" "list"
- )
- font-lock-type-face)
- "\\b"
- ))
- ;; the confirm commands - could be a mess!
- (eval-when-compile
- (make-regexps
- "[ \t]+"
- '((
- "conf" "confi" "confir" "confirm"
- ) font-lock-reference-face)
- "[ \t]+"
- '((
- "e" "ex" "exi" "exis" "exist" "existe" "existen" "existenc" "existence"
- "f" "fi" "fil" "file"
- "n" "nu" "num" "numb" "numbe" "number"
- "v" "va" "var" "vari" "varia" "variab" "variabl" "variable"
- ) font-lock-type-face)
- "\\b"
- ))
- (eval-when-compile
- (make-regexps
- "[ \t]+"
- '((
- "conf" "confi" "confir" "confirm"
- ) font-lock-reference-face)
- "[ \t]+"
- '((
- "integer"
- ) font-lock-type-face)
- "[ \t]+"
- '((
- "n" "nu" "num" "numb" "numbe" "number"
- ) font-lock-type-face)
- "\\b"
- ))
- (eval-when-compile
- (make-regexps
- "[ \t]+"
- '((
- "conf" "confi" "confir" "confirm"
- ) font-lock-reference-face)
- "[ \t]+"
- '((
- "n" "ne" "new"
- ) font-lock-type-face)
- "[ \t]+"
- '((
- "f" "fi" "fil" "file"
- "v" "va" "var" "vari" "varia" "variab" "variabl" "variable"
- ) font-lock-type-face)
- "\\b"
- ))
- (eval-when-compile
- (make-regexps
- "[ \t]+"
- '((
- "conf" "confi" "confir" "confirm"
- ) font-lock-reference-face)
- "[ \t]+"
- '((
- "byte" "double" "float" "int" "long"
- "numeric"
- "str" "stri" "strin" "string"
- ) font-lock-type-face)
- "[ \t]+"
- '((
- "v" "va" "var" "vari" "varia" "variab" "variabl" "variable"
- ) font-lock-type-face)
- "\\b"
- ))
- ;;; the str# won't quite look right, but that's the breaks for using
- ;;; a tool like this...
- (eval-when-compile
- (make-regexps
- "[ \t]+"
- '((
- "conf" "confi" "confir" "confirm"
- ) font-lock-reference-face)
- "[ \t]+"
- '((
- "str"
- ) font-lock-type-face)
- "[1-9]+[0-9]*[ \t]+"
- '((
- "v" "va" "var" "vari" "varia" "variab" "variabl" "variable"
- ) font-lock-type-face)
- "\\b"
- ))
- ;; the estimates commands
- (eval-when-compile
- (make-regexps
- "[ \t]+"
- '((
- "est" "esti" "estim" "estima" "estimat" "estimate" "estimates"
- ) font-lock-reference-face)
- "[ \t]+"
- '((
- "clear"
- "di" "dir" "dis" "disp" "displ" "displa" "display"
- "drop"
- "h" "ho" "hol" "hold"
- "li" "lis" "list"
- "loc" "loca" "local"
- "mat" "matr" "matri" "matrix"
- "post"
- "repost"
- "sca" "scal" "scala" "scalar"
- "u" "un" "unh" "unho" "unhol" "unhold"
- )
- font-lock-type-face)
- "\\b"
- ))
- ;; the gph commands
- (eval-when-compile
- (make-regexps
- "[ \t]+"
- '((
- "gph"
- ) font-lock-reference-face)
- "[ \t]+"
- '((
- "arc"
- "box"
- "clear" "close"
- "font"
- "line"
- "open"
- "pen" "point"
- "text"
- "vline" "vpoint" "vpoly" "vtext"
- )
- font-lock-type-face)
- "\\b"
- ))
-
- ;; some of the matrix commands
- (eval-when-compile
- (make-regexps
- "[ \t]+"
- '(("mat" "matr" "matri" "matrix") font-lock-reference-face)
- "[ \t]+"
- '(("ac" "acc" "accu" "accum"
- "cole" "coleq"
- "coln" "colna" "colnam" "cloname" "colnames"
- "d" "def" "defi" "defin" "define"
- "di" "dir" "dispCns" "drop" "drop _all"
- "glsa" "glsac" "glsacc" "glsaccu" "glsaccum"
- "l" "li" "lis" "list" "makeCns" "mlou" "mlout" "post"
- "rowe" "roweq"
- "rown" "rowna" "rownam" "rowname" "rownames"
- "sco" "scor" "score"
- "sub" "subs" "subst" "substi" "substit" "substitu" "substitut" "substitute"
- "svd" "syme" "symei" "symeig" "symeige" "symeigen"
- "veca" "vecac" "vecacc" "vecaccu" "vecaccum"
- )
- font-lock-type-face)
- "\\b"
- ))
- ;; the ml commands
- (eval-when-compile
- (make-regexps
- "[ \t]+"
- '(("ml") font-lock-reference-face)
- "[ \t]+"
- '(("b" "be" "beg" "begi" "begin"
- "check" "count"
- "de" "dep" "depn" "depna" "depnam" "depname" "depnames"
- "di" "dis" "disp" "displ" "displa" "display"
- "f" "fu" "fun" "func" "funct" "functi" "functio" "function"
- "gr" "gra" "grap" "graph"
- "init"
- "max" "maxi" "maxim" "maximi" "maximiz" "maximize"
- "me" "met" "meth" "metho" "method"
- "ml" "mlo" "mlou" "mlout"
- "mo" "mod" "mode" "model"
- "pl" "plo" "plot"
- "po" "pos" "post"
- "q" "qu" "que" "quer" "query"
- "re" "rep" "repo" "repor" "report"
- "sa" "sam" "samp" "sampl" "sample"
- "se" "sea" "sear" "searc" "search"
- "trace")
- font-lock-type-face)
- "\\b"
- ))
- ;; the net commands
- (eval-when-compile
- (make-regexps
- "[ \t]+"
- '(("net") font-lock-reference-face)
- "[ \t]+"
- '((
- "cd"
- "d" "de" "des" "desc" "descr" "descri" "describ" "describe"
- "from" "get" "install"
- "link"
- "q" "qu" "que" "quer" "query")
- font-lock-type-face)
- "\\b"
- ))
- (eval-when-compile
- (make-regexps
- "[ \t]+"
- '(("net") font-lock-reference-face)
- "[ \t]+"
- '(("set") font-lock-reference-face)
- "[ \t]+"
- '(("ado" "other") font-lock-type-face)
- "\\b"
- ))
- (eval-when-compile
- (make-regexps
- "[ \t]+"
- '(("ado") font-lock-reference-face)
- "[ \t]+"
- '(("d" "de" "des" "desc" "descr" "descri" "describ" "describe"
- "dir"
- "uninstall")
- font-lock-type-face)
- "\\b"
- ))
- ;; the reshape commands
- (eval-when-compile
- (make-regexps
- "[ \t]+"
- '(("reshape") font-lock-keyword-face)
- "[ \t]+"
- '((
- "clear"
- "error"
- "i" "j"
- "long"
- "wide"
- "xi" "xij")
- font-lock-type-face)
- "\\b"
- ))
- ;; the return commands
- (eval-when-compile
- (make-regexps
- "[ \t]+"
- '(("ret" "retu" "retur" "return") font-lock-reference-face)
- "[ \t]+"
- '(("add" "clear" "local" "matrix" "scalar") font-lock-type-face)
- "\\b"
- ))
- (eval-when-compile
- (make-regexps
- "[ \t]+"
- '(("sret" "sretu" "sretur" "sreturn") font-lock-reference-face)
- "[ \t]+"
- '(("clear" "local") font-lock-type-face)
- "\\b"
- ))
- ;; the sts commands
- (eval-when-compile
- (make-regexps
- "[ \t]+"
- '(("sts") font-lock-reference-face)
- "[ \t]+"
- '((
- "g"
- "gen" "gene" "gener" "genera" "generat" "generate"
- "gr" "gra" "grap" "graph"
- "l" "li" "lis" "list"
- "t" "te" "tes" "test"
- )
- font-lock-type-face)
- "\\b"
- ))
- ;; the sw commands
- (eval-when-compile
- (make-regexps
- "[ \t]+"
- '(("sw") font-lock-reference-face)
- "[ \t]+"
- '((
- "cloglog" "cnreg" "cox" "ereg" "gamma" "glm" "gompertz" "hetprob"
- "llogist" "lnormal" "logistic" "logit" "ologit" "oprobit"
- "poisson" "probit" "qreg" "reg" "regr" "regre" "regres" "regress"
- "scobit" "tobit" "weibull"
- )
- font-lock-type-face)
- "\\b"
- ))
- ;; the window commands
- (eval-when-compile
- (make-regexps
- "[ \t]+"
- '((
- "win" "wind" "windo" "window"
- ) font-lock-reference-face)
- "[ \t]+"
- '((
- "d"
- "di" "dia" "dial" "dialo" "dialog"
- "dir" "drop"
- "fo" "fop" "fope" "fopen"
- "fs" "fsa" "fsav" "fsave"
- "l" "list"
- "push"
- "stop" "stopb" "stopbo" "stopbox"
- ) font-lock-type-face)
- "\\b"
- ))
- ;; the window controls
- (eval-when-compile
- (make-regexps
- "[ \t]+"
- '((
- "win" "wind" "windo" "window"
- ) font-lock-reference-face)
- "[ \t]+"
- '((
- "c" "co" "con" "cont" "contr" "contro" "control"
- ) font-lock-reference-face)
- '((
- "button" "check" "clear"
- "edit"
- "mcombo" "msimple"
- "radbegin"
- "radend"
- "radio"
- "scombo"
- "ssimple"
- "static"
- ) font-lock-type-face)
- "\\b"
- ))
- ;; the window manage commands
- (eval-when-compile
- (make-regexps
- "[ \t]+"
- '((
- "win" "wind" "windo" "window"
- ) font-lock-reference-face)
- "[ \t]+"
- '((
- "man" "mana" "manag" "manage"
- ) font-lock-reference-face)
- "[ \t]+"
- '((
- "forward"
- "minimize"
- "prefs load"
- "prefs save"
- "prefs default"
- "print graph"
- "print log"
- "restore"
- "update variable"
- )
- font-lock-type-face)
- "\\b"
- ))
- ;; the window menu commands
- (eval-when-compile
- (make-regexps
- "[ \t]+"
- '((
- "win" "wind" "windo" "window"
- ) font-lock-reference-face)
- "[ \t]+"
- '((
- "m" "me" "men" "menu"
- ) font-lock-reference-face)
- "[ \t]+"
- '((
- "append popout"
- "append string"
- "append separator"
- "clear"
- "popout"
- "set"
- )
- font-lock-type-face)
- "\\b"
- ))
- ;; the xwindow commands
- (eval-when-compile
- (make-regexps
- "[ \t]+"
- '((
- "xwin" "xwind" "xwindo" "xwindow"
- ) font-lock-reference-face)
- "[ \t]+"
- '((
- "de" "def" "defi" "defin" "define"
- "di" "dir"
- "drop"
- "l" "li" "lis" "list"
- )
- font-lock-type-face)
- "\\b"
- ))
-
- ;; all the endless Stata keywords (not in a good order)
- ;; first those keywords which must start line
- ;; note that these will look like text if preceded by a comment
- ;; (but comments shouldn't be before the command, anyway)
-
- (eval-when-compile
- (make-regexps
- "^[ \t]+"
- '((
- "cap" "capt" "captu" "captur" "capture"
- "char" "err" "erro" "error" "e" "ex" "exi" "exit"
- "par" "pars" "parse"
- "set"
- ) font-lock-reference-face)
- "\\b"
- ))
- ;; here are some keywords which appear in the middle of lines
- ;; note that the really short abbreviations could make a mess of things
- ;;
- ;; These are split to allow compiling!
- (eval-when-compile
- (make-regexps
- "\\b"
- '((
- "_huber" "_qreg" "_robust"
- "acprplot" "adjust"
- "adopath" "alpha"
- "an" "ano" "anov" "anova" "arch"
- "areg" "arima"
- "as" "ass" "asse" "asser" "assert"
- "avplot" "avplots"
- "bcskew0"
- "be" "bee" "beep"
- "biprobit" "bitest" "bitesti" "blogit"
- "boxcox" "bprobit" "br" "break" "brier"
- "bro" "brow" "brows" "browse"
- "bsqreg" "bstat" "by"
- "canon" "cat" "cc" "cci" "cchart" "centile" "cf" "ci" "cii"
- "clogi" "clogit" "clogitp" "cloglog"
- "close" "cmdtool"
- "cnr" "cnre" "cnreg" "cnsreg" "codebook" "compare"
- "copy"
- "cor" "corc" "corr" "corre" "correl" "correla" "correlat" "correlate"
- "corrgram"
- "cou" "coun" "count"
- "cox" "cprplot" "_crcswxx" "cs" "csi"
- "ct" "ctset" "cttost"
- "cumul" "cusum")
- font-lock-reference-face)
- "\\b"
- ))
- (eval-when-compile
- (make-regexps
- "[ \t]+"
- '((
- "d" "de" "des" "desc" "descr" "descri" "describ" "describe"
- "dfbeta" "dfuller" "di"
- "dir" "dis" "disp" "disp_res" "disp_s"
- "displ" "displa" "display"
- "do" "dotplot"
- "dprobit" "ds" "dstdize" "dwstat"
- "eivreg" "eq" "ereg"
- "fac" "fact" "facto" "factor"
- "fit" "for" "fpredict"
- "fracplot" "fracpoly" "fsl"
- ) font-lock-reference-face)
- "\\b"
- ))
- (eval-when-compile
- (make-regexps
- "[ \t]+"
- '((
- "gettoken" "gladder" "glm" "glmpred" "glogit" "gnbreg" "gompertz"
- "gphdot" "gphpen" "graph" "gprobit" "greigen" "grmeanby"
- "hadimvo" "hausman" "heckman" "heckprob" "hetprob" "hettest" "hilite"
- "hist" "hlu" "hotel"
- "iqreg" "istdize" "iis"
- "ins" "insp" "inspe" "inspec" "inspect"
- "integ" "intreg" "ir" "iri" "ivreg"
- "kap" "kappa" "kapwgt" "kdensity" "ksm" "ksmirnov" "ktau"
- "kwallis"
- ) font-lock-reference-face)
- "\\b"
- ))
- (eval-when-compile
- (make-regexps
- "[ \t]+"
- '((
- "l" "ladder" "lfit" "lincom" "linktest"
- "li" "lis" "list"
- "log"
- "logistic"
- "logi" "logit"
- "loneway" "lookfor"
- "lo" "loo" "look" "looku" "lookup"
- "lpredict" "lroc" "lrtest" "ls" "lsens" "lstat" "ltable" "lv" "lvr2plot"
- "man" "matcproc" "mcc" "mcci"
- "means"
- "mlog" "mlogi" "mlogit"
- "mor" "more"
- "mvreg" "mx_param"
- "n" "nbreg" "newey" "news"
- "nl" "nlinit"
- "no" "noi" "nois" "noisi" "noisil" "noisily"
- "note" "notes"
- "nptrend" "numlist"
- "olog" "ologi" "ologit"
- "ologitp"
- "on" "one" "onew" "onewa" "oneway"
- "oprob" "oprobi" "oprobit"
- "oprobitp"
- "orthog" "orthpoly"
- "ovtest")
- font-lock-reference-face)
- "\\b"
- ))
- (eval-when-compile
- (make-regexps
- "[ \t]+"
- '(("pac" "pchart" "pchi" "pcorr" "pergram"
- "pl" "plo" "plot"
- "pnorm" "poisgof" "poisson" "pperron"
- "prais"
- "prob" "probi" "probit"
- "prtest" "prtesti"
- "pwcorr" "pwd"
- "q" "qchi" "qnorm" "qqplot" "qreg" "quadchk" "quantile"
- "qu" "que" "quer" "query"
- "qui" "quie" "quiet" "quietl" "quietly"
- "ranksum" "rchart" "regdw" "regph"
- "reg" "reg3" "regr" "regre" "regres" "regress" "reshape"
- "rot" "rota" "rotat" "rotate"
- "rreg"
- "run" "runtest" "rvfplot" "rvpplot"
- ) font-lock-reference-face)
- "\\b"
- ))
- (eval-when-compile
- (make-regexps
- "[ \t]+"
- '((
- "sampsi" "sconfirm"
- "sco" "scobit" "scor" "score"
- "sdtest" "sdtesti" "search" "serrbar"
- "sfrancia" "shell" "shelltool" "shewhart" "signrank" "signtest"
- "sktest" "slog" "spearman" "spikeplt" "sqreg"
- "st" "st_is" "st_show" "st_ct"
- "stcox" "stcoxkm" "stcurv" "stdes"
- "stem"
- "stereg" "stir" "stmc" "stmh" "stphplot" "stphtest"
- "strate" "streg"
- "sts" "stse" "stset" "stsum" "stvary" "stweib"
- "su" "sum" "summ" "summa" "summar" "summari" "summariz" "summarize"
- "sureg"
- "svydes" "svyintrg" "svyivreg" "svylc" "svylogit"
- "svymean" "svymean" "svymlog" "svyolog" "svyoprob" "svypois" "svyprobt"
- "svyprop" "svyratio" "svyreg" "svyset" "svytab" "svytest" "svytotal"
- "swilk" "symmetry" "symmi" "symplot" "syntax" "sysdir"
- ) font-lock-reference-face)
- "\\b"
- ))
- (eval-when-compile
- (make-regexps
- "[ \t]+"
- '((
- "ta" "tab"
- "tab1" "tab2"
- "tabdisp"
- "tabi"
- "table"
- "tabu" "tabul" "tabula" "tabulat" "tabulate"
- "te" "tes" "test"
- "testnl" "testparm" "tis"
- "tob" "tobi" "tobit"
- "token" "tokeni" "tokeniz" "tokenize"
- "touch" "tsreport" "tsset" "tsunab" "ttest" "ttesti"
- "ty" "typ" "type"
- "unab" "using"
- "vce"
- "verinst" "vif" "vwls"
- "weibull" "which" "who" "wntestb" "wntestq"
- "xchart" "xcorr"
- "xtclog" "xtdes" "xtgee" "xtgls" "xthaus" "xtintreg"
- "xtlogit" "xtnbreg" "xtpois" "xtprobit"
- "xtrchh" "xtreg" "xtsum" "xttab" "xttest0" "xttobit" "xttrans"
- "zip" "zinb"
- ) font-lock-reference-face)
- "\\b"
- ))
-
- ;; conditional statements
- ;; if might not work right ('cuz it is also a keyword)
- (eval-when-compile
- (make-regexps
- "^[ \t]*\\sw+[ \t]*"
- '(("if"
- ) font-lock-reference-face t t)
- "\\b"
- ))
-
- (eval-when-compile
- (make-regexps
- "^[ \t]*"
- '(("if" "while"
- ) font-lock-reference-face t t)
- "[ \t]+.*{"
- ))
- ;; else statement (which must just have a {)
- (eval-when-compile
- (make-regexps
- "^[ \t]*"
- '(("else"
- ) font-lock-reference-face)
- "[ \t]*{"
- ))
-
- ;; short version of list --- which can get fooled if used as a var
- (eval-when-compile
- (make-regexps
- '(("^[ \t]*l\\b"
- ) font-lock-reference-face)
- ))
-
- ;; all the Stata options
- ;; commonly used options
- (eval-when-compile
- (make-regexps
- "[ \t]+"
- '(("byte" "int" "long" "str[1-9]+[0-9]?" "float" "double"
- "width" "maxobs" "maxvar"
- ) font-lock-type-face)
- "[ \t]+"
- ))
- ;; special local variables (used in parsing)
- (eval-when-compile
- (make-regexps
- "^[ \t]+\\(local\\)+[ \t]+"
- '(("varlist" "exp" "weight" "if" "in" "using" "options"
- ) font-lock-type-face nil t t)
- "\\b"
- ))
-
- ;; things used with display
- ;; since these are often split across lines, and Stata commands are hard
- ;; to delimit, this will highlight even if out of context
-
- (eval-when-compile
- (make-regexps
- "[ \t]+"
- '((
- "_c" "_co" "_con" "_cont" "_conti" "_contin" "_continu" "_continue"
- "_n" "_ne" "_new" "_newl" "_newli" "_newlin" "_newline"
- "_quote"
- "_r" "_re" "_req" "_requ" "_reque" "_reques" "_request"
- )
- font-lock-type-face)
- "\\b"
- ))
- (eval-when-compile
- (make-regexps
- "[ \t]+"
- '((
- "_col" "_colu" "_colum" "_column"
- "_d" "_du" "_dup"
- "_s" "_sk" "_ski" "_skip"
- )
- font-lock-type-face)
- "([1-9]+[0-9]*)\\b"
- ))
- (eval-when-compile
- (make-regexps
- "\\bin[ \t]+"
- '((
- "b" "bl" "blu" "blue"
- "g" "gr" "gre" "gree" "green"
- "r" "re" "red"
- "w" "wh" "whi" "whit" "white"
- "y" "ye" "yel" "yell" "yello" "yellow"
- ) font-lock-type-face)
- "\\b"
- ))
-
- ;; labels
- (eval-when-compile
- (make-regexps
- "[ \t]+"
- '(("lab" "labe" "label"
- ) font-lock-reference-face t)
- "[ \t]+"
- '((
- "da" "dat" "data"
- "de" "def" "defi" "defin" "define"
- "di" "dir"
- "drop"
- "l" "li" "lis" "list"
- "save"
- "val" "valu" "value" "values"
- "var" "vari" "varia" "variab" "variabl" "variable"
- ) font-lock-type-face nil t t)
- "[ \t]"
- ))
-
- ;; all Stata data-altering stuff
- (eval-when-compile
- (make-regexps
- "\\b"
- '((
- "_pctile" "_predict"
- "aorder" "append"
- "bcskew0" "bsample" "bs" "bstrap"
- "cd" "chdir" "clear" "compress"
- "contract" "convert" "cross"
- "dec" "deco" "decod" "decode"
- "discard" "drop" "dydx"
- "ed" "edi" "edit" "egen"
- "en" "enc" "enco" "encod" "encode"
- "erase"
- "expand"
- "fillin"
- "form" "forma" "format"
- "fracgen" "fracpred"
- "g" "ge" "gen" "gene" "gener" "genera" "generat" "generate"
- "gsort"
- "impute"
- "infile" "infix" "input" "insheet" "integ" "ipolate"
- "joinby"
- "keep"
- "lnskew0"
- ) font-lock-keyword-face)
- "\\b"
- ))
- (eval-when-compile
- (make-regexps
- "\\b"
- '((
- "mark" "markout" "marksample"
- "matname"
- "mer" "merg" "merge"
- "mkdir" "mkmat" "mkspline"
- "mleval" "mlmatsum" "mlsum""mlvecsum"
- "modify" "mov" "move"
- "mvdecode" "mvencode" "nlpred" "nobreak" "order"
- "ou" "out" "outf" "outfi" "outfil" "outfile"
- "outs" "outsh" "outshe" "outshee" "outsheet"
- "pctile"
- "post" "postclose" "postfile"
- "pre" "pred" "predi" "predic" "predict"
- "preserve" "range"
- "recast" "recode"
- "ren" "rena" "renam" "rename"
- "renpfix" "replace" "restore" "rm"
- "sappend"
- "sa" "sav" "save"
- "sample" "sdrop"
- "separate"
- "simul" "sinfile" "smerge"
- "smooth" "snapspan"
- "so" "sor" "sort"
- "ssave" "ssort" "stack"
- "stbase" "stfill" "stgen" "stjoin" "stsplit" "sttocc" "sttoct"
- "suse" "svmat"
- "tsfill" "tsrevar"
- "u" "us" "use"
- "xi" "xi:" "xtile" "xpose"
- "xtdata" "xtpred"
- ) font-lock-keyword-face)
- "\\b"
- ))
-
- ;; assignment of macros
- (eval-when-compile
- (make-regexps
- "^[ \t]*"
- '(("global" "local" "scalar"
- ) font-lock-reference-face)
- '(("\\([ \t]+[a-zA-Z_]+[a-zA-Z_0-9]*\\b\\)?"
- ) font-lock-variable-name-face t)
- ))
- ;; choosing temp names
- (eval-when-compile
- (make-regexps
- "^[ \t]*"
- '(("tempname" "tempfile" "tempvar"
- ) font-lock-reference-face)
- '(("\\([ \t]+[a-zA-Z_]+[a-zA-Z_0-9`']*\\)+"
- ) font-lock-type-face t)
- ))
- ;; all variable/macro stuff (put late so it will override)
- ;; internal constants
- (eval-when-compile
- (make-regexps
- "[^a-zA-Z]"
- '(("_merge" "_n" "_pi" "_rc" "_N"
- ) font-lock-variable-name-face)
- "[^a-zA-Z]"
- ))
- ;; some generated vars
- (eval-when-compile
- (make-regexps
- '(("_result([1-9]+)"
- ) font-lock-variable-name-face)
- ))
- ;; global macros
- (eval-when-compile
- (make-regexps
- '(("\\$[a-zA-Z_*]+[a-zA-Z_0-9]*"
- ) font-lock-variable-name-face t)
- ))
- ;; local macros
- (eval-when-compile
- (make-regexps
- "`+"
- '(("[a-zA-Z_`*]+[a-zA-Z_0-9]*" ;has glitch interior ` is highlighted
- ) font-lock-variable-name-face t)
- "'+"
- ))
- ;; other macro commands
- (eval-when-compile
- (make-regexps
- "[ \t]*"
- '((
- "ma" "mac" "macr" "macro"
- ) font-lock-reference-face)
- "[ \t]+"
- '((
- "de" "def" "define"
- "di" "dir"
- "drop"
- "l" "li" "lis" "list"
- "s" "sh" "shi" "shif" "shift"
- )
- font-lock-type-face)
- "[ \t]+"
- ))
- ;; stata 'functions' i.e. things which require () after them
- (eval-when-compile
- (make-regexps
- "\\b"
- '(("_caller"
- "abs" "acos" "asin" "atan" "autocode"
- "Binomial"
- "binorm"
- "chiprob" "comb" "cond" "cos"
- "d" "date" "digamma" "day"
- "dofh" "dofm" "dofq" "dofw" "dofy" "dow" "doy"
- "e" "exp"
- "float" "fprob" "gammap" "get" "group"
- "h" "halfyear" "halfyearly" "hofd"
- "ibeta" "index" "int"
- "invbinomial" "invchi" "invfprob" "invgammap" "invnchi" "invnorm" "invt"
- "length" "ln" "lnfact" "lngamma" "log" "log10" "lower" "ltrim"
- "m" "matrix" "max" "mdy" "min" "missing" "mod" "mofd" "month" "monthly"
- "nchi" "normd" "normprob" "npnchi"
- "q" "qofd" "quarter" "quarterly"
- "r" "real" "recode" "reldif" "replay" "return" "round" "rtrim"
- "s" "scalar" "sign" "sin" "sqrt" "string" "substr" "sum"
- "tan" "tprob" "trigamma" "trim"
- "uniform" "uniform0" "upper"
- "w" "week" "weekly" "wofd"
- "y" "year" "yearly" "yh" "ym" "yofd" "yq" "yw"
- )
- font-lock-reference-face t)
- "("
- ))
- ;; stata 'functions' i.e. things which require [] after them
- (eval-when-compile
- (make-regexps
- "\\b"
- '(("_b" "_coef" "_se")
- font-lock-reference-face t)
- "\\["
- ))
- ;; common Stata options which require a () after them
- (eval-when-compile
- (make-regexps
- "[, \t]+"
- '(("bands" "by" "connect" "density" "gap" "iterate" "ltolerance" "margin"
- "psize" "saving" "tlabel" "tolerance"
- "xlabel" "xscale" "ylabel" "yscale")
- font-lock-type-face t)
- "("
- ))
- ;; egen 'function' options
- (eval-when-compile
- (make-regexps
- "[ \t]*egen[ \t]+.*=[ \t]*"
- '(("count" "diff" "fill" "group" "iqr"
- "ma" "max" "mean" "median" "min" "mtr" "pctile"
- "rank" "rfirst" "rlast" "rmax" "rmean" "rmin" "rmiss" "robs" "rsd" "rsum"
- "sd" "std" "sum")
- font-lock-reference-face t)
- "(.*)"
- ))
- ;; All Custom ado files which are 'reliable' and which are not file killers
- ;; this might be a useless endeavor --- but I cannot generate tag files
- ;; all the s-extensions are listed under Stata's name (since they alter
- ;; data and will be moved to the utils directory
- (eval-when-compile
- (make-regexps
- "[ \t]*"
- '(("addnote" "anypath" "autolab" "checkvar" "ck1icd9" "ckicd9"
- "datetoe" "dattomdy" "den2dem" "dishis" "dtapath" "dupclean" "echo"
- "exdupbil" "ezip2hsa" "getdate" "getlbl" "getnames" "getobs" "gplur"
- "icd9" "issorted" "isfile" "jultoe" "jultof" "jultomdy" "knowndup"
- "labeldir" "linker"
- "markit" "makewide" "missize" "mpcounts"
- "nodups" "notefile" "prov2zip"
- "qcolsum" "qorder"
- "random" "readraw" "readzip" "repart"
- "setup" "stdrate"
- "timeslot"
- "wdatetoe" "wdatomdy" "zip2ezip"
- "_addext" "_brclean" "_brckado" "_brdlog"
- "_ckbad" "_ckdunno" "_ckdupl" "_ckmiss" "_ckok" "_ckwarn"
- "_delimit" "_filenm" "_lookup" "_mk_ck"
- ) font-lock-function-name-face)
- "\\b"
- ))
- ))
-
-
-(defvar ess-STA-mode-font-lock-defaults (ado-set-font-lock-keywords)
- "Set the Stata mode font-lock keywords to Bill Rising's ado-mode keywords.")
-
-(defvar STA-editing-alist
- '((paragraph-start . (concat "[ \t\f]*$\\|" page-delimiter))
- (paragraph-separate . (concat "[ \t\f]*$\\|" page-delimiter))
- (paragraph-ignore-fill-prefix . t)
- (comment-column . 40)
- ;;(comment-indent-function . 'S-comment-indent)
- ;;(ess-comment-indent . 'S-comment-indent)
- ;;(ess-calculate-indent . 'ess-calculate-indent)
- (ess-local-process-name . nil)
- ;;(ess-keep-dump-files . 'ask)
- (font-lock-defaults . '(ess-STA-mode-font-lock-defaults
- nil nil ((?\. . "w")))))
- "General options for editing Stata do and ado source files.")
-
-;; YOU USED TO HAVE TO (with Thomas's version):
-;;;;; Add the following to your .emacs file
-;;
-;;(autoload 'stata "~/ess-sta-l.el" "inferior stata mode" t )
-;;(autoload 'stata-help "stata" "stata help mode" t)
-;;(autoload 'stata-mode "~/ess-sta-l.el" "stata mode" t)
-;;
-;;(if (assoc "\\.do$" auto-mode-alist) nil
-;; (setq auto-mode-alist
-;; (append
-;; '(("\\.do$" . stata-mode)
-;; ("\\.ado$" . stata-mode))
-;; auto-mode-alist)))
-;;
-
-
-;; QUESTIONS TO ASK THOMAS:
-;; 1 - are 'help' and 'lookup' the same?
-;; 2 - what is the point of the review buffer?
-;; 3 - how to quit?
-
-;;
-;; NOTE: all of Thomas's functions have been left here, to be removed
-;; or merged into real locations as we work on this.
-;;
-
-
-;;;;;;;;; Things to change
-
-(defvar stata-switches "-q"
- "Switches to apply to stata invocation.")
-
-(defvar stata-profile "~/.stataprofile"
- "File to read on startup (nil for no file).")
-
-(define-obsolete-function-alias 'stata-help 'ess-display-help-on-object "ESS[15.09]")
-(define-obsolete-function-alias 'stata-lookup 'ess-display-help-apropos "ESS[16.03]")
-
-;; fixme? Hook this on C-c C-s /ess-execute-search does an R search() right now/
-(defun stata-variables ()
- "Stata variable list in other buffer."
- (interactive)
- (let* ((stata-process (get-process "stata"))
- (stata-buffer (if stata-process
- (process-buffer stata-process)
- (error "Stata is not running.")))
- oldpf oldpb oldpm)
- (set-buffer stata-buffer)
- (setq oldpf (process-filter stata-process))
- (setq oldpb (process-buffer stata-process))
- (setq oldpm (marker-position (process-mark stata-process)))
- (save-excursion
- (if stata-process nil (error "Stata is not running."))
- (beginning-of-line)
- (if (looking-at ". ") nil (error "Stata not ready."))
- (save-excursion
- (set-process-buffer stata-process
- (get-buffer-create "*stata variables*"))
- (set-process-filter stata-process 'inferior-ess-ordinary-filter)
- (set-buffer "*stata variables*")
- (setq buffer-read-only nil)
- (erase-buffer)
- (process-send-string stata-process "desc \n ")
- (stata-prompt-wait stata-process)
- (setq buffer-read-only t)
- (set-buffer stata-buffer)
- (set-process-buffer stata-process oldpb)
- (set-marker (process-mark stata-process) oldpm)
- (set-process-filter stata-process oldpf)))
- (display-buffer "*stata variables*")
- (goto-char (point-max))))
-
-(defun stata-prompt-wait (proc &optional start-of-output)
- "Wait for a prompt to appear at BOL of current buffer.
-PROC is the stata process. Does not change point."
- (if start-of-output nil (setq start-of-output (point-min)))
- (save-excursion
- (while (progn
- ;; get output if there is some ready
- (accept-process-output proc 0 50)
- (goto-char (marker-position (process-mark proc)))
- (beginning-of-line)
- (if (< (point) start-of-output) (goto-char start-of-output))
- (not (looking-at "^. "))))))
-
-(cl-defmethod ess--help-major-mode (&context (ess-dialect "stata"))
- (ess-stata-help-mode))
-
-(define-derived-mode ess-stata-help-mode ess-help-mode "Stata help"
- "Major mode for displaying Stata help in a read-only buffer.
-Active commands are Help (\\[stata-help]) and hyperlink
-(\\[stata-rehelp] or mouse-2)."
- :group 'ess-Stata)
-
-;;; Suggested function from Brendan Halpin:
-(defvar ess-STA-delimit-do-file "delimit-do.do")
-
-(defun ess-STA-delimit-do ()
- (save-excursion
- (let ((commands (buffer-substring-no-properties (region-beginning)
- (region-end))))
- (set-buffer (get-buffer-create ess-STA-delimit-do-file))
- (delete-region (point-min) (point-max))
- (insert "#delimit ;\n"
- commands
- "\n#delimit cr\n")
- (write-file ess-STA-delimit-do-file nil)
- (comint-send-string "Stata"
- (format "do %s \n" ess-STA-delimit-do-file)))))
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-
-(provide 'ess-stata-lang)
-
-;;; ess-stata-lang.el ends here
+++ /dev/null
-;;; ess-stata-mode.el --- Stata customization -*- lexical-binding: t; -*-
-
-;; Copyright (C) 1997--1999 A. J. Rossini, Thomas Lumley
-;; Copyright (C) 1997--2004 A.J. Rossini, Richard M. Heiberger, Martin
-;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
-
-;; Author: A.J. Rossini <rossiniNOSPAMbiostat.washington.edu>
-;; Created: 9 Sep 1998
-;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
-
-;; Keywords: languages
-
-;; 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 defines all the Stata customizations for ess-mode. It is somewhat
-;; based on Stata-mode by Thomas Lumley <thomasNOSPAMbiostat.washington.edu>.
-
-;;; Code:
-
-(require 'ess-mode)
-(require 'ess-stata-lang)
-
-(defvar STA-dialect-name "stata"
- "Name of 'dialect' for Stata.");easily changeable in a user's .emacs
-
-(defvar ess-stata-mode-syntax-table
- (let ((tbl (copy-syntax-table ess-mode-syntax-table)))
- (modify-syntax-entry ?\\ "." tbl) ;nullify escape meaning
- (modify-syntax-entry ?\$ "." tbl)
- (modify-syntax-entry ?` "(\'" tbl)
- (modify-syntax-entry ?\' ")`" tbl)
- (modify-syntax-entry ?/ ". 124b" tbl)
- ;; asterisk at bol comments taken care of by
- ;; `syntax-propertize-function'.
- (modify-syntax-entry ?* ". 23b" tbl)
- (modify-syntax-entry ?\n ">" tbl)
- (modify-syntax-entry ?+ "." tbl)
- (modify-syntax-entry ?- "." tbl)
- (modify-syntax-entry ?= "." tbl)
- (modify-syntax-entry ?% "." tbl)
- (modify-syntax-entry ?< "." tbl)
- (modify-syntax-entry ?> "." tbl)
- (modify-syntax-entry ?& "." tbl)
- (modify-syntax-entry ?| "." tbl)
- (modify-syntax-entry ?~ "." tbl)
- tbl)
- "Syntax table for `ess-stata-mode'.")
-
-(defvar STA-customize-alist
- '((ess-local-customize-alist . 'STA-customize-alist)
- (ess-language . "STA")
- (ess-dialect . STA-dialect-name)
- (ess-suffix . "ado")
- (ess-mode-editing-alist . STA-editing-alist)
- (ess-help-sec-regex . ess-help-STA-sec-regex)
- (ess-help-sec-keys-alist . ess-help-STA-sec-keys-alist)
- (ess-loop-timeout . 500000 )
- (ess-object-name-db-file . "ess-sta-namedb.el" )
- (inferior-ess-program . inferior-STA-program)
- (inferior-ess-objects-command . "describe\n")
- (inferior-ess-help-command . "help %s\n") ;; assumes set more off
- (inferior-ess-exit-command . "exit\n")
- ;; --more-- is necessary here (hangs otherwise if startup stata.msg is big)
- (inferior-ess-primary-prompt . "[.:] \\|--more--")
- (inferior-ess-secondary-prompt . ">\\|--more--")
- (inferior-ess-prompt . "\\([.:>] \\|--more--\\)")
- (comint-use-prompt-regexp . t)
- (inferior-ess-search-list-command . "set more off\n search()\n")
- (ess-execute-screen-options-command . "set linesize %s\n")
- (ess-getwd-command . "pwd\n")
- (ess-setwd-command . "cd \"%s\"\n")
- (ess-load-command . "run \"%s\"\n"))
- "Variables to customize for Stata.")
-
-(cl-defmethod ess--help-web-search-override (cmd &context (ess-dialect "stata"))
- "Browse the web for documentation about CMD in Stata."
- (browse-url
- (format
- "https://www.stata.com/search/?q=%s&restrict=&btnG=Search&client=stata&num=&output=xml_no_dtd&site=stata&ie=&oe=UTF-8&sort=&proxystylesheet=stata"
- cmd)))
-
-;;;###autoload
-(define-derived-mode ess-stata-mode ess-mode "ESS[STA]"
- "Major mode for editing Stata source."
- :group 'ess-Stata
- (ess-setq-vars-local STA-customize-alist)
- (setq-local comint-use-prompt-regexp t)
- (setq-local comment-column 40)
- (setq-local comment-end " */")
- (setq-local comment-start "/* ")
- (setq-local comment-start-skip "/\\*+ *")
- (setq-local comment-use-syntax t)
- (setq-local syntax-propertize-function
- (syntax-propertize-rules ("^\\*" (0 "<"))))
- (setq-local paragraph-ignore-fill-prefix t)
- (setq-local paragraph-separate (concat "[ \t\f]*$\\|" page-delimiter))
- (setq-local paragraph-start (concat "[ \t\f]*$\\|" page-delimiter))
- (setq font-lock-defaults '(ess-STA-mode-font-lock-defaults nil nil ((?\. . "w")))))
-
-(defalias 'STA-mode 'ess-stata-mode)
-(defalias 'stata-mode 'ess-stata-mode)
-(defalias 'Stata-mode 'ess-stata-mode)
-
-;;;###autoload
-(add-to-list 'auto-mode-alist '("\\.do\\'" . ess-stata-mode))
-;;;###autoload
-(add-to-list 'auto-mode-alist '("\\.ado\\'" . ess-stata-mode))
-
-
-(defun ess-sta-remove-comments (string)
- "Remove one-line comments before sending the STRING to process.
-
-This function is placed in `ess-presend-filter-functions'."
- (replace-regexp-in-string "/\\*.*\\*/\\|^//.*$" "" string))
-
-;; (ess-sta-remove-comments "aaa /* sdfdsf */ bbb
-;; sdfsd
-;; ccc
-;; // sdfsf
-;; sdf /* sdfdsf */
-;; sdfsf
-;; " )
-
-
-(defvar ess-stata-post-run-hook nil
- "Functions run in process buffer after the initialization of stata process.")
-
-(defun stata (&optional start-args)
- "Call Stata with START-ARGS."
- (interactive "P")
- (ess-write-to-dribble-buffer
- (format "(STA): ess-dialect=%s , buf=%s \n"
- ess-dialect
- (current-buffer)))
- (let* ((sta-start-args
- (concat inferior-STA-start-args
- (when start-args (read-string "Starting Args [possibly -k####] ? "))))
- (inf-buf (inferior-ess sta-start-args STA-customize-alist))
- (inf-proc (get-buffer-process inf-buf)))
- (while (process-get inf-proc 'sec-prompt)
- ;; get read of all --more-- if stata.msg is too long.
- (ess-send-string inf-proc "q")
- (ess-wait-for-process inf-proc t))
- (ess-send-string inf-proc "set more off")
- (goto-char (point-max))
- (with-current-buffer inf-buf
- (add-hook 'ess-presend-filter-functions 'ess-sta-remove-comments nil 'local)
- (run-mode-hooks 'ess-stata-post-run-hook))
- inf-buf))
-
-(defvar inferior-ess-stata-mode-syntax-table
- (let ((tab (copy-syntax-table ess-stata-mode-syntax-table)))
- tab)
- "Syntax table for `inferior-ess-stata-mode'.")
-
-(define-derived-mode inferior-ess-stata-mode inferior-ess-mode "iESS"
- "Inferior `stata' mode."
- :group 'ess-proc
- (ess-setq-vars-local STA-customize-alist)
- (setq comint-prompt-regexp (concat "^" inferior-ess-prompt))
- (setq-local comint-use-prompt-regexp t)
- (setq font-lock-defaults '(ess-STA-mode-font-lock-defaults nil nil ((?\. . "w")))))
-
-
-(define-derived-mode ess-stata-transcript-mode ess-transcript-mode "ESS Transcript"
- "Stata transcript mode."
- :group 'ess-Stata
- :syntax-table ess-stata-mode-syntax-table
- (ess-setq-vars-local STA-customize-alist)
- (setq comint-prompt-regexp (concat "^" inferior-ess-prompt))
- (setq-local comint-use-prompt-regexp t)
- (setq-local comment-column 40)
- (setq-local comment-end " */")
- (setq-local comment-start "/* ")
- (setq-local comment-start-skip "/\\*+ *")
- (setq-local comment-use-syntax t)
- (setq-local paragraph-ignore-fill-prefix t)
- (setq-local paragraph-separate (concat "[ \t\f]*$\\|" page-delimiter))
- (setq-local paragraph-start (concat "[ \t\f]*$\\|" page-delimiter))
- (setq font-lock-defaults '(ess-STA-mode-font-lock-defaults nil nil ((?\. . "w")))))
-
-(defalias 'STA-transcript-mode 'ess-stata-mode-syntax-table)
-
-(defun ess--STA-retrive-topics-from-search ()
- (with-current-buffer (ess-command inferior-ess-search-list-command)
- (goto-char (point-min))
- (let (topics)
- (while (re-search-forward "(help \\(.+?\\)\\( if installed\\| for replacement.*\\)?)$" nil t)
- (setq topics
- (nconc (split-string (match-string-no-properties 1) ",\\|; +")
- topics)))
- (nreverse (delete-dups topics))
- )))
-
-(cl-defmethod ess-help-get-topics (proc &context (ess-dialect "stata"))
- "Return a list of current STA help topics associated with process PROC."
- (or (ess-process-get 'help-topics proc)
- (progn
- (ess-process-put 'help-topics (ess--STA-retrive-topics-from-search))
- (ess-process-get 'help-topics))))
-
-(provide 'ess-stata-mode)
-
-;;; ess-stata-mode.el ends here
+++ /dev/null
-;;; ess-toolbar.el --- Support for a toolbar in ESS. -*- lexical-binding: t; -*-
-
-;; Copyright (C) 1997--2009 A.J. Rossini, Richard M. Heiberger, Martin
-;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
-
-;; Author: Stephen Eglen
-;; Created: 2004-05-06
-;; Revised: 2009-03-16
-;; Maintainer: ESS-core <ESS-core@r-project.org>
-
-;; 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 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
+++ /dev/null
-;; ess-tracebug.el --- Tracing and debugging facilities for ESS. -*- lexical-binding: t; -*-
-;;
-;; Copyright (C) 2011--2017 A.J. Rossini, Richard M. Heiberger, Martin Maechler,
-;; Kurt Hornik, Rodney Sparapani, Stephen Eglen and Vitalie Spinu.
-;;
-;; Filename: ess-tracebug.el
-;; Author: Vitalie Spinu
-;; Maintainer: Vitalie Spinu
-;; Copyright (C) 2010-2012, Vitalie Spinu, all rights reserved.
-;; Created: Oct 14 14:15:22 2010
-;; URL: https://code.google.com/p/ess-tracebug/
-;; Keywords: tools, languages
-;;
-;; This file is *NOT* part of GNU Emacs.
-;;
-;; This program is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License as
-;; published by the Free Software Foundation; either version 3, 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.
-;;
-;; A copy of the GNU General Public License is available at
-;; https://www.r-project.org/Licenses/
-
-;;; 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-when-compile
- (when (< emacs-major-version 26)
- (require 'cl))
- (require 'cl-lib)
- (require 'tramp)
- (require 'subr-x))
-(require 'comint)
-(require 'compile)
-(require 'ring)
-(require 'ess-utils)
-
-(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-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-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-wait-for-process "ess-inf")
-(declare-function ess-switch-to-end-of-ESS "ess-inf" ())
-(declare-function ess-eval-region--normalise-region "ess-inf" )
-(declare-function inferior-ess-run-callback "ess-inf")
-(declare-function inferior-ess--set-status "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-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-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")
-
-
-(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)))
-
-(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."
- (ess-eval-region--normalise-region start end)
- (let* ((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)))
- (t (or (eq ess-inject-source t)
- ;; We need to always inject with namespaced
- ;; evaluation (fixme: not right place for
- ;; this).
- (ess-r-get-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))
-
-(defvar ess-tracebug-help nil
- "ess-dev-map prefix: \\[ess-dev-map]
-
-* 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-kill'
- 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)
-
-* 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'
-
-* Navigation to errors (general Emacs functionality):
-
- C-x `, M-g n . `next-error'
- M-g p . `previous-error'")
-
-
-;; * 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)
- (describe-variable 'ess-tracebug-help))
-
-(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 already not 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 "syan")))
- "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-replace-long+ t
- "Determines if ESS replaces long + sequences in output.
-If 'strip, remove all such instances. Otherwise, if non-nil, '+
-+ + + ' containing more than 4 + is replaced by
-`ess-long+replacement'."
- :group 'ess-tracebug
- :type '(choice (const nil :tag "No replacement")
- (const 'strip :tag "Replace all")
- (const t :tag "Replace 4 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
- (point-at-bol) (point-at-eol))))
- ;; 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)
- (unless (fboundp 'orig-ess-parse-errors)
- (defalias 'orig-ess-parse-errors (symbol-function 'ess-parse-errors))
- (defalias 'ess-parse-errors (symbol-function '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")
- (when (fboundp 'orig-ess-parse-errors)
- (defalias 'ess-parse-errors (symbol-function 'orig-ess-parse-errors))
- (fmakunbound 'orig-ess-parse-errors)))
- (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 to the positions from which `ess--dbg-goto-input-point' is called.
-See the 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 (point-at-bol)))
- (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
- (point-at-bol) (1+ (point-at-eol)) (current-buffer))
- ;; used by overlay-arrow functionality on no-X, should be bol
- (move-marker ess--dbg-current-debug-position (point-at-bol)))
-
-(defun ess--dbg-deactivate-overlays ()
- "Deletes 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)
-
-
-\f
-;;; MPI
-
-;; http://jkorpela.fi/chars/c0.html
-;; https://en.wikipedia.org/wiki/ANSI_escape_code#Escape_sequences
-(defvar ess-mpi-message-start-delimiter "\e_")
-(defvar ess-mpi-message-field-separator "\1e")
-(defvar ess-mpi-message-end-delimiter "\e\\")
-
-(define-obsolete-variable-alias 'ess-mpi-alist 'ess-mpi-handlers "ESS 19.04")
-(defvar ess-mpi-handlers
- '(("message" . 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: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))))
- (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 \eTYPE\1eFIELD...\1d 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 (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)))
- (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."
- (if 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
- (goto-char (point-min))
- (let ((case-fold-search nil))
- (when (re-search-forward "Error\\(:\\| +in\\)" nil t)
- (unless (get-buffer-window pbuf 'visible)
- (display-buffer (process-buffer proc) 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)))
- ;; for debugging in R:accum window in order to see the pointer moving
- ;; (set-window-point (get-buffer-window) tpos)
- (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 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)
- (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 match-selection ;(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 all 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 (point-at-eol))
- ;; 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 (point-at-bol)))
- (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 (+ (point-at-bol) col))
- (back-to-indentation))
- (when (bound-and-true-p org-babel-tangled-file)
- (org-babel-tangle-jump-to-org))
- (list (point-marker) (copy-marker (point-at-eol))))))))))
-
-(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'."
- (let ((dirs (append
- (ess-r-package-source-dirs)
- (cl-loop for d in ess-tracebug-search-path
- append (ess-r-package--all-source-dirs d))))
- buffer name)
- (setq dirs (cons default-directory dirs)) ;; TODO: should be R working dir
- ;; 1. 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
- (or (and (file-name-absolute-p filename)
- (string-match (format "%s\\'" filename) buffer-file-name))
- (equal filename (file-name-nondirectory buffer-file-name))))
- (setq buffer bf)
- (cl-return))))
- ;; 2. 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)))
- ;; 3. Now 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)))))
- ;; 4. Ask for file if not found (tothink: maybe remove this part?)
- (if (and (null buffer)
- 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)))))))
- ;; nil if not found
- 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 (point-at-bol) 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.
-Equivalent to 'n' at the R prompt."
- (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-point-motion-hooks t)
- (inhibit-field-text-motion t))
- (forward-line -1)
- (end-of-line)
- (looking-back "%>%[ \t]*" (point-at-bol)))))
-
-(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)
- (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
- (<= (point-at-bol) (cdr pos))
- (>= (point-at-eol) (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) (point-at-eol))
- (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) (point-at-eol)) (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 (point-at-bol) (+ 1 (point-at-eol)))
- (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 of the form 'assign(\".ess_watch_expressions\", list(a = parse(expr_a), b= parse(expr_b)), envir = .GlobalEnv)'
-ready to be send to R process. 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 (point-at-eol) 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 name and append it to the end of the 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
- (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
+++ /dev/null
-;;; ess-trns.el --- Support for manipulating S transcript files -*- lexical-binding: t; -*-
-
-;; Copyright (C) 1989--1994 Bates, Kademan, Ritter and Smith
-;; Copyright (C) 1997--2010 A.J. Rossini, Richard M. Heiberger, Martin
-;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
-;; Copyright (C) 2011--2012 A.J. Rossini, Richard M. Heiberger, Martin Maechler,
-;; Kurt Hornik, Rodney Sparapani, Stephen Eglen and Vitalie Spinu.
-
-;; Author: David Smith <dsmithNOSPAMstats.adelaide.edu.au>
-;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
-
-;; 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:
-
-;; Code for dealing with ESS transcripts.
-
-;;; Code:
-
-\f ; Requires and autoloads
-
-(require 'ess-mode)
-(require 'ess-inf)
-(require 'comint)
-
-(declare-function ess-display-help-on-object "ess-help" (object &optional command))
-
-\f ; 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
+++ /dev/null
-;;; ess-utils.el --- General Emacs utility functions used by ESS -*- lexical-binding: t; -*-
-
-;; Copyright (C) 1998--2010 A.J. Rossini, Richard M. Heiberger, Martin
-;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
-;; Copyright (C) 2011--2017 A.J. Rossini, Richard M. Heiberger, Martin Maechler,
-;; Kurt Hornik, Rodney Sparapani, Stephen Eglen and Vitalie Spinu.
-
-;; Author: Martin Maechler <maechlerNOSPAMstat.math.ethz.ch>
-;; Created: 9 Sept 1998
-;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
-
-;; This file is part of ESS (Emacs Speaks Statistics).
-
-;; 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.
-
-;;; Code:
-(require 'cl-lib)
-(require 'comint)
-(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")
-
-\f
-;;*;; 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")
-
-\f
-;;*;; 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))
-
-\f
-;;*;; 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)))))
-
-\f
-;;; 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)))
- (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])))
-
-\f
-;;; 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-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)))
-
-(defmacro ess--execute-electric-command (map &optional prompt wait exit-form &rest args)
- "Execute single-key commands defined in MAP till a key is pressed which is not part of 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)
-
-\f
-;;; 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] \\<ess-mode-map>\\[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)
- "Call `ess-yank-cleaned-commands' if ARG is 16.
-With double prefix ARG (\\[universal-argument]
-\\[universal-argument]) call `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!")))))
-
-\f
-;;; 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 <iversonNOSPAMbiostat.wisc.edu>
-
-(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")
-
-\f
-;;; 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))
- "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)))
-
-\f
-;;; 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))))
-
-;;- From: friedmanNOSPAMgnu.ai.mit.edu (Noah Friedman)
-;;- Date: 12 Feb 1995 21:30:56 -0500
-;;- Newsgroups: gnu.emacs.sources
-;;- Subject: nuke-trailing-whitespace
-;;-
-;;- This is too trivial to make into a big todo with comments and copyright
-;;- notices whose length exceed the size of the actual code, so consider it
-;;- public domain. Its purpose is along similar lines to that of
-;;- `require-final-newline', which is built in. I hope the names make it
-;;- obvious.
-
-;; (add-hook 'write-file-hooks 'nuke-trailing-whitespace)
-;;or at least
-;; (add-hook 'ess-mode-hook
-;; (lambda ()
-;; (add-hook 'local-write-file-hooks 'nuke-trailing-whitespace)))
-
-(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))
-
-\f
-;;; 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 (point-at-eol) (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)))
- (when (bound-and-true-p ess--make-local-vars-permanent)
- (put (car pair) 'permanent-local t))) ;; hack for Rnw
- alist))
-
-(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")
-
-(provide 'ess-utils)
-
-;;; ess-utils.el ends here
+++ /dev/null
-;;; ess.el --- Emacs Speaks Statistics -*- lexical-binding: t; -*-
-;;
-;; Author: David Smith <dsmithNOSPAMstats.adelaide.edu.au>
-;; A.J. Rossini <blindglobeNOSPAMgmail.com>
-;; Richard M. Heiberger <rmhNOSPAMtemple.edu>
-;; Kurt Hornik <Kurt.HornikNOSPAMR-project.org>
-;; Martin Maechler <maechlerNOSPAMstat.math.ethz.ch>
-;; Rodney A. Sparapani <rsparapaNOSPAMmcw.edu>
-;; Stephen Eglen <stephenNOSPAMgnu.org>
-;; Sebastian P. Luque <spluqueNOSPAMgmail.com>
-;; Henning Redestig <henning.redNOSPAMgooglemail.com>
-;; Vitalie Spinu <spinuvitNOSPAMgmail.com>
-;; Lionel Henry <lionel.hryNOSPAMgmail.com>
-;; J. Alexander Branham <alex.branhamNOSPAMgmail.com>
-;;
-;; Maintainer: ESS Core Team <ESS-coreNOSPAMr-project.org>
-;; Copyright (C) 1997-2018 ESS Core Team <ESS-coreNOSPAMr-project.org>
-;; Created: 7 Jan 1994
-;; Version: 18.10.3snapshot
-;; URL: https://ess.r-project.org/
-;; Package-Requires: ((emacs "25.1") (julia-mode "0.3"))
-;; ESSR-Version: 1.5
-;;
-;; 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:
-;;
-;; 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)
-
-(defvar reporter-prompt-for-summary-p)
-
-\f
-;; Versions
-
-(defconst ess-version (eval-when-compile
- (require 'lisp-mnt)
- (lm-version (or load-file-name buffer-file-name)))
- "Version of ESS currently loaded.")
-
-(defconst essr-version (eval-when-compile
- (require 'lisp-mnt)
- (save-excursion (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(<from source>) 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 1 (point-at-eol))))))
- (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 "<unknown>"))
- (concat ess-version " [" ess-revision "]")))
-
-\f
-;;; 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-bugsNOSPAMr-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))))))))
-
-
-\f
-;;; Timer
-
-(defcustom ess-idle-timer-interval 1
- "Number of idle 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'.")
-
-\f
-;;; 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
+++ /dev/null
-This is ess.info, produced by makeinfo version 6.5 from ess.texi.
-
-INFO-DIR-SECTION Emacs
-START-INFO-DIR-ENTRY
-* ESS: (ess). Emacs Speaks Statistics (R/S/S+, SAS, BUGS/JAGS and Stata).
-END-INFO-DIR-ENTRY
-
-ESS -- Emacs Speaks Statistics
-******************************
-
-\1f
-File: ess.info, Node: Top, Next: Introduction, Up: (dir)
-
-ESS: Emacs Speaks Statistics
-****************************
-
-ESS version 18.10.3snapshot
-
- 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.
-
- 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.
-
- 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.
-
-* 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::
-
-\1f
-File: ess.info, Node: Introduction, Next: Installation, Prev: Top, Up: Top
-
-1 Introduction to ESS
-*********************
-
-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, _Emacs_ refers to _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
-'ESS[dialect]', where 'dialect' can take values such as 'R', 'SAS', or
-'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 ('iESS'), and are shown in the modeline by 'iESS
-[dialect]'.
-
- Currently, the documentation contains many references to ''R'' where
-actually any supported (statistics) language is meant, i.e., 'R' could
-also mean 'S' or 'SAS.'
-
- 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.
-
- No special knowledge of Emacs is necessary when using R interactively
-under ESS.
-
- 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
-
-\1f
-File: ess.info, Node: Features, Next: New features, Up: Introduction
-
-1.1 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 <https://www.gnu.org/philosophy/free-sw.html>.
-
-* Menu:
-
-* Current Features::
-
-\1f
-File: ess.info, Node: Current Features, Up: Features
-
-1.1.1 Features Overview
------------------------
-
- * Languages Supported:
- * S family (R, S, and S+ AKA S-PLUS)
- * SAS
- * BUGS/JAGS
- * Stata
- * Julia
- * Editing source code (S family, SAS, BUGS/JAGS, Stata, Julia)
- * Syntactic indentation and highlighting of source code
- * Partial evaluation of code
- * Loading and error-checking of code
- * Source code revision maintenance
- * Batch execution (SAS, BUGS/JAGS)
- * Use of imenu to provide links to appropriate functions
- * Interacting with the process (S family, SAS, Stata, Julia)
- * Command-line editing
- * Searchable Command history
- * Command-line completion of S family object names and file
- names
- * Quick access to object lists and search lists
- * Transcript recording
- * Interface to the help system
- * Transcript manipulation (S family, Stata)
- * Recording and saving transcript files
- * Manipulating and editing saved transcripts
- * Re-evaluating commands from transcript files
- * Interaction with Help Pages and other Documentation (R)
- * Fast Navigation
- * Sending Examples to running ESS process.
- * Fast Transfer to Further Help Pages
- * Help File Editing (R)
- * Syntactic indentation and highlighting of source code.
- * Sending Examples to running ESS process.
- * Previewing
-
- For source code buffers, ESS offers several features:
-
- * Support for multiple indentation styles R code *Note Indenting::.
-
- * Facilities for loading and error-checking source files, including a
- keystroke to jump straight to the position of an error in a source
- file. *Note Error Checking::.
-
- * Source code revision maintenance, which allows you to keep historic
- versions of R source files. *Note Source Files::.
-
- * Facilities for evaluating R code such as portions of source files,
- or line-by-line evaluation of files (useful for debugging). *Note
- Evaluating code::.
-
- 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:
-
- * Command-line editing for fixing mistakes in commands before they
- are entered. *Note Command-line editing::.
-
- * Searchable command history for recalling previously-submitted
- commands. *Note Command History::.
-
- * Command-line completion of both object and file names for quick
- entry. *Note Completion::.
-
- * Hot-keys for quick entry of commonly-used commands in 'R' such as
- 'objects()', and 'search()'. *Note Hot keys::.
-
- * Transcript recording for a complete record of all the actions in an
- R session. *Note Transcript::.
-
- * Interface to the help system, with a specialized mode for viewing R
- help files. *Note Help::.
-
- * 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. *Note Edit
- buffer::.
-
- Finally, ESS provides features for re-submitting commands from saved
-transcript files, including:
-
- * Evaluation of previously entered commands, stripping away
- unnecessary prompts. *Note Transcript resubmit::.
-
-\1f
-File: ess.info, Node: New features, Next: Credits, Prev: Features, Up: Introduction
-
-1.2 New features in ESS
-=======================
-
-Changes and New Features in 19.04 (unreleased):
-
- * 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
- <language>-mode-hook and <language>-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. See
- *Note (ess)Controlling buffer display:: for more information and
- examples.
-
- * '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.
-
- * 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.
-
- 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 <https://github.com/polymode/poly-R/>,
- <https://polymode.github.io/>, or markdown-mode with edit-indirect
- <https://jblevins.org/projects/markdown-mode>.
-
- * 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" <ess-config-here>)' 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. *Note (ess)Activating and Loading ESS:: for more
- information on this feature.
-
- * 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
-
-\1f
-File: ess.info, Node: Credits, Next: Manual, Prev: New features, Up: Introduction
-
-1.3 Authors of and contributors to ESS
-======================================
-
-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.
-
- * The multiple process code, and the idea for
- 'ess-eval-line-and-next-line' are by Rod Ball.
-
- * Thanks to Doug Bates for many useful suggestions.
-
- * Thanks to Martin Maechler for reporting and fixing bugs, providing
- many useful comments and suggestions, and for maintaining the ESS
- mailing lists.
-
- * Thanks to Frank Ritter for updates, particularly the menu code, and
- invaluable comments on the manual.
-
- * Thanks to Ken'ichi Shibayama for his excellent indenting code, and
- many comments and suggestions.
-
- * Thanks to Aki Vehtari for adding interactive BUGS support.
-
- * Thanks to Brendan Halpin for bug-fixes and updates to Stata-mode.
-
- * Last, but definitely not least, thanks to the many ESS users and
- contributors to the ESS mailing lists.
-
- _ESS_ is being developed and currently maintained by
-
- * A.J. Rossini (mailto:blindglobeNOSPAMgmail.com)
- * Richard M. Heiberger (mailto:rmhNOSPAMtemple.edu)
- * Kurt Hornik (mailto:Kurt.HornikNOSPAMR-project.org)
- * Martin Maechler (mailto:maechlerNOSPAMstat.math.ethz.ch)
- * Rodney A. Sparapani (mailto:rsparapaNOSPAMmcw.edu)
- * Stephen Eglen (mailto:stephenNOSPAMgnu.org)
- * Sebastian P. Luque (mailto:spluqueNOSPAMgmail.com)
- * Henning Redestig (mailto:henning.redNOSPAMgooglemail.com)
- * Vitalie Spinu (mailto:spinuvitNOSPAMgmail.com)
- * Lionel Henry (mailto:lionel.hryNOSPAMgmail.com)
- * J. Alexander Branham (mailto:alex.branhamNOSPAMgmail.com)
-
-\1f
-File: ess.info, Node: Manual, Prev: Credits, Up: Introduction
-
-1.4 How to read this manual
-===========================
-
-If you need to install ESS, read *note 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 'C-h t'.
-
- In this manual we use the standard notation used by Emacs for
-describing the keystrokes used to invoke certain commands. 'C-<chr>'
-means hold the CONTROL key while typing the character <chr>. 'M-<chr>'
-means hold the META key (usually ALT) down while typing <chr>. If there
-is no META, EDIT or ALT key, instead press and release the ESC key and
-then type <chr>.
-
- All ESS commands can be invoked by typing '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 'M-x R' can accept an optional 'prefix'
-argument. To specify the prefix argument, you would type 'C-u' before
-giving the command. For example, if you type '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 'C-h f'. For example, if you type 'C-h f
-ess-eval-region', documentation for that command will appear in a
-separate *Help* buffer. Second, '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
-'M-x customize-group RET ess RET' to get started. *note 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.
-
-\1f
-File: ess.info, Node: Installation, Next: Interactive ESS, Prev: Introduction, Up: Top
-
-2 Installing ESS on your system
-*******************************
-
-ESS 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.
-
- 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 *note Activating and Loading ESS:: for more details.
-
-* Menu:
-
-* Installing from a third-party repository::
-* Installing from source::
-* Activating and Loading ESS::
-* Check Installation::
-
-\1f
-File: ess.info, Node: Installing from a third-party repository, Next: Installing from source
-
-2.1 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 MELPA's website (https://melpa.org/).
-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 *note Activating and Loading ESS::.
-Depending on install method, this may be taken care of automatically.
-
-\1f
-File: ess.info, Node: Installing from source, Next: Activating and Loading ESS, Prev: Installing from a third-party repository
-
-2.2 Installing from source
-==========================
-
-Stable versions of ESS are available at the ESS web page
-(https://ess.r-project.org) as a .tgz file or .zip file. ESS releases
-are GPG-signed, you should check the signature by downloading the
-accompanying '.sig' file and doing:
-
- gpg --verify ess-18.10.tgz.sig
-
- Alternatively, you may download the git repository. ESS is currently
-hosted on GitHub: <https://github.com/emacs-ess/ESS>. 'git clone
-https://github.com/emacs-ess/ESS.git' will download it to a new
-directory 'ESS' in the current working directory.
-
- We will refer to the location of the ESS source files as
-'/path/to/ESS/' hereafter.
-
- After installing, users should make sure they activate or load ESS in
-each Emacs session, see *note Activating and Loading ESS::
-
- Optionally, compile elisp files, build the documentation, and the
-autoloads:
- cd /path/to/ESS/
- make
- 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 'make install'. You might need
-administrative privileges:
-
- make install
-
- The files are installed into '/usr/share/emacs' directory. For this
-step to run correctly on macOS, you will need to adjust the 'PREFIX'
-path in 'Makeconf'. The necessary code and instructions are commented
-in that file.
-
-\1f
-File: ess.info, Node: Activating and Loading ESS, Next: Check Installation, Prev: Installing from source
-
-2.3 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 *note Check Installation::
-
- Otherwise, you may need to add the path to ESS to 'load-path' with:
-
- (add-to-list 'load-path "/path/to/ESS/lisp")
-
- 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 'make'):
-
- (load "ess-autoloads")
-
- To require ESS on startup, you can either put
-
- (require 'ess-site)
-
- or
-
- (require 'ess-r-mode)
-
- In your configuration file, depending on whether you want all ESS
-features or only R related features.
-
-\1f
-File: ess.info, Node: Check Installation, Prev: Activating and Loading ESS
-
-2.4 Check Installation
-======================
-
-Restart Emacs and check that ESS was loaded from a correct location with
-'M-x ess-version'.
-
-\1f
-File: ess.info, Node: Interactive ESS, Next: Entering commands, Prev: Installation, Up: Top
-
-3 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::
-
-\1f
-File: ess.info, Node: Starting up, Next: Multiple ESS processes, Up: Interactive ESS
-
-3.1 Starting an ESS process
-===========================
-
-To start an inferior R session on GNU/Linux, macOS, or Windows using the
-Cygwin bash shell, simply type 'M-x R RET'. To start an R session on
-Windows when you use the MSDOS/powershell shell, simply type 'M-x
-S+6-msdos RET'. R will then (by default) ask the question
-
- R starting data directory?
-
-Enter the name of the directory you wish to have as the working
-directory (that is, the directory you wish to have 'getwd()' return if
-using R).
-
- You will then be popped into a buffer named '*R*' which will be used
-for interacting with the ESS process, and you can start entering
-commands.
-
-\1f
-File: ess.info, Node: Multiple ESS processes, Next: ESS processes on Remote Computers, Prev: Starting up, Up: Interactive ESS
-
-3.2 Running more than one ESS process
-=====================================
-
-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
-(process 1) is simply named 'R'. If you call 'M-x R' again without
-killing the first R process, ESS will start a second R process with the
-name 'R:2'. To have the first buffer named 'R:1', customize the option
-'ess-plain-first-buffername'. With a prefix argument, 'C-u M-x R'
-allows for the specification of command line options.
-
- -- User Option: ess-plain-first-buffername
- If non-'nil', name the first iESS process [R]. Otherwise, name it
- [R:1].
-
- You can switch to any active ESS process with the command '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.
-
-\1f
-File: ess.info, Node: ESS processes on Remote Computers, Next: Customizing startup, Prev: Multiple ESS processes, Up: Interactive ESS
-
-3.3 ESS processes on Remote Computers
-=====================================
-
-3.3.1 ESS and TRAMP
--------------------
-
-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 *Note (tramp)Top::.
-
- Start an ssh session using TRAMP with '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 ('R', 'Julia', 'stata' etc) as you would
-usually do on local machine: 'M-x R'.
-
- Alternatively you can start your process normally ('M-x R'). When
-asked for starting directory, simply type '/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
-'.ssh/' folder and add an account. For example if you use amazon EC2,
-it might look like following:
-
- Host amazon
- Hostname ec2-54-215-203-181.us-west-1.compute.amazonaws.com
- User ubuntu
- IdentityFile ~/.ssh/my_amazon_key.pem
- ForwardX11 yes
-
- With this configuration '/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
-
-3.3.2 ESS-remote
-----------------
-
-TRAMP is the recommended way of starting a remote session. The other
-way to start a remote ESS connection is through 'ess-remote'.
-
- 1. Start a new shell, telnet or ssh buffer and connect to the remote
- computer (e.g. use, 'M-x shell', 'M-x telnet' or 'M-x ssh'; ssh.el
- is available at
- <https://www.splode.com/~friedman/software/emacs-lisp/src/ssh.el>).
-
- 2. Start the ESS process on the remote machine, for example with one
- of the commands 'R', 'Splus', or 'sas -stdio'.
-
- 3. Start '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 ('C-c C-n' and its relatives) now work
- with the R language processes. For SAS you need to use a different
- command 'C-c i' (that is a regular 'i', not a 'C-i') to send lines
- from your 'myfile.sas' to the remote SAS process. 'C-c i' sends
- lines over invisibly. 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.
-
- 4. Graphics (interactive) on the remote machine. If you run X11
- (*Note X11::, X Windows) on both the local and remote machines then
- you should be able to display the graphs locally by setting the
- 'DISPLAY' environment variable appropriately. Windows users can
- download 'xfree86' from cygwin.
-
- 5. 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 '.gif' and '.jpg' files. Otherwise, a
- graphics file viewer will be needed. Ghostscript/ghostview may be
- downloaded to display '.ps' and '.eps' files. Viewers for GIF and
- JPEG are usually included with operating systems. *Note
- ESS(SAS)--Function keys for batch processing::, for more
- information on using the F12 key for displaying graphics files with
- SAS.
-
- Should you or a colleague inadvertently start a statistical process
-in an ordinary '*shell*' buffer, the 'ess-remote' command can be used to
-convert it to an ESS buffer and allow you to use the ESS commands with
-it.
-
-\1f
-File: ess.info, Node: Customizing startup, Next: Controlling buffer display, Prev: ESS processes on Remote Computers, Up: Interactive ESS
-
-3.4 Changing the startup actions
-================================
-
-If you do not wish ESS to prompt for a starting directory when starting
-a new process, set the variable 'ess-ask-for-ess-directory' to 'nil'.
-In this case, the starting directory will be set using one of the
-following methods:
-
- 1. If the variable 'ess-directory-function' stores the name of a
- function, the value returned by this function is used. The default
- for this variable is nil.
-
- 2. Otherwise, if the variable 'ess-directory' stores the name of a
- directory (ending in a slash), this value is used. The default for
- this variable is nil.
-
- 3. Otherwise, the working directory of the current buffer is used.
-
- If 'ess-ask-for-ess-directory' has a non-'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,
-'ess-directory' is an ideal variable to set in 'ess-pre-run-hook'.
-
- You may also customize 'ess-post-run-hook' and the dialect-specific
-'ess-*-post-run-hook' variables. For example, you may want to use
-'ess-load-file' to load a file when ESS starts R:
-
- (add-hook 'ess-r-post-run-hook (lambda () (ess-load-file "foo.R")))
-
- If you like to keep a record of your R actions, set the variable
-'ess-ask-about-transfile' to 't', and you will be asked for a filename
-for the transcript before the ESS process starts.
-
- -- User Option: ess-ask-about-transfile
- If non-'nil', ask for a file name in which to save the session
- transcript.
-
- 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 '.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 --
-*note Saving transcripts::.)
-
- Once these questions are answered (if they are asked at all) the
-inferior process itself is started. If you need to pass any arguments
-to this program, they may be specified in the variable
-'inferior-S_PROGRAM_NAME-args'. For example, if 'inferior-ess-program'
-is '"R"' then the variable to set is 'inferior-R-args'. It is not
-normally necessary to pass arguments to the iESS program; in particular
-do not pass the '-e' option to 'Splus', since ESS provides its own
-command history mechanism.
-
- ESS can set the width option of inferior processes automatically when
-the window configuration changes. To do so, set '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 'ess-auto-width-visible' to a
-non-nil value.
-
-\1f
-File: ess.info, Node: Controlling buffer display, Prev: Customizing startup, Up: Interactive ESS
-
-3.5 Controlling buffer display
-==============================
-
-Users can control how buffers are displayed by customizing
-'display-buffer-alist', *Note (emacs)Window Choice::. 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; '*R Dired*' would match '*R' if it
-came before in the alist.
-
- (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))))
-
- 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. *Note (elisp)Buffer Display Action
-Alists:: for a detailed description of 'reusable-frames'.
-
- (setq display-buffer-alist
- '(("*R"
- (display-buffer-reuse-window display-buffer-pop-up-frame)
- (reusable-frames . 0))))
-
- 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. *Note
-(elisp)Dedicated Windows::. For example, this prevents help buffers
-from being displayed in the window showing the inferior R process.
-
- (setq display-buffer-alist
- '(("*R"
- nil
- (dedicated . t))))
-
- 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:
-
- (setq display-buffer-alist
- '(("*R" . ((display-buffer-same-window) (inhibit-same-window . nil)))
- ("\\.R$" . ((display-buffer-same-window) (inhibit-same-window . nil)))))
-
-\1f
-File: ess.info, Node: Entering commands, Next: Evaluating code, Prev: Interactive ESS, Up: Top
-
-4 Interacting with the ESS process
-**********************************
-
-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 _inferior_ buffer,
-which has an active 'inferior-ess-mode'. The features of inferior R
-mode are similar to those provided by the standard Emacs shell mode
-(*note (emacs)Shell Mode::). 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
-
-\1f
-File: ess.info, Node: Command-line editing, Next: Transcript, Up: Entering commands
-
-4.1 Entering commands and fixing mistakes
-=========================================
-
-Sending a command to the ESS process is as simple as typing it in and
-pressing the <RETURN> key:
-
- -- Command: inferior-ess-send-input
- 'RET' Send the command on the current line to the ESS process.
-
- If you make a typing error before pressing 'RET' all the usual Emacs
-editing commands are available to correct it (*note Basic:
-(emacs)Basic.). Once the command has been corrected you can press
-<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:
-
-'C-c C-w'
- 'backward-kill-word' Deletes the previous word (such as an object
- name) on the command line.
-
-'C-c C-u'
- '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.
-
-'C-a'
- 'comint-bol' Move to the beginning of the line, and then skip
- forwards past the prompt, if any.
-
- *Note (emacs)Shell Mode::, for other commands relevant to entering
-input.
-
-\1f
-File: ess.info, Node: Transcript, Next: Command History, Prev: Command-line editing, Up: Entering commands
-
-4.2 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 move back up
-through the buffer, to look at the output from previous commands for
-example.
-
- Within the process buffer, a paragraph is defined as the prompt, the
-command after the prompt, and the output from the command. Thus 'M-{'
-and 'M-}' move you backwards and forwards, respectively, through
-commands in the transcript. A particularly useful command is 'M-h'
-('mark-paragraph') which will allow you to mark a command and its entire
-output (for deletion, perhaps). For more information about paragraph
-commands, *note Paragraphs: (emacs)Paragraphs.
-
- 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 ('^L') character.
-Thus pages in the ESS process buffer correspond to ESS sessions. Thus,
-for example, you may use 'C-x [' and 'C-x ]' to move backward and
-forwards through ESS sessions in a single ESS process buffer. For more
-information about page commands, *note Pages: (emacs)Pages.
-
-* 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
-
-\1f
-File: ess.info, Node: Last command, Next: Process buffer motion, Up: Transcript
-
-4.2.1 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:
-
- '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 'comint-scroll-to-bottom-on-input' to 't' or ''this'. If the
-first part of the output is still not visible, use 'C-c C-r'
-('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 'C-c C-o' ('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.
-
-\1f
-File: ess.info, Node: Process buffer motion, Next: Transcript resubmit, Prev: Last command, Up: Transcript
-
-4.2.2 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:
-
-'C-c C-p'
- 'comint-previous-prompt' Moves point to the preceding prompt in the
- process buffer.
-
-'C-c C-n'
- 'comint-next-prompt' Moves point to the next prompt in the process
- buffer.
-
-Note that these two commands are analogous to 'C-p' and 'C-n' but apply
-to command lines rather than text lines. And just like 'C-p' and 'C-n',
-passing a prefix argument to these commands means to move to the ARG'th
-next (or previous) command. (These commands are also discussed in *note
-Shell History Copying: (emacs)Shell History Copying.)
-
- 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 (*note Syntax of Regular Expression:
-(emacs)Regexps.), and then moves to the next (previous) command matching
-the pattern.
-
-'comint-backward-matching-input regexp arg'
-'comint-forward-matching-input regexp arg'
- Search backward (forward) through the transcript buffer for the
- ARG'th previous (next) command matching REGEXP. ARG is the prefix
- argument; REGEXP is prompted for in the minibuffer.
-
-\1f
-File: ess.info, Node: Transcript resubmit, Next: Saving transcripts, Prev: Process buffer motion, Up: Transcript
-
-4.2.3 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 _output_, an error is
-signaled). Note all commands involve the <RETURN> key.
-
-'RET'
- 'inferior-ess-send-input' *Note Command-line editing::.
-
-'C-c RET'
- '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.
-
- When the cursor is not after the current prompt, the <RETURN> key has
-a slightly different behavior than usual. Pressing '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 '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 '+' instead of '>') -- 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 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 *note
-Command History::.
-
-\1f
-File: ess.info, Node: Saving transcripts, Prev: Transcript resubmit, Up: Transcript
-
-4.2.4 Keeping a record of your R session
-----------------------------------------
-
-To keep a record of your R session in a disk file, use the Emacs command
-'C-x C-w' ('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 '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 'ess-ask-about-transfile' to
-'t'; *Note Customizing startup::. For R files, naming transcript files
-'*.Rout' puts them in a special mode (ESS transcript mode -- *note
-Transcript Mode::) for editing transcript files which is automatically
-selected for files with this suffix.
-
- R transcripts can get very large, so some judicious editing is
-appropriate if you are saving it in a file. Use '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
-'M-h C-w'. Also, remember that '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 'ess-transcript-clean-region' to strip output from a
-transcript, leaving only source code suitable for inclusion in files
-'source()'-able from R. *note Transcript Mode: Clean.
-
-\1f
-File: ess.info, Node: Command History, Next: History expansion, Prev: Transcript, Up: Entering commands
-
-4.3 Command History
-===================
-
-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 'comint-input-ring-size' in
-'inferior-ess-mode-hook'.) The simplest history commands simply select
-the next and previous commands in the input history:
-
-'M-p'
- 'comint-previous-input' Select the previous command in the input
- history.
-
-'M-n'
- 'comint-next-input' Select the next command in the input history.
-
-For example, pressing '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 '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 (*note Syntax of Regular
-Expression: (emacs)Regexps.), to search for a particular variable name
-for example, these commands are also available:
-
-'M-r'
- 'comint-history-isearch-backward-regexp' Prompt for a regular
- expression, and search backwards through the input history for a
- command matching the expression.
-
-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:
-
-'C-c M-r'
- 'comint-previous-matching-input-from-input' Select the previous
- command in the history which matches the string typed so far.
-
-'C-c M-s'
- 'comint-next-matching-input-from-input' Select the next command in
- the history which matches the string typed so far.
-
-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 'attach()' command,
-you may only need to type 'att' and then 'C-c M-r' and 'RET'.
-
- *Note Shell History Ring: (emacs)Shell Ring, for a more detailed
-discussion of the history mechanism, and do experiment with the 'In/Out'
-menu to explore the possibilities.
-
- Many ESS users like to have even easier access to these, and
-recommend to add something like
- (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)
- ))
- to your Emacs configuration file, where the last two settings are
-typically desirable for the situation where you work with a script (for
-example, 'code.R') and send code chunks to the process buffer (e.g.
-'*R*'). Note however that these settings influence all 'comint'-using
-Emacs modes, not just the ESS ones, and for that reason, these
-customization cannot be part of 'ESS' itself.
-
-* Menu:
-
-* Saving History::
-
-\1f
-File: ess.info, Node: Saving History, Up: Command History
-
-4.3.1 Saving the command history
---------------------------------
-
-The 'ess-history-file' variable, which is 't' by default, together with
-'ess-history-directory', governs if and where the command history is
-saved and restored between sessions. By default,
-'ess-history-directory' is '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:
-
- (setq ess-history-file nil)
-
-or if you prefer only one global command history file:
-
- (setq ess-history-directory "~/.R/")
-
-in your Emacs configuration file.
-
-\1f
-File: ess.info, Node: History expansion, Next: Hot keys, Prev: Command History, Up: Entering commands
-
-4.4 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 'csh'. History references are introduced by a '!' or '^' character
-and have meanings as follows:
-
-'!!'
- The immediately previous command
-
-'!-N'
- The Nth previous command
-
-'!text'
- The last command beginning with the string 'text'
-
-'!?text'
- The last command containing the string 'text'
-
- In addition, you may follow the reference with a "word designator" to
-select particular "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 'comint-delimiter-argument-list' to a list of
-characters that are allowed to separate words and themselves form
-words.) Words are numbered beginning with zero. The word designator
-usually begins with a ':' (colon) character; however it may be omitted
-if the word reference begins with a '^', '$', '*' or '-'. If the word
-is to be selected from the previous command, the second '!' character
-can be omitted from the event specification. For instance, '!!:1' and
-'!:1' both refer to the first word of the previous command, while '!!$'
-and '!$' both refer to the last word in the previous command. The
-format of word designators is as follows:
-
-'0'
- The zeroth word (i.e. the first one on the command line)
-
-'N'
- The Nth word, where N is a number
-
-'^'
- The first word (i.e. the second one on the command line)
-
-'$'
- The last word
-
-'X-Y'
- A range of words; '-Y' abbreviates '0-Y'
-
-'*'
- All the words except the zeroth word, or nothing if the command had
- just one word (the zeroth)
-
-'X*'
- Abbreviates X-$
-
-'X-'
- Like 'X*', but omitting the last word
-
- In addition, you may surround the entire reference except for the
-first '!' 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
-'^old^new^' means "the last command, but with the first occurrence of
-the string 'old' replaced with the string 'new'" (the last '^' is
-optional). Similarly, '^old^' means "the last command, with the first
-occurrence of the string 'old' deleted" (again, the last '^' is
-optional).
-
- To convert a history reference as described above to an input
-suitable for R, you need to "expand" the history reference, using the
-<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 'SPC TAB'. This will convert the history
-reference into an R command from the history, which you can then edit or
-press <RET> to execute.
-
- For example, to execute the last command that referenced the variable
-'data', type '!?data SPC TAB RET'.
-
-\1f
-File: ess.info, Node: Hot keys, Next: Statistical Process running in ESS?, Prev: History expansion, Up: Entering commands
-
-4.5 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 'objects()' or '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:
-
- -- User Option: ess-execute-in-process-buffer
- If non-'nil', means that these commands will produce their output
- in the process buffer instead.
-
- In any case, passing a prefix argument to the commands (with 'C-u')
-will reverse the meaning of '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:
-
- -- Command: ess-execute-objects POSN
- 'C-c C-x' Sends the 'objects()' command to the ESS process. A
- prefix argument specifies the position on the search list (use a
- negative argument to toggle '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 POSN gets the objects
- for that position, as well as toggling
- 'ess-execute-in-process-buffer'.
-
- -- Command: ess-execute-search INVERT
- 'C-c C-s' Sends the 'inferior-ess-search-list-command' command to
- the 'ess-language' process; 'search()' in R. Prefix INVERT toggles
- 'ess-execute-in-process-buffer'.
-
- '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; *note
-Keyboard Macros: (emacs)Keyboard Macros.
-
- The following hot keys do not use '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:
-
- -- Command: ess-load-file FILENAME
- 'C-c M-l' Prompts for a file (FILENAME) to load into the ESS
- process using 'source()'. If there is an error during loading, you
- can jump to the error in the file with the following function.
-
- -- Command: ess-parse-errors ARG RESET
- Visits next '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 ARG specifies
- how many error messages to move; negative means move back to
- previous error messages. Just 'C-u' as a prefix means reparse the
- error message buffer and start at the first error. The RESET
- argument specifies restarting from the beginning.
-
- *Note Error Checking::, for more details.
-
- -- Command: ess-display-help-on-object OBJECT COMMAND
- 'C-c C-v' Pops up a help buffer for an R object or function. If
- COMMAND is supplied, it is used instead of
- 'inferior-ess-help-command'. See *note Help:: for more details.
-
- -- Command: ess-quit
- 'C-c C-q' Issue an exiting command to the inferior process,
- additionally also running '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 '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.
-
-\1f
-File: ess.info, Node: Statistical Process running in ESS?, Next: Emacsclient, Prev: Hot keys, Up: Entering commands
-
-4.6 Is the Statistical Process running under ESS?
-=================================================
-
-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 'options(STERM="iESS")' for R language processes running in
-an inferior 'iESS[S]' or 'iESS[R]' buffer.
-
- ESS sets '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 'ddeESS[S]' buffer.
-
- Other values of 'options()$STERM' that we recommend are:
-
- * 'length': Fixed length xterm or telnet window.
- * 'scrollable': Unlimited length xterm or telnet window.
- * 'server': S-Plus Stat Server.
- * 'BATCH': BATCH.
- * 'Rgui': R GUI.
- * 'Commands': S-Plus GUI without DDE interface to ESS.
-
- Additional values may be recommended in the future as new interaction
-protocols are created. Unlike the values 'iESS' and 'ddeESS', ESS can't
-set these other values since the R language program is not under the
-control of ESS.
-
-\1f
-File: ess.info, Node: Emacsclient, Next: Other, Prev: Statistical Process running in ESS?, Up: Entering commands
-
-4.7 Using emacsclient
-=====================
-
-When starting R or S under Unix, ESS sets
-'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 'iterator', typing
-'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 'edit()' rather than
-'fix()' means that the function is not updated. Finally, the R function
-'page(x)' will also show a text representation of the object 'x' in a
-temporary Emacs buffer.
-
-\1f
-File: ess.info, Node: Other, Prev: Emacsclient, Up: Entering commands
-
-4.8 Other commands provided by inferior-ESS
-===========================================
-
-The following commands are also available in the process buffer:
-
- -- Command: comint-interrupt-subjob
- 'C-c C-c' Sends a Control-C signal to the iESS process. This has
- the effect of aborting the current command.
-
- -- Command: ess-switch-to-inferior-or-script-buffer TOGGLE-EOB
- '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 'C-z' switch between the script and
- process buffers.
-
- If TOGGLE-EOB is given, the value of
- 'ess-switch-to-end-of-proc-buffer' is toggled.
-
- -- User Option: ess-switch-to-end-of-proc-buffer
- If non-'nil', 'ess-switch-to-inferior-or-script-buffer' goes to end
- of process buffer.
-
- Other commands available in iESS modes are discussed in *note
-(emacs)Shell Mode::.
-
-\1f
-File: ess.info, Node: Evaluating code, Next: Transcript Mode, Prev: Entering commands, Up: Top
-
-5 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 '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:
-
- -- User Option: ess-eval-visibly
- Non-'nil' means 'ess-eval-*' commands display commands and output
- in the process buffer. Default is 't'.
-
- Passing a prefix ('C-u') (in elisp terms, the argument VIS) to any of
-the following commands, however, reverses the meaning of
-'ess-eval-visibly' for that command only -- for example 'C-u C-c C-j'
-evaluates the current line without showing the input in the iESS buffer.
-The default value of 'ess-eval-visibly' ('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 'ess-eval-visibly' to ''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:
-
- -- Command: ess-eval-region-or-line-and-step VIS
- 'C-<RET>' Sends the highlighted region or current line and step to
- next line of code.
-
- -- Command: ess-eval-region-or-function-or-paragraph VIS
- 'C-M-x' Sends the current selected region or function or paragraph.
-
- -- Command: ess-eval-region-or-function-or-paragraph-and-step VIS
- 'C-c C-c' Like 'ess-eval-region-or-function-or-paragraph' but steps
- to next line of code.
-
- Other, not so often used, evaluation commands are:
-
- -- Command: ess-eval-line VIS
- 'C-c C-j' Sends the current line to the ESS process.
-
- -- Command: ess-eval-line-and-go VIS
- 'C-c M-j' Like 'ess-eval-line' but additionally switches point to
- the ESS process.
-
- -- Command: ess-eval-function VIS NO-ERROR
- 'C-c C-f' Sends the function containing point to the ESS process.
-
- -- Command: ess-eval-function-and-go VIS
- 'C-c M-f' Like 'ess-eval-function' but additionally switches point
- to the ESS process.
-
- -- Command: ess-eval-region START END TOGGLE MESSAGE
- 'C-c C-r' Sends the current region to the ESS process.
-
- -- Command: ess-eval-region-and-go START END VIS
- 'C-c M-r' Like 'ess-eval-region' but additionally switches point to
- the ESS process.
-
- -- Command: ess-eval-buffer VIS
- 'C-c C-b' Sends the current buffer to the ESS process.
-
- -- Command: ess-eval-buffer-and-go VIS
- 'C-c M-b' Like 'ess-eval-buffer' but additionally switches point to
- the ESS process.
-
- All the above '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 'C-c C-l' to
-update the function's value. In particular, '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 'comint-move-point-for-output' to ''others' or 't'.
-
-\1f
-File: ess.info, Node: Transcript Mode, Next: Editing objects, Prev: Evaluating code, Up: Top
-
-6 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 "transcript file", which should normally have the suffix '.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 '.Rout' into Emacs, it is placed
-in R Transcript Mode. Transcript Mode is similar to inferior R mode
-(*note Entering commands::): paragraphs are defined as a command and its
-output, and you can move though commands either with the paragraph
-commands or with 'C-c C-p' and 'C-c C-n'.
-
-* Menu:
-
-* Resubmit:: Resubmitting commands from the transcript file
-* Clean:: Cleaning transcript files
-
-\1f
-File: ess.info, Node: Resubmit, Next: Clean, Up: Transcript Mode
-
-6.1 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:
-
- -- Command: ess-transcript-send-command
- 'M-RET' Sends the current command line to the ESS process, and
- execute it.
-
- -- Command: ess-transcript-copy-command
- 'C-c RET' Copy the current command to the ESS process, and switch
- to it (ready to edit the copied command).
-
- -- Command: ess-transcript-send-command-and-move
- '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.
-
-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.
-
-\1f
-File: ess.info, Node: Clean, Prev: Resubmit, Up: Transcript Mode
-
-6.2 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:
-
- -- Command: ess-transcript-clean-region BEG END EVEN-IF-READ-ONLY
- 'C-c C-w' Strip the transcript in the region (given by BEG and
- END), leaving only commands. Deletes any lines not beginning with
- a prompt, and then removes the prompt from those lines that remain.
- Prefix argument EVEN-IF-READ-ONLY means to clean even if the buffer
- is read-only. Don't forget to remove any erroneous commands first!
-
-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 (*note Evaluating code::) using the code evaluation commands
-from R mode, also available in R Transcript Mode.
-
-\1f
-File: ess.info, Node: Editing objects, Next: Help, Prev: Transcript Mode, Up: Top
-
-7 Editing objects and 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
-
-\1f
-File: ess.info, Node: Edit buffer, Next: Loading, Up: Editing objects
-
-7.1 Creating or modifying R objects
-===================================
-
-To edit an object, type
-
- -- Command: ess-dump-object-into-edit-buffer OBJECT
- 'C-c C-e C-d' Edit an object in its own edit buffer.
-
- from within the iESS process buffer ('*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 'TAB' key),
-or you may enter the name of a new object. 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
-'ess-function-template' is non-'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 'ess-dump-object-into-edit-buffer' is placed in the '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.
-
- Note: when you dump a file with '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 (*note 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
-'dump()' command issued. 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 'ess-dump-object-into-edit-buffer' by typing 'C-u C-c
-C-e C-d'.
-
-\1f
-File: ess.info, Node: Loading, Next: Error Checking, Prev: Edit buffer, Up: Editing objects
-
-7.2 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 'source' function.
-You have already seen how to create source files using '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
-'ess-load-file' ('C-c M-l'). *note Hot keys::.
-
-After typing '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 '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 '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.
-
-\1f
-File: ess.info, Node: Error Checking, Next: Indenting, Prev: Loading, Up: Editing objects
-
-7.3 Detecting errors in source files
-====================================
-
-If any errors occur when loading a file with '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 'C-c `'
-('ess-parse-errors'). You will be returned to the offending file
-(loading it into a buffer if necessary) with point at the line S
-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 '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 _is_ a syntax error)
-by passing a prefix argument to 'ess-parse-errors' with 'C-u C-c `'.
-
-\1f
-File: ess.info, Node: Indenting, Next: Other edit buffer commands, Prev: Error Checking, Up: Editing objects
-
-7.4 Indenting and formatting R code
-===================================
-
-ESS provides a sophisticated mechanism for indenting R source code.
-Compound statements (delimited by '{' and '}') 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, 'if' statements,
-calls to '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.
-
- Comments are also handled specially by ESS, using an idea borrowed
-from the Emacs-Lisp indentation style. By default, comments beginning
-with '###' are aligned to the beginning of the line. Comments beginning
-with '##' are aligned to the current level of indentation for the block
-containing the comment. Finally, comments beginning with '#' are
-aligned to a column on the right (the 40th column by default, but this
-value is controlled by the variable '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 '(setq ess-indent-with-fancy-comments nil)' to your '.emacs' file.
-
- ESS also supports Roxygen entries which is R documentation maintained
-in the source code as comments *Note Roxygen::.
-
- The indentation commands provided by ESS are:
-
- -- Command: ess-indent-or-complete
- '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
- 'tab-always-indent' is ''complete'. See also
- 'ess-first-tab-never-complete'.
-
- -- User Option: ess-first-tab-never-complete
- If non-'nil', 'TAB' never tries to complete in ess-mode. The
- default ''symbol' does not try to complete if the next char is a
- valid symbol constituent. There are more options, see the help
- ('C-h v').
-
- -- Command: ess-indent-exp
- 'TAB' Indents each line in the R (compound) expression which
- follows point. Very useful for beautifying your R code.
-
- -- Command: ess-electric-brace
- '{' '}' The braces automatically indent to the correct position
- when typed.
-
- The following Emacs command are also helpful:
-
-'RET'
-'LFD'
- 'newline-and-indent' Insert a newline, and indent the next line.
- (Note that most keyboards nowadays do not have a <LINEFEED> key,
- but <RET> and 'C-j' are equivalent.)
-
-'M-;'
- 'indent-dwim' Call the comment command you want (Do What I Mean).
-
-* Menu:
-
-* Styles:: Changing styles for indentation and alignment
-
-\1f
-File: ess.info, Node: Styles, Up: Indenting
-
-7.4.1 Changing styles for code indentation and alignment
---------------------------------------------------------
-
-The combined value of twelve variables (4 of three groups
-'ess-indent-*', 'ess-offset-*' and 'ess-align-*') that control
-indentation are collectively termed a style. ESS provides several
-styles covering the common styles of indentation: 'DEFAULT', 'OWN',
-'GNU', 'BSD', 'K&R', 'C++', 'RRR', 'RRR+', 'Rstudio', 'Rstudio-', and
-'CLB'. The variable 'ess-style-alist' lists the value of each
-indentation variable per style (and its documentation contains more).
-
- -- Command: ess-set-style
- 'C-c C-e C-s' (or 'C-c C-e s') sets the formatting style in this
- buffer to be one of the predefined styles, see above. The
- 'DEFAULT' style uses the default values for the indenting
- variables; The 'OWN' style allows you to use your own private
- values of the indentation variable, see below.
-
- -- User Option: ess-style
- The style to use. See the variable 'ess-style-alist' for how these
- groups (DEFAULT, OWN, GNU, RRR, ...) map onto different settings
- for variables. You can set this in your Emacs configuration file:
-
- (setq ess-style 'C++)
-
- -- 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 'ess-own-style-list'. The default
- style in use is controlled by 'ess-style'.
-
- The styles 'DEFAULT' and 'OWN' are initially identical. If you wish
-to edit some of the default values, set 'ess-style' to ''OWN' and change
-'ess-own-style-list'. *Note 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:
-
- (defun myindent-ess-hook ()
- (setq ess-indent-level 4))
- (add-hook 'ess-mode-hook 'myindent-ess-hook)
-
- In the rare case that you'd like to add an entire new indentation
-style of your own, copy the definition of 'ess-own-style-list' to a new
-variable and ensure that the last line of the ':set' declaration calls
-'ess-add-style' with a unique name for your style (e.g. ''MINE').
-Finally, add '(setq ess-style 'MINE)' to use your new style.
-
-\1f
-File: ess.info, Node: Other edit buffer commands, Next: Source Files, Prev: Indenting, Up: Editing objects
-
-7.5 Commands for motion, completion and more
-============================================
-
-A number of commands are provided to move across function definitions in
-the edit buffer:
-
- -- Command: ess-goto-beginning-of-function-or-para
- 'ESC C-a' aka 'C-M-a' If inside a function go to the beginning of
- it, otherwise go to the beginning of paragraph.
-
- -- Command: ess-goto-end-of-function-or-para
- 'ESC C-e' aka 'C-M-e' Move point to the end of the function
- containing point.
-
- -- Command: ess-mark-function
- 'ESC C-h' aka 'C-M-h' Place point at the beginning of the R
- function containing point, and mark at the end.
-
-Don't forget the usual Emacs commands for moving over balanced
-expressions and parentheses: *Note Lists and Sexps: (Emacs)Lists.
-
- Completion is provided in the edit buffer in a similar fashion to the
-process buffer: <TAB> first indents, and if there is nothing to indent,
-completes the object or file name; 'M-?' lists file completions. See
-*Note Completion::, for more.
-
- Finally, 'C-c C-z' ('ess-switch-to-inferior-or-script-buffer')
-returns you to the 'iESS' process buffer, if done from a script buffer,
-placing point at the end of the buffer. If this is done from the '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 'C-c
-C-v', edit another function with 'C-c C-e C-d' and of course 'C-c C-l'
-can be used to load a source file into R.
-
-\1f
-File: ess.info, Node: Source Files, Next: Source Directories, Prev: Other edit buffer commands, Up: Editing objects
-
-7.6 Maintaining R source files
-==============================
-
-Every edit buffer in ESS is associated with a "dump file" on disk. Dump
-files are created whenever you type 'C-c C-e C-d'
-('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.
-
- -- User Option: ess-delete-dump-files
- If non-'nil', dump files created with C-c C-e C-d are deleted
- immediately after they are created by the ess-process.
-
- 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 _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 'dump'
-function; it doesn't apply to source files which already exist. The
-default value is 't'.
-
- -- User Option: ess-keep-dump-files
- 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 behaviour of
- 'ess-load-file'. Dump files are never deleted if an error occurs
- during the load.
-
- After an object has been successfully (without error) loaded back
-into R with '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.
-
- If the value of 'ess-keep-dump-files' is '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 --
-*note Single or Numbered Backups: (emacs)Backup Names, you can keep a
-historic record of function definitions. Another possibility is to
-maintain the files with a version-control system such as git *Note
-Version Control: (emacs)Version Control. As long as a dump file exists
-in the appropriate place for a particular object, editing that object
-with '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 _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 'ess-keep-dump-files' is nil, the dump file is always
-silently deleted after a successful load with 'C-c C-l'. While this is
-useful for files that were created with '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
-'ess-keep-dump-files' is buffer-local, you can make sure particular
-files are not deleted by setting it to 't' in the Local Variables
-section of the file *Note Local Variables in Files: (emacs)File
-Variables.
-
- A safer option is to set 'ess-keep-dump-files' to '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 'C-c C-e C-d', but not any other files, setting
-'ess-keep-dump-files' to 'check' (the default value) will silently
-delete dump files created with '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 'C-c C-l', the dump file is _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.
-
- Dump buffers are always autosaved, regardless of the value of
-'ess-keep-dump-files'.
-
-\1f
-File: ess.info, Node: Source Directories, Prev: Source Files, Up: Editing objects
-
-7.7 Names and locations of dump files
-=====================================
-
-Every dump file should be given a unique file name, usually the dumped
-object name with some additions.
-
- -- User Option: ess-dump-filename-template
- Template for filenames of dumped objects. '%s' is replaced by the
- object name.
-
-By default, dump file names are the user name, followed by '.' and the
-object and ending with '.R'. Thus if user 'joe' dumps the object
-'myfun' the dump file will have name 'joe.myfun.R'. The username part
-is included to avoid clashes when dumping into a publicly-writable
-directory, such as '/tmp'; you may wish to remove this part if you are
-dumping into a directory owned by you.
-
- You may also specify the directory in which dump files are written:
-
- -- User Option: ess-source-directory
- Directory name (ending in a slash) where R dump files are to be
- written.
-
- By default, dump files are always written to '/tmp', which is fine
-when 'ess-keep-dump-files' is 'nil'. If you are keeping dump files,
-then you will probably want to keep them somewhere in your home
-directory, say '~/R-source'. This could be achieved by including the
-following line in your Emacs configuration file:
- (setq ess-source-directory (expand-file-name "~/R-source/"))
-
- 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 '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 'Src' of the
-directory the ESS process was run in.
-
- (setq ess-source-directory
- (lambda ()
- (concat ess-directory "Src/")))
-
-('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:
- (setq ess-source-directory
- (lambda ()
- (file-name-as-directory
- (expand-file-name (concat
- (car ess-search-list)
- "/.Src")))))
-
- 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.
-
-\1f
-File: ess.info, Node: Help, Next: Completion, Prev: Editing objects, Up: Top
-
-8 Reading 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 'C-c C-v' ('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 '*help(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:
-
-'?'
- 'ess-describe-help-mode' Pops up a help buffer with a list of the
- commands available in R help mode.
-
-'h'
- 'ess-display-help-on-object' Pop up a help buffer for a different
- object.
-
- Paging commands:
-
-'DEL'
- 'scroll-down-command' Move one screen backwards through the help
- file.
-
-'SPC'
- 'scroll-up-command' Move one screen forwards through the help file.
-
-'>'
-'<'
- 'end/beginning-of-buffer' Move to the end or beginning of the help
- file, respectively.
-
- Section-based motion commands:
-
-'n'
-'p'
- 'ess-skip-to-previous-section' and '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.
-
- In addition, the '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 's ?' to get the current list of active key bindings.
-
-'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:
-
-'?'
- Pops up a help buffer with a list of the defined section motion
- keys.
-
- Evaluation:
-
-'l'
- '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.
-
-'r'
- 'ess-eval-region' Send the contents of the current region to the
- ESS process. Useful for running examples in help files.
-
- Quit commands:
-
-'q'
- 'ess-help-quit' Return to previously selected buffer, and bury the
- help buffer.
-
-'k'
- 'kill-buffer' Return to previously selected buffer, and kills the
- help buffer.
-
-'x'
- 'ess-kill-buffer-and-go' Return to the ESS process, killing this
- help buffer.
-
- Miscellaneous:
-
-'i'
- 'ess-display-index' Prompt for a package and display it's help
- index.
-
-'v'
- 'ess-display-vignettes' Display all available vignettes.
-
-'w'
- 'ess-display-help-in-browser' Display current help page with the
- web browser.
-
-'/'
- 'isearch-forward' Same as 'C-s'.
-
- In addition, all of the ESS commands available in the edit buffers
-are also available in R help mode (*note Edit buffer::). Of course, the
-usual (non-editing) Emacs commands are available, and for convenience
-the digits and <-> 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 'C-u') to 'ess-display-help-on-object'.
-
- Help buffers are marked as temporary buffers in ESS, and are deleted
-when 'ess-quit' or '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 'ess-help-own-frame'.
-
- Help buffers are displayed by calling the function
-'ess-display-help'. You can customize where these buffers are displayed
-by adding an entry in 'display-buffer-alist' (see *Note (ess)Controlling
-buffer display:: for examples) or by customizing the options
-'ess-help-own-frame', 'ess-help-frame-alist', and
-'ess-display-buffer-reuse-frame'.
-
-\1f
-File: ess.info, Node: Completion, Next: Developing with ESS, Prev: Help, Up: Top
-
-9 Completion
-************
-
-* Menu:
-
-* Object names::
-* Function arguments::
-* Minibuffer completion::
-* Company::
-* Icicles::
-
-\1f
-File: ess.info, Node: Object names, Next: Function arguments, Up: Completion
-
-9.1 Completion of object names
-==============================
-
-The <TAB> key is for completion. The value of the variable
-'ess-first-tab-never-complete' controls when completion is allowed to
-occur. In 'ess-mode' <TAB> first tries to indent, and if there is
-nothing to indent, complete the object name instead.
-
-'TAB'
- 'comint-dynamic-complete' Complete the R object name or filename
- before point.
-
- When the cursor is just after a partially-completed object name,
-pressing <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 'search()' command along with
-the component objects of attached data frames
-
- For example, consider three functions 'binomplot()', 'binom.test()'
-and 'binomial()'. Typing 'bin TAB' will insert the characters 'om',
-completing the longest prefix ('binom') which distinguishes these three
-commands. Pressing 'TAB' once more provides a list of the three
-commands which have this prefix, allowing you to add more characters
-(say, '.') which specify the function you desire. After entering more
-characters pressing '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 'M-?'.
-
- -- Command: ess-complete-object-name
- 'M-?' List all possible completions of the object name at point.
-
- ESS also provides completion over the components of named lists and
-environments (after '$'), S4 classes slots (after @), package and
-namespace objects (after :: and :::).
-
- Completion is also provided over file names, which is particularly
-useful when using R functions such as 'get()' or '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 <TAB> key has a third use: it
-expands history references. *Note 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 *know* is there), the command 'M-x ess-resynch'
-forces the _entire_ cache to be refreshed, which should fix the problem.
-
-\1f
-File: ess.info, Node: Function arguments, Next: Minibuffer completion, Prev: Object names, Up: Completion
-
-9.2 Completion of function arguments
-====================================
-
-When inside a function call (i.e. following ''(''), 'TAB' completion
-also provides function arguments. If function is a generic, completion
-will provide all the arguments of 'S3' methods known to 'R'.
-
- 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
-'?rc.options' at the prompt. For example, to have the equals sign for
-function arguments contain spaces on both sides (e.g. 'lm(for)'
-suggests 'formula = ' rather than 'formula='), you can adjust
-'funarg.suffix':
-
- utils::rc.options(funarg.suffix = " = ")
-
- A related functionality is *Note ESS ElDoc::, which displays function
-arguments in the echo area whenever the point is inside a function call.
-
-\1f
-File: ess.info, Node: Minibuffer completion, Next: Company, Prev: Function arguments, Up: Completion
-
-9.3 Minibuffer completion
-=========================
-
-ESS uses 'IDO' mechanism (part of default Emacs) for minibuffer
-completion if the 'ido' package is available and the value of
-'ess-use-ido' it 't' (the default). The completion command
-'ess-completing-read' falls back on classic 'completion-read' interface
-if this feature is not available for whatever reason.
-
-\1f
-File: ess.info, Node: Company, Next: Icicles, Prev: Minibuffer completion, Up: Completion
-
-9.4 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 'ess-use-company' to 'nil'. You can set it to
-''script-only' to only activate company in R scripts.
-
-\1f
-File: ess.info, Node: Icicles, Prev: Company, Up: Completion
-
-9.5 Icicles
-===========
-
-Another option for comprehensively handling completion in Emacs is via
-Icicles (<https://www.emacswiki.org/emacs/Icicles>). It allows users to
-have completions shown temporarily in the standard '*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 'customize-group Icicles', for more details on
-installation and customization options.
-
- Once installed, Icicles can be activated by evaluating):
-
- (require 'icicles)
- (icy-mode 1)
-
- Icicles can be toggled by typing 'M-x icy'.
-
- When Icicles is on, 'TAB' offers completion, provided the conditions
-determined by 'ess-first-tab-never-complete' allow it. Typing 'M-TAB'
-will attempt completion regardless. Typing 'M-?' in 'ESS' or 'iESS'
-modes brings up the relevant completion candidates from which to choose.
-Minibuffer input filters the available candidates. Use 'TAB' for prefix
-completion or 'S-TAB' for substring or regexp completion. Use 'S-SPC'
-to match an additional pattern (repeatable). You can cycle among the
-matching candidates, choosing with 'RET' or 'mouse-2'.
-
-\1f
-File: ess.info, Node: Developing with ESS, Next: Extras, Prev: Completion, Up: Top
-
-10 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
-
-\1f
-File: ess.info, Node: ESS tracebug, Next: Editing documentation, Up: Developing with ESS
-
-10.1 ESS tracebug
-=================
-
-* Menu:
-
-* Getting started with tracebug:: Quick tutorial
-
-ESS '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.
-
- 'ess-tracebug' is on by default. You can toggle it on and off with
-'M-x' 'ess-tracebug'. To disable startup activation of 'ess-tracebug'
-set 'ess-use-tracebug' to nil.
-
- Tracebug functionality can be found on 'ess-dev-map', bound to 'C-c
-C-t'. Additionally, when subprocess is in a debugging state
-'ess-debug-minor-mode' is active and the following additional shortcuts
-are available:
-
-* 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'
-
-
- These are all the tracebug commands defined in 'ess-dev-map' ('C-c
-C-t ?' to show this table):
-
-
-* 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'
-
-
- To configure how electric watch window splits the display see
-'ess-watch-width-threshold' and 'ess-watch-height-threshold' variables.
-
- _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")
-
-\1f
-File: ess.info, Node: Getting started with tracebug, Up: ESS tracebug
-
-10.1.1 Getting started with tracebug
-------------------------------------
-
-Consider a buffer with the following function:
-
-test <- function(x){
- mean(x),
-}
-
- Evaluating the function (e.g. 'C-c C-c') results in an error about
-an unexpected comma. You can use 'next-error' (bound by default to 'C-x
-`', 'M-g n', and '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 'mean' and
-set the breakpoint using 'C-c C-t b' ('ess-bp-set') and reevaluate the
-function. Jump to the inferior buffer (possibly using 'C-c C-z') and
-evaluate 'test(1:10)'. An interactive debug process starts, stopping at
-the breakpoint we just specified. Here you can debug your function
-(what is 'x' at this point?). Use 'M-N' to continue.
-
- Let's replace our test function with one slightly more complicated:
-
-test <- function(x){
- x <- x + 1
- y <- mean(x)
- x <- ifelse(x > 5, x, x - 100)
- list(x, y)
-}
-
- Try setting multiple breakpoints. You can unset a breakpoint by
-killing it with 'C-c C-t k'. You can set conditional breakpoints too.
-Try setting one by placing point on the line 'x <- x + 1' and doing 'C-c
-C-t B'. ESS will ask for the condition. Let's set it to
-'!is.numeric(x)'. After re-evaluating 'test', try calling 'test(1:100)'
-and 'test('foo')'.
-
- You can remove all breakpoints with 'C-c C-t K'.
-
- You can flag a function for debugging (similar to calling
-'debug(test)' at R's prompt) by doing 'C-c C-t d'. Try this yourself by
-putting point over 'test' and doing 'C-c C-t d'.
-
- If an error occurs, you can get the complete call stack by doing 'C-c
-`' or 'C-c C-t `' ('ess-show-traceback').
-
- Tracebug also offers a watch window where you can watch values of
-objects. Open it with 'C-c C-t w' ('ess-watch'). Initially you aren't
-watching anything. Add something with 'a' (e.g. 'a test'). The watch
-window displays what the object is at any given time and automatically
-updates. Quit the watch window with 'q'.
-
-\1f
-File: ess.info, Node: Editing documentation, Next: Namespaced Evaluation, Prev: ESS tracebug, Up: Developing with ESS
-
-10.2 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
-Roxygen package.
-
-* Menu:
-
-* R documentation files:: Edit objects in a specialized buffer
-* Roxygen:: Loading source files into the ESS process
-
-\1f
-File: ess.info, Node: R documentation files, Next: Roxygen, Up: Editing documentation
-
-10.2.1 Editing R documentation (Rd) files
------------------------------------------
-
-R objects are documented in files written in the "R documentation"
-("Rd"), a simple markup language closely resembling (La)TeX, which can
-be processed into a variety of formats, including LaTeX, 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 '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.
-
-'C-h m'
- Describe the features of Rd mode.
-
-'LFD'
-'RET'
- Reindent the current line, insert a newline and indent the new line
- ('reindent-then-newline-and-indent'). An abbrev before point is
- expanded if 'abbrev-mode' is non-'nil'.
-
-'TAB'
- Indent current line based on its contents and on previous lines.
- ('indent-according-to-mode').
-
-'C-c C-e'
- Insert a "skeleton" with Rd markup for at least all mandatory
- entries in Rd files ('Rd-mode-insert-skeleton'). Note that many
- users might prefer to use the R function '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).
-
-'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 ('Rd-font'). 'C-c C-f' is only a prefix;
- see e.g. '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 'C-c
- C-f'.
-
-'C-c C-j'
- Insert a suitably indented '\item{' on the next line
- ('Rd-mode-insert-item').
-
-'C-c C-p'
- Preview a plain text version ("help file", *note Help::) generated
- from the Rd file ('Rd-preview-help').
-
- 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,
-'C-c C-v' provides access to on-line help, and '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 'C-h
-m' for all available commands.
-
- Rd mode also provides access to abbreviations for most of the Rd
-markup commands. Type '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.
-
- -- User Option: Rd-mode-hook
- Hook to be run when Rd mode is entered.
-
- -- User Option: Rd-indent-level
- The indentation of Rd code with respect to containing blocks.
- Default is 2.
-
- -- User Option: Rd-to-help-command
- The shell command used for converting Rd source to help text.
- Default is 'R CMD Rd2txt'.
-
- To automatically turn on the abbrev and font-lock features of Rd
-mode, add the following lines to one of your Emacs startup files:
-
- (add-hook 'Rd-mode-hook
- (lambda ()
- (abbrev-mode 1)
- (font-lock-mode 1)))
-
-\1f
-File: ess.info, Node: Roxygen, Prev: R documentation files, Up: Editing documentation
-
-10.2.2 Editing Roxygen documentation
-------------------------------------
-
-The Roxygen R package makes it possible to keep the intended contents
-for Rd files as structured comments in the R source files. Roxygen can
-then parse R files and generate appropriate Rd files from these
-comments, fill the usage fields as well as updating 'NAMESPACE' files.
-See the Roxygen documentation found via <http://roxygen.org> for more
-information on its usage. An example of an Roxygen entry for a simple R
-function can look like this:
-
- ##' 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")
- The entry is immediately preceding the object to document and all
-lines start with the Roxygen prefix string, in this case '##''. ESS
-provides support to edit these documentation entries by providing line
-filling, navigation, template generation etc. Syntax highlighting is
-provided.
-
- Roxygen is customized by the variables in the customization group
-"Ess Roxy". Customizables include the Roxygen prefix, use of folding to
-toggle visibility of Roxygen entries and the Roxygen template.
-
- All ESS Roxygen support is defined in 'ess-roxy.el' which is loaded
-by default in ESS. The following special Emacs commands are provided.
-
- -- Command: ess-roxy-update-entry
- 'C-c C-o C-o' Generate a Roxygen template or update the parameter
- list in Roxygen 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 'ess-roxy-fill-param-p' is non-nil.
-
- -- Command: ess-roxy-toggle-roxy-region BEG END
- 'C-c C-o C-c' Toggle the presence of the leading Roxygen string on
- all lines in the marked region (between BEG and END. Convenient
- for transferring text to Roxygen entries and to evaluate example
- fields.
-
- -- Command: ess-roxy-preview-Rd NAME-FILE
- '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 NAME-FILE,
- i.e. '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 Roxygen package to be installed.
-
- -- Command: ess-roxy-preview-HTML VISIT-INSTEAD-OF-OPEN
- '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 VISIT-INSTEAD-OF-OPEN, i.e. 'C-u C-c C-e
- C-t', visit the generated HTML file instead. Requires the Roxygen
- and tools packages to be installed.
-
- -- Command: ess-roxy-previous-entry
- 'C-c C-o p' Go to start of the Roxygen entry above point.
-
- -- Command: ess-roxy-next-entry
- 'C-c C-o n' Go to end of the Roxygen entry above point.
-
- -- Command: ess-roxy-hide-all
- 'C-c C-o C-h' Use the hideshow mode to fold away the visibility of
- all Roxygen entries. Hide-show support must be enabled for this
- binding to get defined.
-
- ESS also advises the following standard editing functions in order to
-make Roxygen editing more intuitive:
-
-'TAB'
- 'ess-R-complete-object-name' Complete Roxygen tag at point. E.g.
- doing 'TAB' when the point is at the end of '@par' completes to
- '@param'.
-
-'M-h'
- '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.
-
-'TAB'
- 'ess-indent-command' If hide-show support is enabled, fold away the
- visibility of the Roxygen entry at point.
-
-'M-q'
- 'fill-paragraph' Fill the Roxygen field at point.
-
-'C-a'
- 'ess-roxy-move-beginning-of-line' Move to the point directly to the
- right of the Roxygen start string. If already there, move to the
- beginning of the line.
-
-'RET'
- 'newline-and-indent' Insert a new line and the Roxygen prefix
- string.
-
-\1f
-File: ess.info, Node: Namespaced Evaluation, Prev: Editing documentation, Up: Developing with ESS
-
-10.3 Namespaced Evaluation
-==========================
-
-In non package files evaluation commands, *Note Evaluating code::, send
-portions of the current buffer environment ('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
-<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 'GlobalEnv' from inside a
-package. In such cases 'C-c C-t C-s' is your friend.
-
- -- Command: ess-r-set-evaluation-env ARG
- 'C-c C-t C-s' Set or unset the current evaluation environment (a
- package).
-
-\1f
-File: ess.info, Node: Extras, Next: ESS for R, Prev: Developing with ESS, Up: Top
-
-11 Other ESS features and tools
-*******************************
-
-ESS has a few extra features, which didn't fit anywhere else.
-* 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
-
-\1f
-File: ess.info, Node: ESS ElDoc, Next: ESS Flymake, Up: Extras
-
-11.1 ElDoc
-==========
-
-In 'ElDoc' mode, the echo area displays function's arguments at point.
-ElDoc is active by default in 'ess-mode' and 'inferior-ess-mode'
-buffers. To activate it only in 'ess-mode' buffers, place the following
-into your init file:
-
- (setq ess-use-eldoc 'script-only)
-
- -- User Option: ess-use-eldoc
- If 't', activate eldoc in ess-mode and inferior-ess-mode buffers.
- If ''script-only' activate in ess-mode buffers only. Set
- 'ess-use-eldoc' to 'nil' to stop using 'ElDoc' altogether.
-
- -- User Option: ess-eldoc-show-on-symbol
- This variable controls whether the help is shown only inside
- function calls. If set to 't', '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 ''(''.
-
- -- User Option: ess-eldoc-abbreviation-style
- The variable determines how the doc string should be abbreviated to
- fit into minibuffer. Posible values are 'nil', 'mild', 'normal',
- 'strong' and 'aggressive'. Please see the documentation of the
- variable for more details. The default filter is 'normal'.
-
- Ess-eldoc also honors the value of 'eldoc-echo-area-use-multiline-p',
-which if set to 'nil', will cause the truncation of doc string
-indifferent of the value of 'ess-eldoc-abbreviation-style'. This way
-you can combine different filter levels with the truncation.
-
-\1f
-File: ess.info, Node: ESS Flymake, Next: Handy commands, Prev: ESS ElDoc, Up: Extras
-
-11.2 Flymake
-============
-
-The minor mode '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 'ess-use-flymake' to
-'nil'. In order to use it, you may need to install the 'lintr' R
-package, available from CRAN.
-
- -- User Option: ess-use-flymake
- When non-nil, use flymake. If ''process', only use flymake when
- the buffer has an inferior process running.
-
- -- 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 'lintr::with_defaults'. See the
- help page for 'lintr::default_linters' for information on available
- linters and their defaults.
-
- -- User Option: ess-r-flymake-lintr-cache
- When 't' (the default), lintr uses a cache. Change to 'nil' to
- disable lintr's caching mechanism.
-
-\1f
-File: ess.info, Node: Handy commands, Next: Highlighting, Prev: ESS Flymake, Up: Extras
-
-11.3 Handy commands
-===================
-
- -- Command: ess-handy-commands
- Request and execute a command from 'ess-handy-commands' list.
-
- -- User Option: ess-handy-commands
- An alist of custom ESS commands available for call by
- 'ess-handy-commands' and 'ess-smart-comma' function.
-
- Currently contains:
-
- 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.
-
-\1f
-File: ess.info, Node: Highlighting, Next: Parens, Prev: Handy commands, Up: Extras
-
-11.4 Syntactic highlighting of buffers
-======================================
-
-ESS provides Font-Lock (*note Using Multiple Typefaces: (emacs)Faces.)
-patterns for inferior R Mode, S Mode, and R Transcript Mode buffers.
-
- The font-lock patterns are defined by the following variables, which
-you may modify if desired:
-
- -- User Option: inferior-R-font-lock-keywords
- Font-lock patterns for inferior *R* processes. (There is a
- corresponding '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 'NA' and
- 'TRUE'.
-
- -- User Option: ess-R-font-lock-keywords
- Font-lock patterns for ESS R programming mode. (There is a
- corresponding 'ess-S-font-lock-keywords' for S buffers.) The
- default value highlights function names, literals, assignments,
- source functions and reserved words.
-
-\1f
-File: ess.info, Node: Parens, Next: Graphics, Prev: Highlighting, Up: Extras
-
-11.5 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:
-
- (show-paren-mode)
-
-\1f
-File: ess.info, Node: Graphics, Next: Imenu, Prev: Parens, Up: Extras
-
-11.6 Using graphics with ESS
-============================
-
-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
-
-\1f
-File: ess.info, Node: printer, Next: X11, Up: Graphics
-
-11.6.1 Using ESS with the 'printer()' driver
---------------------------------------------
-
-This is the simplest (and least desirable) method of using graphics
-within ESS. S's '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
- printer(width=79)
- (the '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 'show()' command is
-issued, which displays the current figure.
-
-\1f
-File: ess.info, Node: X11, Next: winjava, Prev: printer, Up: Graphics
-
-11.6.2 Using ESS with windowing devices
----------------------------------------
-
-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.
-
-\1f
-File: ess.info, Node: winjava, Prev: X11, Up: Graphics
-
-11.6.3 Java Graphics Device
----------------------------
-
-S+6.1 and newer on Windows contains a java library that supports
-graphics. Send the commands:
-
- library(winjava)
- java.graph()
-
-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.)
-
-\1f
-File: ess.info, Node: Imenu, Next: Toolbar, Prev: Graphics, Up: Extras
-
-11.7 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 'imenu-generic-expression'. This value is set
-by various ESS variables such as 'ess-imenu-S-generic-expression'.
-
-\1f
-File: ess.info, Node: Toolbar, Next: Xref, Prev: Imenu, Up: Extras
-
-11.8 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. *Note Customization::, for
-ways to change the toolbar.
-
-\1f
-File: ess.info, Node: Xref, Next: Rdired, Prev: Toolbar, Up: Extras
-
-11.9 Xref
-=========
-
-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. *Note (emacs)Xref:: for how to use this
-feature.
-
-\1f
-File: ess.info, Node: Rdired, Next: Package listing, Prev: Xref, Up: Extras
-
-11.10 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 'M-x R' and then store a few variables, such
-as:
-
- s <- sin(seq(from=0, to=8*pi, length=100))
- x <- c(1, 4, 9)
- y <- rnorm(20)
- z <- TRUE
-
- Then use 'M-x ess-rdired' to create a buffer listing the objects in
-your current environment and display it in a new window:
- mode length
- s numeric 100
- x numeric 3
- y numeric 20
- z logical 1
-
- Type 'C-h m' or '?' 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).
-
-\1f
-File: ess.info, Node: Package listing, Next: Org, Prev: Rdired, Up: Extras
-
-11.11 Package listing
-=====================
-
-ESS[R] provides several commands to list and manage packages and objects
-under the 'C-c C-.' keymap:
-
- -- Command: ess-r-package-list-local-packages
- 'C-c C-. l' List all packages in all available libraries.
-
- -- Command: ess-r-package-list-available-packages
- 'C-c C-. r' List available packages from repositories listed by
- 'getOptions(``repos'')' in the current R session.
-
- -- Command: ess-r-package-update-packages LIB REPOS
- 'C-c C-. u' Update packages in a particular library LIB and
- repository REPOS.
-
- -- Command: ess-rutils-rm-all
- 'C-c C-. m' Remove all R objects.
-
- -- Command: ess-rutils-load-wkspc
- 'C-c C-. w' Load a workspace file into R.
-
- -- Command: ess-rutils-save-wkspc
- 'C-c C-. s' Save a workspace file.
-
- -- Command: ess-change-directory
- 'C-c C-. d' Change the working directory for the current R session.
-
- -- Command: ess-rutils-html-docs
- 'C-c C-. H' Use 'browse-url' to navigate R html documentation.
-
- Functions for listing objects and packages ('ess-rutils-local-pkgs',
-'ess-rutils-repos-pkgs', and 'ess-rutils-objs') show results in a
-separate buffer and window, in 'ess-rutils-mode', providing useful key
-bindings in this mode (type '?' in this buffer for a description).
-
-\1f
-File: ess.info, Node: Org, Next: Sweave and AUCTeX, Prev: Package listing, Up: Extras
-
-11.12 Interaction with Org mode
-===============================
-
-Org-mode (<https://orgmode.org>) now supports reproducible research and
-literate programming in many languages (including R) - see chapter 14 of
-the Org manual
-(<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.)
-
-\1f
-File: ess.info, Node: Sweave and AUCTeX, Prev: Org, Up: Extras
-
-11.13 Support for Sweave in ESS and AUCTeX
-==========================================
-
-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 <https://github.com/polymode/poly-R/>,
-<https://polymode.github.io/>, or markdown-mode with edit-indirect
-<https://jblevins.org/projects/markdown-mode>.
-
- ESS provides support for writing and processing Sweave
-(<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:
-
- -- Command: ess-swv-weave CHOOSE
- 'M-n s' Run Sweave on the current .Rnw file. If CHOOSE is
- non-'nil', offer a menu of available weavers.
-
- -- Command: ess-swv-latex
- 'M-n l' Run LaTeX after Sweave'ing.
-
- -- Command: ess-swv-PS
- 'M-n p' Generate and display a postscript file after LaTeX'ing.
-
- -- Command: ess-swv-PDF PDFLATEX-CMD
- 'M-n P' Generate and display a PDF file after LaTeX'ing. Optional
- argument PDFLATEX-CMD is the command to use, which by default, is
- the command used to generate the PDF file is the first element of
- 'ess-swv-pdflatex-commands'.
-
- -- User Option: ess-swv-pdflatex-commands
- Commands used by 'ess-swv-PDF' to run a version of pdflatex; the
- first entry is the default command.
-
- Sweave'ing with 'ess-swv-weave' starts an inferior-ESS process, if
-one is not available. Other commands are available from the 'Sweaving,
-Tangling, ...' submenu of the Noweb menu.
-
- AUCTeX (<https://www.gnu.org/software/auctex>) users may prefer to
-set the variable '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 '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 'C-c C-c Sweave RET' without an inferior-ESS process.
-Similarly, LaTeX'ing can be done by 'C-c C-c LaTeXSweave RET'. In both
-cases, the process can be monitored with 'C-c C-l'
-('TeX-recenter-output-buffer'). Open the viewer with 'C-c C-v'
-('TeX-view'), as usual in AUCTeX.
-
-\1f
-File: ess.info, Node: ESS for R, Next: ESS for SAS, Prev: Extras, Up: Top
-
-12 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::
-
-\1f
-File: ess.info, Node: ESS(R)--Editing files, Next: iESS(R)--Inferior ESS processes, Up: ESS for R
-
-12.1 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 '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.
-
-\1f
-File: ess.info, Node: iESS(R)--Inferior ESS processes, Next: Philosophies for using ESS(R), Prev: ESS(R)--Editing files, Up: ESS for R
-
-12.2 iESS[R]-Inferior ESS processes
-===================================
-
-To start up iESS mode for R, use:
- M-x R
- M-x S+3
- M-x S4
- M-x S+5
- M-x S+6
-
-(for R, S-PLUS 3.x, S4, S+5, S+6 or S+7, respectively. This assumes
-that you have access to each).
-
- 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
-'inferior-R-args'.
-
- Note that R has some extremely useful command line arguments. For
-example, '--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
-'exec-path' for R binaries. If ESS cannot find your R binaries, on Unix
-you can change the Unix environment variable 'PATH', as this variable is
-used to set 'exec-path'.
-
- R on GNU/Linux systems and other Unix-like systems (macOS): If you
-have "R-1.8.1" on your 'exec-path', it can be started using 'M-x
-R-1.8.1'. By default, ESS will find versions of R beginning "R-1",
-"R-2", "R-3", "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 'ess-r-runners-prefixes'. To see which functions
-have been created for starting different versions of R, type '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 'exec-path', it
-can be started using 'M-x rw1081'. By default, ESS will find versions
-of R located in directories parallel to the version of R in your 'PATH'.
-If your versions of R are called other names, you will need to change
-the variable 'ess-rterm-versions'. To see which functions have been
-created for starting different versions of R, type '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 '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 'R --version' to determine which is newest.)
-
-\1f
-File: ess.info, Node: Philosophies for using ESS(R), Next: Example ESS usage, Prev: iESS(R)--Inferior ESS processes, Up: ESS for R
-
-12.3 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:
- (setq ess-keep-dump-files nil)
- (setq ess-delete-dump-files t)
- (setq ess-mode-silently-save nil)
-
-\1f
-File: ess.info, Node: Example ESS usage, Prev: Philosophies for using ESS(R), Up: ESS for R
-
-12.4 Example ESS usage
-======================
-
-Comments as to what should be happening are prefixed by "##".
-
- ### 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.
-
-
-\1f
-File: ess.info, Node: ESS for SAS, Next: ESS for BUGS, Prev: ESS for R, Up: Top
-
-13 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::
-ESS[SAS] was designed for use with SAS. It is descended from emacs
-macros developed by John Sall for editing SAS programs and '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.
-
-\1f
-File: ess.info, Node: ESS(SAS)--Design philosophy, Next: ESS(SAS)--Editing files, Up: ESS for SAS
-
-13.1 ESS[SAS]-Design philosophy
-===============================
-
-ESS[SAS] was designed to aid the user in writing and maintaining SAS
-programs, such as 'FOO.sas'. Both interactive and batch submission of
-SAS programs is supported.
-
- ESS[SAS] was written with two primary goals.
- 1. 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.
- 2. 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.
-
-\1f
-File: ess.info, Node: ESS(SAS)--Editing files, Next: ESS(SAS)--TAB key, Prev: ESS(SAS)--Design philosophy, Up: ESS for SAS
-
-13.2 ESS[SAS]-Editing files
-===========================
-
-ESS[SAS] is the mode for editing SAS language files. This mode handles:
-
- * proper indenting, generated by both <TAB> and <RET>.
- * color and font choices based on syntax.
- * 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.
- * capability of killing the batch SAS process through the '*shell*'
- buffer or allow the SAS process to keep on running after you exit
- emacs.
- * single keypress navigation of '.sas', '.log' and '.lst' files
- ('.log' and '.lst' files are refreshed with each keypress).
- * ability to send the contents of an entire buffer, a highlighted
- region, or a single line to an interactive SAS process.
- * ability to switch between processes which would be the target of
- the buffer (for the above).
-
- ESS[SAS] is automatically turned on when editing a file with a '.sas'
-suffix (or other extension, if specified via '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 'M-x SAS' (*Note
-iESS(SAS)--Interactive SAS processes::.)
-
- At this writing, the indenting and syntax highlighting are generally
-correct. Known issues: for multiple line '*' or '%*' comments, only the
-first line is highlighted; for '.log' files, only the first line of a
-'NOTE:', 'WARNING:' or 'ERROR:' message is highlighted; unmatched
-single/double quotes in 'CARDS' data lines are *NOT* ignored; in an
-iterative 'DO' statement, 'TO' and 'BY' are not highlighted.
-
-\1f
-File: ess.info, Node: ESS(SAS)--TAB key, Next: ESS(SAS)--Batch SAS processes, Prev: ESS(SAS)--Editing files, Up: ESS for SAS
-
-13.3 ESS[SAS]-<TAB> key
-=======================
-
-Two options. The <TAB> key is bound by default to 'sas-indent-line'.
-This function is used to syntactically indent SAS code so 'PROC' and
-'RUN' are in the left margin, other statements are indented
-'sas-indent-width' spaces from the margin, continuation lines are
-indented '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
-'require'/'load':
- (setq ess-sas-edit-keys-toggle nil)
-
- ESS provides an alternate behavior for <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, 'C-<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 'require'/'load':
- (setq ess-sas-edit-keys-toggle t)
- Under the alternate behavior, <TAB> is bound to 'M-x tab-to-tab-stop'
-and the stops are defined by 'ess-sas-tab-stop-list'.
-
-\1f
-File: ess.info, Node: ESS(SAS)--Batch SAS processes, Next: ESS(SAS)--Function keys for batch processing, Prev: ESS(SAS)--TAB key, Up: ESS for SAS
-
-13.4 ESS[SAS]-Batch SAS processes
-=================================
-
-Submission of a SAS batch job is dependent on your environment.
-'ess-sas-submit-method' is determined by your operating system and your
-shell. It defaults to ''sh' unless you are running Windows or Mac
-Classic. Under Windows, it will default to ''sh' if you are using a
-UNIX-imitating shell; otherwise ''ms-dos' for an MS-DOS shell. On
-macOS, it will default to ''sh', but under Mac Classic, it defaults to
-''apple-script'. You will also set this to ''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 'ess-sas-shell-buffer-remote-init' is a Local
-Variable that defaults to '"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 'ssh-agent'/'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 'ess-kermit-prefix' character prepended (the default is
-'"#"'). Execute the command '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 '*shell*' buffer, then note
-that the Kermit escape sequence is 'C-q C-\ c' rather than '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
-'ess-kermit-command'.
-
- The command used by the 'SUBMIT' function key (<F3> or <F8>) to
-submit a batch SAS job, whether local or remote, is
-'ess-sas-submit-command' which defaults to 'sas-program'. 'sas-program'
-is '"invoke SAS using program file"' for Mac Classic and '"sas"'
-otherwise. However, you may have to alter '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:
- endsas;
- Local variables:
- ess-sas-submit-command: "sas8"
- End:
-
- The command line is also made of 'ess-sas-submit-pre-command',
-'ess-sas-submit-post-command' and 'ess-sas-submit-command-options' (the
-last of which is also buffer-local). Here are some examples for your
-'~/.emacs' or '~/.emacs.d/init.el' file (you may also use
-'M-x customize-variable'):
- ;'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")
-
- 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
-'~/.emacs' or '~/.emacs.d/init.el' file by:
- (setq ess-sleep-for 0.2)
-
- For example, '(setq ess-sas-global-unix-keys t)' keys shown, '(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
-'C-x C-f foo.sas'. 'FOO.sas' will be in ESS[SAS] mode. Edit as
-appropriate, then save and submit the batch SAS job.
- <F3> (<F8>)
- The job runs in the '*shell*' buffer while you continue to edit
-'FOO.sas'. If 'ess-sas-submit-method' is ''sh', then the message buffer
-will display the shell notification when the job is complete. The ''sh'
-setting also allows you to terminate the SAS batch job before it is
-finished.
- <F8> (<F3>)
- Terminating a SAS batch in the '*shell*' buffer.
- kill PID
- You may want to visit the '.log' (whether the job is still running or
-it is finished) and check for error messages. The '.log' will be
-refreshed and you will be placed in it's buffer. You will be taken to
-the first error message, if any.
- <F5> (<F6>)
- Goto the next error message, if any.
- <F5> (<F6>)
- Now, 'refresh' the '.lst' and go to it's buffer.
- <F6> (<F7>)
- If you wish to make changes, go to the '.sas' file with.
- <F4> (<F5>)
- Make your editing changes and submit again.
- <F3> (<F8>)
-
-\1f
-File: ess.info, Node: ESS(SAS)--Function keys for batch processing, Next: iESS(SAS)--Interactive SAS processes, Prev: ESS(SAS)--Batch SAS processes, Up: ESS for SAS
-
-13.5 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
-(GECS) which do not allow function keys to be bound so that they are
-available to the user.
-
- Options 2-5. Since 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).
-
- a. SAS Display Manager has different function key definitions for UNIX
- (2, 4) and Windows (3, 5); ESS[SAS] can use either.
- b. 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
- 'auto-mode-alist'.
-
- The distinction between local and global is subtle. If you want the
-ESS[SAS] definitions to work when you are in the '*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.
-
- a. For a site installation or an individual, place *ONLY ONE* of the
- following lines in your initialization file prior to a
- 'require'/'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:
- ;;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)
-
- The names '-unix-' and '-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.
-
- b. If your site installation has configured the keys contrary to your
- liking, then you must call the appropriate function.
- (load "ess-site") ;; local-unix-keys
- (ess-sas-global-pc-keys)
-
- 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).
-
-UNIX PC Nickname
-<F2> <F2> 'refresh'
- revert the current buffer with the file of the same name if the file is
- newer than the buffer
-<F3> <F8> 'SUBMIT'
- save the current '.sas' file (which is either the '.sas' file in the
- current buffer or the '.sas' file associated with the '.lst' or '.log'
- file in the current buffer) and submit the file as a batch SAS job
-<F4> <F5> 'PROGRAM'
- switch buffer to '.sas' file
-<F5> <F6> 'LOG'
- switch buffer to '.log' file, 'refresh' and goto next error message, if
- any
-<F6> <F7> 'OUTPUT'
- switch buffer to '.lst' file and 'refresh'
-<F7> <F4> 'filetype-1'
- switch buffer to 'filetype-1' (defaults to '.txt') file and 'refresh'
-<F8> <F3> 'shell'
- switch buffer to '*shell*'
-<F9> <F9> 'VIEWTABLE'
- open an interactive 'PROC FSEDIT' session on the SAS dataset near point
-<F10> <F10> toggle-log
- toggle ESS[SAS] for '.log' files; useful for certain debugging situations
-<F11> <F11> 'filetype-2'
- switch buffer to 'filetype-2' (defaults to '.dat') file and 'refresh'
-<F12> <F12> viewgraph
- open a 'GSASFILE' near point for viewing either in emacs or with an
- external viewer
-'C-<F1>' 'C-<F1>' rtf-portrait
- create an MS RTF portrait file from the current buffer with a file
- extension of '.rtf'
-'C-<F2>' 'C-<F2>' rtf-landscape
- create an MS RTF landscape file from the current buffer with a file
- extension of '.rtf'
-'C-<F3>' 'C-<F8>' submit-region
- write region to 'ess-temp.sas' and submit
-'C-<F5>' 'C-<F6>' append-to-log
- append 'ess-temp.log' to the current '.log' file
-'C-<F6>' 'C-<F7>' append-to-output
- append 'ess-temp.lst' to the current '.lst' file
-'C-<F9>' 'C-<F9>' 'INSIGHT'
- open an interactive 'PROC INSIGHT' session on the SAS dataset near point
-'C-<F10>''C-<F10>'toggle-listing
- toggle ESS[SAS] for '.lst' files; useful for toggling read-only
-
- 'SUBMIT', 'PROGRAM', 'LOG' and '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.
-
- 'shell' switches you to the '*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 '*shell*') with the
-buffer-local variable '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 'ess-sas-submit-method'.
-
- <F2> performs the 'refresh' operation on the current buffer.
-'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 'LOG', 'OUTPUT', 'filetype-1' or <F11> are pressed.
-
- 'filetype-1' switches you to a file with the same file name as your
-'.sas' file, but with a different extension ('.txt' by default) and
-performs 'refresh'. You can over-ride the default extension; for
-example in your '~/.emacs' or '~/.emacs.d/init.el' file:
- (setq ess-sas-suffix-1 "csv") ; for example
-
- <F9> will prompt you for the name of a permanent SAS dataset near
-point to be opened for viewing by 'PROC FSEDIT'. You can control the
-SAS batch command-line with 'ess-sas-data-view-submit-options'. For
-controlling the SAS batch commands, you have the global variables
-'ess-sas-data-view-libname' and 'ess-sas-data-view-fsview-command' as
-well as the buffer-local variable 'ess-sas-data-view-fsview-statement'.
-If you have your SAS 'LIBNAME' defined in '~/autoexec.sas', then the
-defaults for these variables should be sufficient.
-
- Similarly, 'C-<F9>' will prompt you for the name of a permanent SAS
-dataset near point to be opened for viewing by 'PROC INSIGHT'. You can
-control the SAS batch command-line with
-'ess-sas-data-view-submit-options'. For controlling the SAS batch
-commands, you have the global variables 'ess-sas-data-view-libname' and
-'ess-sas-data-view-insight-command' as well as the buffer-local variable
-'ess-sas-data-view-insight-statement'.
-
- <F10> toggles ESS[SAS] mode for '.log' files which is off by default
-(technically, it is 'SAS-log-mode', but it looks the same). The syntax
-highlighting can be helpful in certain debugging situations, but large
-'.log' files may take a long time to highlight.
-
- <F11> is the same as 'filetype-1' except it is '.dat' by default.
-
- <F12> will prompt you for the name of a 'GSASFILE' near the point in
-'.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 '.gif' and '.jpg' files internally. You
-may need to change the following variables for your own situation.
-'ess-sas-graph-view-suffix-regexp' is a regular expression of supported
-file types defined via file name extensions.
-'ess-sas-graph-view-viewer-default' is the default external viewer for
-your platform. '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.
- (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
-
- 'C-<F2>' produces US landscape by default, however, it can produce A4
-landscape (first line for "global" key mapping, second for "local"):
- (global-set-key [(control f2)] 'ess-sas-rtf-a4-landscape)
- (define-key sas-mode-local-map [(control f2)] 'ess-sas-rtf-a4-landscape)
-
-\1f
-File: ess.info, Node: iESS(SAS)--Interactive SAS processes, Next: iESS(SAS)--Common problems, Prev: ESS(SAS)--Function keys for batch processing, Up: ESS for SAS
-
-13.6 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 '"-stdio -linesize 80 -noovp
--nosyntaxcheck"' (the default of 'inferior-SAS-args').
-
- '-stdio'
- required to make the redirection of stdio work
- '-linesize 80'
- keeps output lines from folding on standard terminals
- '-noovp'
- prevents error messages from printing 3 times
- '-nosyntaxcheck'
- permits recovery after syntax errors
-
- To start up iESS[SAS] mode, use:
- M-x SAS
-
- The '*SAS:1.log*' buffer in 'ESStr' mode corresponds to the file
-'FOO.log' in SAS batch usage and to the 'SAS: LOG' window in the SAS
-Display Manager. All commands submitted to SAS, informative messages,
-warnings, and errors appear here.
-
- The '*SAS:1.lst*' buffer in 'ESSlst' mode corresponds to the file
-'FOO.lst' in SAS batch usage and to the 'SAS: OUTPUT' window in the SAS
-Display Manager. All printed output appears in this window.
-
- The '*SAS:1*' buffer exists solely as a communications buffer. The
-user should never use this buffer directly. Files are edited in the
-'FOO.sas' buffer. The 'C-c C-r' key in ESS[SAS] is the functional
-equivalent of bringing a file into the 'SAS: PROGRAM EDITOR' window
-followed by 'SUBMIT'.
-
- For example, open the file you want to work with.
- C-x C-f foo.sas
- 'FOO.sas' will be in ESS[SAS] mode. Edit as appropriate, and then
-start up SAS with the cursor in the 'FOO.sas' buffer.
- M-x SAS
- Four buffers will appear on screen:
-Buffer Mode Description
-'FOO.sas' 'ESS[SAS]' your source file
-'*SAS:1*' 'iESS[SAS:1]' iESS communication buffer
-'*SAS:1.log*' 'Shell ESStr SAS log information
- []'
-'*SAS:1.lst*' 'Shell ESSlst SAS listing information
- []'
- 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 'FOO.sas'. Enter the sequence 'C-c C-w'. The cursor
-will normally be in buffer 'FOO.sas'. If not, put it there and
-'C-x b 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
-'DATA' or 'PROC' and end with 'RUN;'), '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
-'FOO.sas' buffer and resubmit with another 'C-c C-r'.
-
- At the end of the session you may save the log and listing buffers
-with the usual 'C-x C-s' commands. You will be prompted for a file
-name. Typically, the names 'FOO.log' and '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 'C-x C-q'.
-
- At the end of the session, the input file '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 '*SAS:1*' buffer is strictly for ESS use. The user should never
-need to read it or write to it. Refer to the '.lst' and '.log' buffers
-for monitoring output!
-
- Troubleshooting: *Note iESS(SAS)--Common problems::.
-
-\1f
-File: ess.info, Node: iESS(SAS)--Common problems, Next: ESS(SAS)--Graphics, Prev: iESS(SAS)--Interactive SAS processes, Up: ESS for SAS
-
-13.7 iESS[SAS]-Common problems
-==============================
-
- 1. iESS[SAS] does not work on Windows. In order to run SAS inside an
- emacs buffer, it is necessary to start SAS with the '-stdio'
- option. SAS does not support the '-stdio' option on Windows.
- 2. If 'M-x SAS' gives errors upon startup, check the following:
- * you are running Windows: see 1.
- * 'ess-sas-sh-command' (from the ESS 'etc' directory) needs to
- be executable; too check, type 'M-x dired'; if not, fix it as
- follows, type 'M-:', then at the minibuffer prompt 'Eval:',
- type '(set-file-modes "ess-sas-sh-command" 493)'.
- * 'sas' isn't in your executable path; to verify, type 'M-:' and
- at the minibuffer prompt 'Eval:', type '(executable-find
- "sas")'
- 3. 'M-x SAS' starts SAS Display Manager. Probably, the command 'sas'
- on your system calls a shell script. In that case you will need to
- locate the real 'sas' executable and link to it. You can execute
- the UNIX command:
- find / -name sas -print
- Now place a soft link to the real 'sas' executable in your '~/bin'
- directory, with for example
- cd ~/bin
- ln -s /usr/local/sas9/sas sas
- Check your 'PATH' environment variable to confirm that '~/bin'
-appears before the directory in which the 'sas' shell script appears.
-
-\1f
-File: ess.info, Node: ESS(SAS)--Graphics, Next: ESS(SAS)--Windows, Prev: iESS(SAS)--Common problems, Up: ESS for SAS
-
-13.8 ESS[SAS]-Graphics
-======================
-
-Output from a SAS/GRAPH '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 <F12>, then include the following (either in 'FOO.sas' or in
-'~/autoexec.sas'):
- filename gsasfile 'graphics.ps';
- goptions device=ps gsfname=gsasfile gsfmode=append;
- '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:
- proc plot;
- plot a*b / vpos=25;
- run;
-
-\1f
-File: ess.info, Node: ESS(SAS)--Windows, Prev: ESS(SAS)--Graphics, Up: ESS for SAS
-
-13.9 ESS[SAS]-Windows
-=====================
-
- * iESS[SAS] does not work on Windows. *Note iESS(SAS)--Common
- problems::.
-
- * ESS[SAS] mode for editing SAS language files works very well.
- *Note ESS(SAS)--Editing files::.
-
- * There are two execution options for SAS on Windows. You can use
- batch. *Note 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.
-
-\1f
-File: ess.info, Node: ESS for BUGS, Next: ESS for JAGS, Prev: ESS for SAS, Up: Top
-
-14 ESS for BUGS
-***************
-
-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.
-
-14.1 ESS[BUGS]-Model files
-==========================
-
-Model files with the '.bug' extension are edited in ESS[BUGS] mode.
-Three keys are bound for your use in ESS[BUGS], 'F2', 'C-c C-c' and '='.
-'F2' performs the same action as it does in ESS[SAS], *Note
-ESS(SAS)--Function keys for batch processing::. 'C-c C-c' performs the
-function '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.
-'=' inserts the set operator, '<-'.
-
-14.2 ESS[BUGS]-Command files
-============================
-
-Files ending in '.bmd' are used for BUGS command files. When you have
-finished editing your model file and press 'C-c C-c', a command file is
-created if one does not already exist. When you are finished editing
-your command file, pressing 'C-c C-c' again will submit your command
-file as a batch job.
-
-14.3 ESS[BUGS]-Log files
-========================
-
-The '.bog' extension is used for BUGS log files. The command line
-generated by ESS creates the '.bog' transcript file.
-
-\1f
-File: ess.info, Node: ESS for JAGS, Next: Mailing lists/bug reports, Prev: ESS for BUGS, Up: Top
-
-15 ESS for JAGS
-***************
-
-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.
-
-15.1 ESS[JAGS]-Model files
-==========================
-
-Files with the '.jag' extension are edited in ESS[JAGS] mode. Three
-keys are bound for your use in ESS[JAGS], 'F2', 'C-c C-c' and '='. 'F2'
-performs the same action as it does in ESS[SAS], *Note
-ESS(SAS)--Function keys for batch processing::. 'C-c C-c' performs the
-function '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.
-'=' inserts the set operator, '<-'.
-
- The first press of 'C-c C-c' will set up a template, including some
-necessary file-local variables in an empty buffer. These variables are
-'ess-jags-chains', 'ess-jags-monitor', 'ess-jags-thin',
-'ess-jags-burnin' and 'ess-jags-update'; they appear in the 'Local
-Variables' section. When you are finished editing your model file,
-pressing 'C-c C-c' will perform the necessary actions to build your
-command file for you.
-
- The 'ess-jags-chains' variable is the number of chains that you want
-to initialize and sample from; defaults to 1. The 'ess-jags-monitor'
-variable is a list of variables that you want monitored: encase each
-variable in double quotes. When you press '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
-'ess-jags-thin' variable is the thinning parameter. By default, the
-thinning parameter is set to 1, i.e. no thinning. The
-'ess-jags-burnin' variable is the number of initial samples to discard.
-By default, the burnin parameter is set to 10000. The 'ess-jags-update'
-variable is the number of post-burnin samples to keep. By default, the
-update parameter is set to 10000. Both 'ess-jags-burnin' and
-'ess-jags-update' are multiplied by 'ess-jags-thin' since JAGS does not
-do it automatically.
-
-15.2 ESS[JAGS]-Command files
-============================
-
-Files ending in '.jmd' are for JAGS command files. For your '.jmd'
-file, there is only one variable, 'ess-jags-command', in the 'Local
-Variables' section. When you have finished editing your model file and
-press 'C-c C-c', a command file is created if one does not already
-exist. When you are finished editing your command file, pressing 'C-c
-C-c' again will submit your command file as a batch job. The
-'ess-jags-command' variable allows you to specify a different JAGS
-program to use to run your model; defaults to "jags".
-
-15.3 ESS[JAGS]-Log files
-========================
-
-The '.jog' extension is used for JAGS log files. You may find 'F2'
-useful to refresh the '.jog' if the batch process over-writes or appends
-it.
-
-\1f
-File: ess.info, Node: Mailing lists/bug reports, Next: Customization, Prev: ESS for JAGS, Up: Top
-
-16 Bugs and Bug Reporting, Mailing Lists
-****************************************
-
-* Menu:
-
-* Bugs::
-* Reporting Bugs::
-* Mailing Lists::
-* Help with Emacs::
-
-\1f
-File: ess.info, Node: Bugs, Next: Reporting Bugs, Up: Mailing lists/bug reports
-
-16.1 Bugs
-=========
-
- * Commands like '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.
-
- * The '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 _windows_ with 'window-point' at the right
- place.
-
- * It's possible to clear the modification flag (say, by saving the
- buffer) with the edit buffer not having been loaded into S.
-
- * Backup files can sometimes be left behind, even when
- 'ess-keep-dump-files' is 'nil'.
-
- * Passing an incomplete S expression to 'ess-execute' causes ESS to
- hang.
-
- * 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).
-
- * Multi-line commands could be handled better by the command history
- mechanism.
-
- * Changes to the continutation prompt in R (e.g. '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 'inferior-ess-secondary-prompt' in
- 'R-customize-alist'.
-
-\1f
-File: ess.info, Node: Reporting Bugs, Next: Mailing Lists, Prev: Bugs, Up: Mailing lists/bug reports
-
-16.2 Reporting Bugs
-===================
-
-Please send bug reports, suggestions etc. to <ESS-bugsNOSPAMr-project.org>,
-or post them on our github issue tracker
-(https://github.com/emacs-ess/ESS/issues)
-
- The easiest way to do this is within Emacs by typing
-
- '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.
-
-\1f
-File: ess.info, Node: Mailing Lists, Next: Help with Emacs, Prev: Reporting Bugs, Up: Mailing lists/bug reports
-
-16.3 Mailing Lists
-==================
-
-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 <ess-help-requestNOSPAMr-project.org>; contributions
-to the list may be mailed to <ess-helpNOSPAMr-project.org>. Rest assured,
-this is a fairly low-volume mailing list.
-
- The purposes of the mailing list include
-
- * helping users of ESS to get along with it.
- * discussing aspects of using ESS.
- * suggestions for improvements.
- * announcements of new releases of ESS.
- * posting small patches to ESS.
-
-\1f
-File: ess.info, Node: Help with Emacs, Prev: Mailing Lists, Up: Mailing lists/bug reports
-
-16.4 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 'M-x view-emacs-faq') and EmacsWiki
-(<https://www.emacswiki.org>). Please consult them before asking on the
-mailing list about issues that are not specific to ESS.
-
-\1f
-File: ess.info, Node: Customization, Next: Indices, Prev: Mailing lists/bug reports, Up: Top
-
-Appendix A Customizing ESS
-**************************
-
-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 '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.
-
-\1f
-File: ess.info, Node: Indices, Prev: Customization, Up: Top
-
-Indices
-*******
-
-* Menu:
-
-* Key index::
-* Function and program index::
-* Variable index::
-* Concept index::
-
-\1f
-File: ess.info, Node: Key index, Next: Function and program index, Up: Indices
-
-Key index
-=========
-
-\0\b[index\0\b]
-* Menu:
-
-* ,: Handy commands. (line 6)
-* {: Indenting. (line 53)
-* }: Indenting. (line 53)
-* C-c C-. d: Package listing. (line 30)
-* C-c C-. H: Package listing. (line 33)
-* C-c C-. l: Package listing. (line 10)
-* C-c C-. m: Package listing. (line 21)
-* C-c C-. r: Package listing. (line 13)
-* C-c C-. s: Package listing. (line 27)
-* C-c C-. u: Package listing. (line 17)
-* C-c C-. w: Package listing. (line 24)
-* C-c C-b: Evaluating code. (line 66)
-* C-c C-c: Other. (line 9)
-* C-c C-c <1>: Evaluating code. (line 39)
-* C-c C-e C-d: Edit buffer. (line 9)
-* C-c C-e C-s: Styles. (line 15)
-* C-c C-e s: Styles. (line 15)
-* C-c C-f: Evaluating code. (line 52)
-* C-c C-j: Evaluating code. (line 45)
-* C-c C-o C-c: Roxygen. (line 45)
-* C-c C-o C-h: Roxygen. (line 72)
-* C-c C-o C-o: Roxygen. (line 37)
-* C-c C-o C-r: Roxygen. (line 51)
-* C-c C-o C-t: Roxygen. (line 59)
-* C-c C-o n: Roxygen. (line 69)
-* C-c C-o p: Roxygen. (line 66)
-* C-c C-q: Hot keys. (line 71)
-* C-C C-r: Evaluating code. (line 59)
-* C-c C-s: Hot keys. (line 34)
-* C-c C-t C-s: Namespaced Evaluation.
- (line 36)
-* C-c C-v: Hot keys. (line 66)
-* C-c C-w: Clean. (line 11)
-* C-c C-x: Hot keys. (line 24)
-* C-c C-z: Other. (line 13)
-* C-c M-b: Evaluating code. (line 69)
-* C-c M-f: Evaluating code. (line 55)
-* C-c M-j: Evaluating code. (line 48)
-* C-c M-l: Hot keys. (line 50)
-* C-c M-r: Evaluating code. (line 62)
-* C-c RET: Resubmit. (line 14)
-* C-c `: Error Checking. (line 9)
-* C-j: Indenting. (line 60)
-* C-M-a: Other edit buffer commands.
- (line 10)
-* C-M-e: Other edit buffer commands.
- (line 14)
-* C-M-h: Other edit buffer commands.
- (line 18)
-* C-M-q: Indenting. (line 49)
-* C-M-x: Evaluating code. (line 36)
-* C-RET: Evaluating code. (line 32)
-* ESC C-a: Other edit buffer commands.
- (line 10)
-* ESC C-e: Other edit buffer commands.
- (line 14)
-* ESC C-h: Other edit buffer commands.
- (line 18)
-* ESC C-q: Indenting. (line 49)
-* M-;: Indenting. (line 65)
-* M-?: Object names. (line 33)
-* M-C-q: Indenting. (line 49)
-* M-n l: Sweave and AUCTeX. (line 24)
-* M-n P: Sweave and AUCTeX. (line 30)
-* M-n s: Sweave and AUCTeX. (line 20)
-* M-RET: Resubmit. (line 10)
-* RET: Command-line editing. (line 10)
-* RET <1>: Resubmit. (line 18)
-* TAB: Indenting. (line 35)
-
-\1f
-File: ess.info, Node: Function and program index, Next: Variable index, Prev: Key index, Up: Indices
-
-Function and program index
-==========================
-
-\0\b[index\0\b]
-* Menu:
-
-* backward-kill-word: Command-line editing.
- (line 22)
-* comint-backward-matching-input: Process buffer motion.
- (line 31)
-* comint-bol: Command-line editing.
- (line 31)
-* comint-copy-old-input: Transcript resubmit. (line 16)
-* comint-delete-output: Last command. (line 24)
-* comint-dynamic-complete: Object names. (line 12)
-* comint-forward-matching-input: Process buffer motion.
- (line 32)
-* comint-history-isearch-backward-regexp: Command History. (line 32)
-* comint-interrupt-subjob: Other. (line 8)
-* comint-kill-input: Command-line editing.
- (line 26)
-* comint-next-input: Command History. (line 18)
-* comint-next-matching-input-from-input: Command History. (line 45)
-* comint-next-prompt: Process buffer motion.
- (line 15)
-* comint-previous-input: Command History. (line 14)
-* comint-previous-matching-input-from-input: Command History. (line 41)
-* comint-previous-prompt: Process buffer motion.
- (line 11)
-* comint-show-output: Last command. (line 20)
-* dump(): Edit buffer. (line 35)
-* ess-change-directory: Package listing. (line 29)
-* ess-cleanup: Hot keys. (line 71)
-* ess-cleanup <1>: Help. (line 170)
-* ess-complete-object-name: Object names. (line 32)
-* ess-describe-help-mode: Help. (line 21)
-* ess-display-help-on-object: Hot keys. (line 65)
-* ess-display-help-on-object <1>: Help. (line 8)
-* ess-display-help-on-object <2>: Help. (line 25)
-* ess-dump-object-into-edit-buffer: Edit buffer. (line 8)
-* ess-electric-brace: Indenting. (line 52)
-* ess-eval-buffer: Evaluating code. (line 65)
-* ess-eval-buffer-and-go: Evaluating code. (line 68)
-* ess-eval-function: Evaluating code. (line 51)
-* ess-eval-function-and-go: Evaluating code. (line 54)
-* ess-eval-line: Evaluating code. (line 44)
-* ess-eval-line-and-go: Evaluating code. (line 47)
-* ess-eval-line-and-step: Help. (line 106)
-* ess-eval-region: Evaluating code. (line 58)
-* ess-eval-region <1>: Help. (line 111)
-* ess-eval-region-and-go: Evaluating code. (line 61)
-* ess-eval-region-or-function-or-paragraph: Evaluating code. (line 35)
-* ess-eval-region-or-function-or-paragraph-and-step: Evaluating code.
- (line 38)
-* ess-eval-region-or-line-and-step: Evaluating code. (line 31)
-* ess-execute-objects: Hot keys. (line 23)
-* ess-execute-search: Hot keys. (line 33)
-* ess-goto-beginning-of-function-or-para: Other edit buffer commands.
- (line 9)
-* ess-goto-end-of-function-or-para: Other edit buffer commands.
- (line 13)
-* ess-handy-commands: Handy commands. (line 6)
-* ess-handy-commands <1>: Handy commands. (line 6)
-* ess-indent-command: Roxygen. (line 90)
-* ess-indent-exp: Indenting. (line 48)
-* ess-indent-or-complete: Indenting. (line 34)
-* ess-load-file: Hot keys. (line 49)
-* ess-load-file <1>: Loading. (line 11)
-* ess-mark-function: Other edit buffer commands.
- (line 17)
-* ess-parse-errors: Hot keys. (line 54)
-* ess-parse-errors <1>: Error Checking. (line 9)
-* ess-quit: Hot keys. (line 70)
-* ess-quit <1>: Help. (line 170)
-* ess-R-complete-object-name: Roxygen. (line 80)
-* ess-r-package-list-available-packages: Package listing. (line 12)
-* ess-r-package-list-local-packages: Package listing. (line 9)
-* ess-r-package-update-packages: Package listing. (line 16)
-* ess-r-set-evaluation-env: Namespaced Evaluation.
- (line 35)
-* ess-remote: ESS processes on Remote Computers.
- (line 9)
-* ess-request-a-process: Multiple ESS processes.
- (line 18)
-* ess-resynch: Object names. (line 52)
-* ess-roxy-hide-all: Roxygen. (line 71)
-* ess-roxy-move-beginning-of-line: Roxygen. (line 97)
-* ess-roxy-next-entry: Roxygen. (line 68)
-* ess-roxy-preview-HTML: Roxygen. (line 58)
-* ess-roxy-preview-Rd: Roxygen. (line 50)
-* ess-roxy-previous-entry: Roxygen. (line 65)
-* ess-roxy-toggle-roxy-region: Roxygen. (line 44)
-* ess-roxy-update-entry: Roxygen. (line 36)
-* ess-rutils-html-docs: Package listing. (line 32)
-* ess-rutils-load-wkspc: Package listing. (line 23)
-* ess-rutils-rm-all: Package listing. (line 20)
-* ess-rutils-save-wkspc: Package listing. (line 26)
-* ess-set-style: Styles. (line 14)
-* ess-skip-to-help-section: Help. (line 55)
-* ess-skip-to-next-section: Help. (line 46)
-* ess-skip-to-previous-section: Help. (line 46)
-* ess-smart-comma: Handy commands. (line 6)
-* ess-submit-bug-report: Reporting Bugs. (line 6)
-* ess-switch-to-end-of-ESS: Help. (line 117)
-* ess-switch-to-inferior-or-script-buffer: Other. (line 12)
-* ess-swv-latex: Sweave and AUCTeX. (line 23)
-* ess-swv-PDF: Sweave and AUCTeX. (line 29)
-* ess-swv-PS: Sweave and AUCTeX. (line 26)
-* ess-swv-weave: Sweave and AUCTeX. (line 19)
-* ess-tracebug: ESS tracebug. (line 6)
-* ess-transcript-clean-region: Clean. (line 10)
-* ess-transcript-copy-command: Resubmit. (line 13)
-* ess-transcript-send-command: Resubmit. (line 9)
-* ess-transcript-send-command-and-move: Resubmit. (line 17)
-* ess-use-ido, ess-completing-read: Minibuffer completion.
- (line 6)
-* fill-paragraph: Roxygen. (line 94)
-* getting started with tracebug: Getting started with tracebug.
- (line 6)
-* inferior-ess-send-input: Command-line editing.
- (line 9)
-* mark-paragraph: Roxygen. (line 85)
-* newline-and-indent: Roxygen. (line 102)
-* objects(): Hot keys. (line 24)
-* printer(): printer. (line 11)
-* q(): Hot keys. (line 71)
-* R: Starting up. (line 11)
-* S: Starting up. (line 11)
-* search(): Hot keys. (line 34)
-* search() <1>: Object names. (line 19)
-* source(): Evaluating code. (line 18)
-* source() <1>: Loading. (line 11)
-* STERM: Statistical Process running in ESS?.
- (line 6)
-
-\1f
-File: ess.info, Node: Variable index, Next: Concept index, Prev: Function and program index, Up: Indices
-
-Variable index
-==============
-
-\0\b[index\0\b]
-* Menu:
-
-* comint-delimiter-argument-list: History expansion. (line 28)
-* comint-input-ring-size: Command History. (line 9)
-* comment-column: Indenting. (line 24)
-* ess-ask-about-transfile: Customizing startup. (line 36)
-* ess-ask-about-transfile <1>: Saving transcripts. (line 12)
-* ess-ask-for-ess-directory: Customizing startup. (line 7)
-* ess-ask-for-ess-directory <1>: Customizing startup. (line 21)
-* ess-auto-width: Customizing startup. (line 56)
-* ess-auto-width-visible: Customizing startup. (line 56)
-* ess-delete-dump-files: Source Files. (line 12)
-* ess-directory: Source Directories. (line 48)
-* ess-dump-filename-template: Source Directories. (line 9)
-* ess-eldoc-abbreviation-style: ESS ElDoc. (line 24)
-* ess-eldoc-show-on-symbol: ESS ElDoc. (line 18)
-* ess-eval-visibly: Evaluating code. (line 14)
-* ess-execute-in-process-buffer: Hot keys. (line 13)
-* ess-first-tab-never-complete: Indenting. (line 42)
-* ess-first-tab-never-complete <1>: Object names. (line 6)
-* ess-function-template: Edit buffer. (line 17)
-* ess-handy-commands: Handy commands. (line 6)
-* ess-handy-commands <1>: Handy commands. (line 9)
-* ess-indent-with-fancy-comments: Indenting. (line 27)
-* ess-keep-dump-files: Source Files. (line 26)
-* ess-plain-first-buffername: Multiple ESS processes.
- (line 14)
-* ess-post-run-hook: Customizing startup. (line 26)
-* ess-pre-run-hook: Customizing startup. (line 21)
-* ess-r-flymake-linters: ESS Flymake. (line 16)
-* ess-r-flymake-lintr-cache: ESS Flymake. (line 23)
-* ess-R-font-lock-keywords: Highlighting. (line 19)
-* ess-search-list: Source Directories. (line 62)
-* ess-source-directory: Source Directories. (line 22)
-* ess-style: Styles. (line 21)
-* ess-style-alist: Styles. (line 28)
-* ess-switch-to-end-of-proc-buffer: Other. (line 21)
-* ess-swv-pdflatex-commands: Sweave and AUCTeX. (line 35)
-* ess-use-eldoc: ESS ElDoc. (line 13)
-* ess-use-flymake: ESS Flymake. (line 12)
-* iESS program arguments: Customizing startup. (line 48)
-* inferior-ess-program: Customizing startup. (line 48)
-* inferior-R-font-lock-keywords: Highlighting. (line 12)
-* Rd-indent-level: R documentation files.
- (line 78)
-* Rd-mode-hook: R documentation files.
- (line 75)
-* Rd-to-help-command: R documentation files.
- (line 82)
-
-\1f
-File: ess.info, Node: Concept index, Prev: Variable index, Up: Indices
-
-Concept Index
-=============
-
-\0\b[index\0\b]
-* Menu:
-
-* aborting R commands: Other. (line 9)
-* aborting S commands: Other. (line 9)
-* arguments to R program: Customizing startup. (line 51)
-* arguments to S program: Customizing startup. (line 51)
-* authors: Credits. (line 6)
-* autosaving: Source Files. (line 83)
-* bug reports: Reporting Bugs. (line 6)
-* bugs: Bugs. (line 6)
-* changing ESS processes: Multiple ESS processes.
- (line 6)
-* cleaning up: Hot keys. (line 71)
-* comint: Credits. (line 6)
-* command history: Command History. (line 6)
-* command line arguments: iESS(R)--Inferior ESS processes.
- (line 16)
-* command-line completion: Object names. (line 6)
-* command-line editing: Command-line editing.
- (line 6)
-* commands: Entering commands. (line 6)
-* comments: Source Files. (line 41)
-* comments in R: Indenting. (line 18)
-* company: Company. (line 6)
-* completion in edit buffer: Other edit buffer commands.
- (line 24)
-* completion of object names: Object names. (line 6)
-* completion on file names: Object names. (line 39)
-* completion on lists: Object names. (line 37)
-* completion, when prompted for object names: Edit buffer. (line 14)
-* creating new objects: Edit buffer. (line 14)
-* credits: Credits. (line 6)
-* customization: Customization. (line 6)
-* data frames: Object names. (line 20)
-* deleting output: Last command. (line 24)
-* directories: Starting up. (line 11)
-* dump file directories: Source Directories. (line 20)
-* dump file names: Source Directories. (line 6)
-* dump files: Edit buffer. (line 27)
-* dump files <1>: Source Files. (line 10)
-* echoing commands when evaluating: Evaluating code. (line 18)
-* edit buffer: Edit buffer. (line 6)
-* editing commands: Command History. (line 6)
-* editing functions: Editing objects. (line 6)
-* editing transcripts: Saving transcripts. (line 18)
-* ElDoc: ESS ElDoc. (line 6)
-* emacsclient: Emacsclient. (line 6)
-* entering commands: Entering commands. (line 6)
-* errors: Error Checking. (line 6)
-* ESS commands blocking Emacs: Evaluating code. (line 18)
-* ess developer: Namespaced Evaluation.
- (line 6)
-* ESS process buffer: Starting up. (line 17)
-* ESS process directory: Starting up. (line 11)
-* ESS tracebug: ESS tracebug. (line 6)
-* ESS-elsewhere: ESS processes on Remote Computers.
- (line 9)
-* ess-roxy: Roxygen. (line 6)
-* evaluating code with echoed commands: Evaluating code. (line 18)
-* evaluating R expressions: Evaluating code. (line 29)
-* evaluating S expressions: Evaluating code. (line 29)
-* finding function definitions: Xref. (line 6)
-* flymake: ESS Flymake. (line 6)
-* font-lock mode: Highlighting. (line 7)
-* formatting source code: Indenting. (line 32)
-* graphics: Graphics. (line 6)
-* Handy commands: Handy commands. (line 6)
-* help files: Help. (line 6)
-* highlighting: Highlighting. (line 7)
-* historic backups: Source Files. (line 41)
-* hot keys: Hot keys. (line 43)
-* icicles: Icicles. (line 6)
-* IDO completions: Minibuffer completion.
- (line 6)
-* indenting: Indenting. (line 32)
-* installation: Installation. (line 6)
-* interactive use of R: Introduction. (line 31)
-* interactive use of S: Introduction. (line 31)
-* interrupting R commands: Other. (line 9)
-* interrupting S commands: Other. (line 9)
-* introduction: Introduction. (line 6)
-* keyboard short cuts: Hot keys. (line 43)
-* killing temporary buffers: Hot keys. (line 71)
-* killing the ESS process: Hot keys. (line 71)
-* lists, completion on: Object names. (line 37)
-* motion in transcript mode: Transcript Mode. (line 17)
-* multi-line commands, resubmitting: Transcript resubmit. (line 33)
-* multiple ESS processes: Multiple ESS processes.
- (line 6)
-* multiple inferior processes: Multiple ESS processes.
- (line 6)
-* multiple interactive processes: Multiple ESS processes.
- (line 6)
-* new objects, creating: Edit buffer. (line 14)
-* objects: Hot keys. (line 24)
-* pages in the process buffer: Transcript. (line 24)
-* paging commands in help buffers: Help. (line 28)
-* paragraphs in the process buffer: Transcript. (line 13)
-* parsing errors: Error Checking. (line 6)
-* process buffer: Starting up. (line 17)
-* process names: Multiple ESS processes.
- (line 8)
-* programming in R: Introduction. (line 43)
-* programming in S: Introduction. (line 43)
-* project work in R: Source Files. (line 41)
-* project work in S: Source Files. (line 41)
-* quitting from ESS: Hot keys. (line 71)
-* re-executing commands: Command History. (line 6)
-* reading long command outputs: Last command. (line 19)
-* remote Computers: ESS processes on Remote Computers.
- (line 9)
-* reverting function definitions: Edit buffer. (line 27)
-* roxy: Roxygen. (line 6)
-* Roxygen: Roxygen. (line 6)
-* running R: Starting up. (line 6)
-* running S: Starting up. (line 6)
-* S+elsewhere: ESS processes on Remote Computers.
- (line 9)
-* search list: Hot keys. (line 34)
-* search list <1>: Source Directories. (line 55)
-* sending input: Entering commands. (line 6)
-* Space in function argument completion: Function arguments. (line 10)
-* starting directory: Starting up. (line 11)
-* starting ESS: Starting up. (line 6)
-* STERM: Statistical Process running in ESS?.
- (line 6)
-* temporary buffers: Help. (line 169)
-* temporary buffers, killing: Hot keys. (line 71)
-* tracebug tutorial: Getting started with tracebug.
- (line 6)
-* tramp support: ESS processes on Remote Computers.
- (line 9)
-* transcript: Transcript. (line 9)
-* transcript file: Customizing startup. (line 40)
-* transcript file names: Saving transcripts. (line 13)
-* transcript mode motion: Transcript Mode. (line 17)
-* transcripts of R sessions: Introduction. (line 38)
-* transcripts of S sessions: Introduction. (line 38)
-* using ESS interactively: Introduction. (line 31)
-* using R interactively: Introduction. (line 31)
-* using S interactively: Introduction. (line 31)
-* winjava: winjava. (line 6)
-* working directory: Starting up. (line 11)
-* working directory <1>: Source Directories. (line 55)
-* X Windows: X11. (line 6)
-* xref: Xref. (line 6)
-
-
-\1f
-Tag Table:
-Node: Top\7f268
-Node: Introduction\7f2914
-Node: Features\7f5668
-Node: Current Features\7f6494
-Node: New features\7f9945
-Node: Credits\7f29468
-Node: Manual\7f33085
-Node: Installation\7f35751
-Node: Installing from a third-party repository\7f36688
-Node: Installing from source\7f37635
-Node: Activating and Loading ESS\7f39227
-Node: Check Installation\7f40301
-Node: Interactive ESS\7f40521
-Node: Starting up\7f41366
-Node: Multiple ESS processes\7f42110
-Node: ESS processes on Remote Computers\7f43191
-Node: Customizing startup\7f47294
-Node: Controlling buffer display\7f50184
-Node: Entering commands\7f52782
-Node: Command-line editing\7f53940
-Node: Transcript\7f55173
-Node: Last command\7f56942
-Node: Process buffer motion\7f58368
-Node: Transcript resubmit\7f59871
-Node: Saving transcripts\7f61836
-Node: Command History\7f63626
-Node: Saving History\7f67035
-Node: History expansion\7f67796
-Node: Hot keys\7f71007
-Node: Statistical Process running in ESS?\7f75077
-Node: Emacsclient\7f76356
-Node: Other\7f77148
-Node: Evaluating code\7f78167
-Node: Transcript Mode\7f81848
-Node: Resubmit\7f83001
-Node: Clean\7f84064
-Node: Editing objects\7f85060
-Node: Edit buffer\7f86178
-Node: Loading\7f88224
-Node: Error Checking\7f89251
-Node: Indenting\7f90300
-Node: Styles\7f93342
-Node: Other edit buffer commands\7f95716
-Node: Source Files\7f97372
-Node: Source Directories\7f101976
-Node: Help\7f105129
-Node: Completion\7f109573
-Node: Object names\7f109788
-Node: Function arguments\7f112422
-Node: Minibuffer completion\7f113365
-Node: Company\7f113839
-Node: Icicles\7f114226
-Node: Developing with ESS\7f115546
-Node: ESS tracebug\7f115992
-Node: Getting started with tracebug\7f118999
-Node: Editing documentation\7f121157
-Node: R documentation files\7f121707
-Node: Roxygen\7f125409
-Node: Namespaced Evaluation\7f129783
-Node: Extras\7f131781
-Node: ESS ElDoc\7f132805
-Node: ESS Flymake\7f134301
-Node: Handy commands\7f135395
-Node: Highlighting\7f136592
-Node: Parens\7f137627
-Node: Graphics\7f138103
-Node: printer\7f138774
-Node: X11\7f139530
-Node: winjava\7f139869
-Node: Imenu\7f140281
-Node: Toolbar\7f141128
-Node: Xref\7f141536
-Node: Rdired\7f141859
-Node: Package listing\7f142922
-Node: Org\7f144298
-Node: Sweave and AUCTeX\7f145252
-Node: ESS for R\7f147804
-Node: ESS(R)--Editing files\7f148104
-Node: iESS(R)--Inferior ESS processes\7f148605
-Node: Philosophies for using ESS(R)\7f151255
-Node: Example ESS usage\7f152182
-Node: ESS for SAS\7f153587
-Node: ESS(SAS)--Design philosophy\7f154310
-Node: ESS(SAS)--Editing files\7f155243
-Node: ESS(SAS)--TAB key\7f157097
-Node: ESS(SAS)--Batch SAS processes\7f158463
-Node: ESS(SAS)--Function keys for batch processing\7f163491
-Node: iESS(SAS)--Interactive SAS processes\7f172978
-Node: iESS(SAS)--Common problems\7f176732
-Node: ESS(SAS)--Graphics\7f178255
-Node: ESS(SAS)--Windows\7f179038
-Node: ESS for BUGS\7f179616
-Node: ESS for JAGS\7f181372
-Node: Mailing lists/bug reports\7f184724
-Node: Bugs\7f184988
-Node: Reporting Bugs\7f186613
-Node: Mailing Lists\7f187506
-Node: Help with Emacs\7f188233
-Node: Customization\7f188765
-Node: Indices\7f189539
-Node: Key index\7f189714
-Node: Function and program index\7f194846
-Node: Variable index\7f204266
-Node: Concept index\7f207827
-\1f
-End Tag Table
+++ /dev/null
-;;; essd-els.el --- S-PLUS 3.x at another location customization -*- lexical-binding: t; -*-
-
-;; Copyright (C) 1998 Richard M. Heiberger
-;; Copyright (C) 1999--2005 A.J. Rossini, Richard M. Heiberger, Martin
-;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
-
-;; Author: Richard M. Heiberger <rmhNOSPAMtemple.edu>
-;; Created: December 1998
-
-;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
-
-;; Keywords: languages
-
-;; 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 defines all the S-PLUS 3.x customizations for ess-mode.
-
-;;; Code:
-
-(require 'ess-julia)
-(require 'ess-s-lang)
-(require 'ess-sp6-d)
-(require 'ess-sas-d)
-(require 'ess-stata-mode)
-(require 'ess-trns)
-(require 'ess-utils)
-
-;; 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))
-
-(define-obsolete-function-alias 'S+elsewhere-transcript-mode #'S-transcript-mode "2000")
-
-;; 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" "arc" "vst" "omg" "s3" "s4" "stata" "sp3" "sp4"
- "sqpe4" "sp5" "sqpe" "XLS" "SAS"))
- (dialect (or dialect
- (ess-completing-read "Dialect" dialects nil t))))
- (cond
- ((string= dialect "julia") ess-julia-customize-alist)
- ((string= dialect "stata") STA-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))))
-
-
-\f ; Provide package
-
-(provide 'essd-els)
-
-;;; essd-els.el ends here
+++ /dev/null
-#!/usr/bin/Rscript
-## -*- mode: R -*-
-## code to build ESSR environemnt.
-## 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.load.ESSR('./R/')
-saveRDS(ESSR, file = "../ESSR.rds")
+++ /dev/null
-## -*- 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)
- })
-})
+++ /dev/null
-#### Essential functionality needed by ESS
-
-## Should work on *all* vesions 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?
- .ess.help <- function(...) {
- do.call(get("help", envir = .GlobalEnv), list(...))
- }
-
- if (.ess.Rversion > "2.10") {
- ## Abbreviating help_type to avoid underscore
- .ess.help(..., help = help.type)
- } else {
- .ess.help(..., htmlhelp = help.type == "html")
- }
-}
-
-.ess.getHelpAliases <- function(){
- readrds <-
- if(.ess.Rversion >= '2.13.0') readRDS
- else .readRDS
- rds.files <- paste(searchpaths(), "/help/aliases.rds", sep = "")
- unlist(lapply(rds.files,
- function(f){
- if( file.exists(f) )
- try(names(readrds(f)))
- }),
- use.names = FALSE)
-}
-
-### 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 cleanning 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))
- }
+++ /dev/null
-## 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
-
-## load .base.R and all other files into ESSR environment; then attach ESSR
-.ess.load.ESSR <- function(dir) {
- .source <-
- if(any("keep.source" == names(formals(sys.source))))
- sys.source
- else
- function(..., keep.source) sys.source(...)
-
- Rver <- if(exists("getRversion", mode="function")) getRversion()
- else paste(R.version$major, R.version$minor, sep=".")
- oldR <- Rver <= "1.3.0"
-
- ESSR <-
- if(oldR) ## 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.5"
- assign(".ess.ESSRversion", VERSION, envir = ESSR)
-
-
- ## .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(!oldR) # no sense if(oldR)
- for( f in dir(dir, pattern='\\.R$', full.names=TRUE) )
- try(.source(f, envir = ESSR, keep.source = FALSE))
-
- if(Rver >= "2.4.0")
- attach(ESSR)
- else if(!oldR) { ## borrow from older library()
- e <- attach(NULL, name = "ESSR")
- .Internal(lib.fixup(ESSR, e))
- } else { ## if(oldR), use as in that old library():
- .Internal(lib.fixup(ESSR, .GlobalEnv))
- }
-
- ## BUILDESSR needs this:
- invisible(ESSR)
-}
+++ /dev/null
-## 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"))
-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")
- }
-})
-
-\f
-.ess_eval <- function(str, env = globalenv()) {
- ## don't remove; really need eval(parse( here!!
- tryCatch(base::eval(base::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
-}
-
-.ess_srcref <- function(name, pkg) {
- if (!is.null(pkg) && requireNamespace(pkg)) {
- env <- asNamespace(pkg)
- } else {
- env <- globalenv()
- }
- fn <- .ess_eval(name, env)
- 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)
-}
-
-\f
-.ess_fn_pkg <- function(fn_name) {
- fn <- .ess_eval(fn_name)
- env_name <- base::environmentName(base::environment(fn))
- out <- if (base::is.primitive(fn)) { # environment() does not work on primitives.
- "base"
- } else if (base::is.function(fn) && env_name != "R_GlobalEnv") {
- env_name
- } else {
- ""
- }
- base::cat(base::sprintf("%s\n", out))
-}
-
-.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))
- }
-}
-
-\f
-.ess_get_completions <- function(string, end, suffix = " = ") {
- oldopts <- utils::rc.options(funarg.suffix = suffix)
- on.exit(utils::rc.options(oldopts))
- 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')
-}
+++ /dev/null
-### 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)
-}
-
-\f
-.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 realy 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))
-}
-
-\f
-.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)
- }))
-}
-
-\f
-### 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]
- for(i in seq_along(exps)) {
- cat('\n@---- ', .essWEnames[[i]], ' ',
- rep.int('-', max(0, 35 - nchar(.essWEnames[[i]]))), '-@\n', sep = '')
- cat(paste('@---:', deparse(exps[[i]][[1]])), ' \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' ))
- }
- }
-}
-
-\f
-.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)
-}
-
-\f
-.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
- }
-}
+++ /dev/null
-.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)
-}
-
-\f
-.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 suchs
- ## 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)
-}
-
-\f
-.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")
-}
+++ /dev/null
-## simple Message Parsing Inerface
-
-.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 = "\1e")
- cat(sprintf("\e_%s\1e%s\e\\", 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)
-}
-
+++ /dev/null
-## 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)
-}
-
-\f
-##' 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) {
- oldopts <- options(warn = 2)
- on.exit(options(oldopts))
- pname <- paste("package:", package, sep = "")
- envpkg <- tryCatch(as.environment(pname), error = function(cond) NULL)
- if (is.null(envpkg))
- if (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 namspace: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)
-}
-
-\f
-.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
-}
-
-\f
-.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)
-}
-
-\f
-.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
-}
-
-\f
-.ess.ns_insert_essenv <- function(nsenv) {
- if (is.character(nsenv))
- nsenv <- base::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)
-}
+++ /dev/null
-
-.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
-}
+++ /dev/null
-### 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
+++ /dev/null
-module 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
-
-\f
-### 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
-
-\f
-### 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
+++ /dev/null
-#!/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 </dev/tty 1>$1 2>$2 $3
-
-set -x
-stdout=$1
-stderr=$2
-shift 2
-set +x
-echo sas \</dev/tty 1\>$stdout 2\>$stderr $@
-sas </dev/tty 1>$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.
+++ /dev/null
-This is license.info, produced by makeinfo version 6.5 from
-license.texi.
-
-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.
-
-\1f
-Tag Table:
-\1f
-End Tag Table
+++ /dev/null
-This is mailing.info, produced by makeinfo version 6.5 from
-mailing.texi.
-
-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 <ess-help-request@r-project.org>; contributions
-to the list may be mailed to <ess-helpNOSPAMr-project.org>. Rest assured,
-this is a fairly low-volume mailing list.
-
- The purposes of the mailing list include
-
- * helping users of ESS to get along with it.
- * discussing aspects of using ESS.
- * suggestions for improvements.
- * announcements of new releases of ESS.
- * posting small patches to ESS.
-
-\1f
-Tag Table:
-\1f
-End Tag Table
+++ /dev/null
-;;; make-regexp.el --- generate efficient regexps to match strings.
-
-;; Copyright (C) 1994, 1995 Simon Marshall.
-
-;; Author: Simon Marshall <simonNOSPAMgnu.ai.mit.edu>
-;; Keywords: lisp, matching
-;; Version: 1.02
-
-;; LCD Archive Entry:
-;; make-regexp|Simon Marshall|simonNOSPAMgnu.ai.mit.edu|
-;; Generate efficient regexps to match strings.|
-;; 11-Jul-1995|1.02|~/functions/make-regexp.el.gz|
-
-;; The archive is archive.cis.ohio-state.edu in /pub/gnu/emacs/elisp-archive.
-
-;;; This file is not part of GNU Emacs.
-
-;;; This program is free software; you can redistribute it and/or modify
-;;; it under the terms of the GNU General Public License as published by
-;;; the Free Software Foundation; either version 2, 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.
-
-;; A copy of the GNU General Public License is available at
-;; https://www.r-project.org/Licenses/
-
-;;; Commentary:
-
-;; Purpose:
-;;
-;; To make efficient regexps from lists of strings.
-
-;; For example:
-;;
-;; (let ((strings '("cond" "if" "while" "let\\*?" "prog1" "prog2" "progn"
-;; "catch" "throw" "save-restriction" "save-excursion"
-;; "save-window-excursion" "save-match-data"
-;; "unwind-protect" "condition-case" "track-mouse")))
-;; (concat "(" (make-regexp strings t)))
-;;
-;; => "(\\(c\\(atch\\|ond\\(\\|ition-case\\)\\)\\|if\\|let\\*?\\|prog[12n]\\|save-\\(excursion\\|match-data\\|restriction\\|window-excursion\\)\\|t\\(hrow\\|rack-mouse\\)\\|unwind-protect\\|while\\)"
-;;
-;; To search for the above regexp takes about 70% of the time as for the simple
-;; (concat "(\\(" (mapconcat 'identity strings "\\|") "\\)") regexp.
-;;
-;; Obviously, the more the similarity between strings, the faster the regexp:
-;;
-;; (make-regexp '("abort" "abs" "accept" "access" "array" "begin" "body" "case"
-;; "constant" "declare" "delay" "delta" "digits" "else" "elsif"
-;; "entry" "exception" "exit" "function" "generic" "goto" "if"
-;; "others" "limited" "loop" "mod" "new" "null" "out" "subtype"
-;; "package" "pragma" "private" "procedure" "raise" "range"
-;; "record" "rem" "renames" "return" "reverse" "select"
-;; "separate" "task" "terminate" "then" "type" "when" "while"
-;; "with" "xor"))
-;;
-;; => "a\\(b\\(ort\\|s\\)\\|cce\\(pt\\|ss\\)\\|rray\\)\\|b\\(egin\\|ody\\)\\|c\\(ase\\|onstant\\)\\|d\\(e\\(clare\\|l\\(ay\\|ta\\)\\)\\|igits\\)\\|e\\(ls\\(e\\|if\\)\\|ntry\\|x\\(ception\\|it\\)\\)\\|function\\|g\\(eneric\\|oto\\)\\|if\\|l\\(imited\\|oop\\)\\|mod\\|n\\(ew\\|ull\\)\\|o\\(thers\\|ut\\)\\|p\\(ackage\\|r\\(agma\\|ivate\\|ocedure\\)\\)\\|r\\(a\\(ise\\|nge\\)\\|e\\(cord\\|m\\|names\\|turn\\|verse\\)\\)\\|s\\(e\\(lect\\|parate\\)\\|ubtype\\)\\|t\\(ask\\|erminate\\|hen\\|ype\\)\\|w\\(h\\(en\\|ile\\)\\|ith\\)\\|xor"
-;;
-;; To search for the above regexp takes less than 60% of the time of the simple
-;; mapconcat equivalent.
-;;
-;; But even small regexps may be worth it:
-;;
-;; (make-regexp '("and" "at" "do" "end" "for" "in" "is" "not" "of" "or" "use"))
-;; => "a\\(nd\\|t\\)\\|do\\|end\\|for\\|i[ns]\\|not\\|o[fr]\\|use"
-;;
-;; as this is 10% faster than the mapconcat equivalent.
-
-;; Installation:
-;;
-;; (autoload 'make-regexp "make-regexp"
-;; "Return a regexp to match a string item in STRINGS.")
-;;
-;; (autoload 'make-regexps "make-regexp"
-;; "Return a regexp to REGEXPS.")
-;;
-;; Since these functions were written to produce efficient regexps, not regexps
-;; efficiently, it is probably not a good idea to in-line too many calls in
-;; your code, unless you use the following neat trick with `eval-when-compile':
-;;
-;; (defvar definition-regexp
-;; (let ((regexp (eval-when-compile
-;; (make-regexp '("defun" "defsubst" "defmacro" "defalias"
-;; "defvar" "defconst" "defadvice") t))))
-;; (concat "^(" regexp)))
-;;
-;; The `byte-compile' code will be as if you had defined the variable thus:
-;;
-;; (defvar definition-regexp
-;; "^(\\(def\\(a\\(dvice\\|lias\\)\\|const\\|macro\\|subst\\|un\\|var\\)\\)")
-
-;; Feedback:
-;;
-;; Originally written for font-lock, from an idea from Stig's hl319.
-;; Please don't tell me that it doesn't produce optimal regexps; I know that
-;; already. But (ideas or) code to improve things (are) is welcome. Please
-;; test your code and tell me the speed up in searching an appropriate buffer.
-;;
-;; Please send me bug reports, bug fixes, and extensions, etc.
-;; Simon Marshall <simonNOSPAMgnu.ai.mit.edu>
-
-;; History:
-;;
-;; 1.00--1.01:
-;; - Made `make-regexp' take `lax' to force top-level parentheses.
-;; - Fixed `make-regexps' for MATCH bug and new `font-lock-keywords'.
-;; - Added `unfontify' to user timing functions.
-;; 1.01--1.02:
-;; - Made `make-regexp' `let' a big `max-lisp-eval-depth'.
-
-;; The basic idea is to find the shortest common non-"" prefix each time, and
-;; squirrel it out. If there is no such prefix, we divide the list into two so
-;; that (at least) one half will have at least a one-character common prefix.
-
-;; In addition, we (a) delay the addition of () parenthesis as long as possible
-;; (until we're sure we need them), and (b) try to squirrel out one-character
-;; sequences (so we can use [] rather than ()).
-
-;;; Code:
-
-(defun make-regexp (strings &optional paren lax)
- "Return a regexp to match a string item in STRINGS.
-If optional PAREN non-nil, output regexp parentheses around returned regexp.
-If optional LAX non-nil, don't output parentheses if it doesn't require them.
-Merges keywords to avoid backtracking in Emacs' regexp matcher."
- (let* ((max-lisp-eval-depth (* 1024 1024))
- (strings (let ((l strings)) ; Paranoia---make strings unique!
- (while l (setq l (setcdr l (delete (car l) (cdr l)))))
- (sort strings 'string-lessp)))
- (open-paren (if paren "\\(" "")) (close-paren (if paren "\\)" ""))
- (open-lax (if lax "" open-paren)) (close-lax (if lax "" close-paren))
- (completion-ignore-case nil))
- (cond
- ;; If there's only one string, just return it.
- ((= (length strings) 1)
- (concat open-lax (car strings) close-lax))
- ;; If there's an empty string, pull it out.
- ((string= (car strings) "")
- (if (and (= (length strings) 2) (= (length (nth 1 strings)) 1))
- (concat open-lax (nth 1 strings) "?" close-lax)
- (concat open-paren "\\|" (make-regexp (cdr strings)) close-paren)))
- ;; If there are only one-character strings, make a [] list instead.
- ((= (length strings) (apply '+ (mapcar 'length strings)))
- (concat open-lax "[" (mapconcat 'identity strings "") "]" close-lax))
- (t
- ;; We have a list of strings. Is there a common prefix?
- (let ((prefix (try-completion "" (mapcar 'list strings))))
- (if (> (length prefix) 0)
- ;; Common prefix! Squirrel it out and recurse with the suffixes.
- (let* ((len (length prefix))
- (sufs (mapcar (lambda (str) (substring str len)) strings)))
- (concat open-paren prefix (make-regexp sufs t t) close-paren))
- ;; No common prefix. Is there a one-character sequence?
- (let ((letters (let ((completion-regexp-list '("^.$")))
- (all-completions "" (mapcar 'list strings)))))
- (if (> (length letters) 1)
- ;; Do the one-character sequences, then recurse on the rest.
- (let ((rest (let ((completion-regexp-list '("^..+$")))
- (all-completions "" (mapcar 'list strings)))))
- (concat open-paren
- (make-regexp letters) "\\|" (make-regexp rest)
- close-paren))
- ;; No one-character sequence, so divide the list into two by
- ;; dividing into those that start with a particular letter, and
- ;; those that do not.
- (let* ((char (substring (car strings) 0 1))
- (half1 (all-completions char (mapcar 'list strings)))
- (half2 (nthcdr (length half1) strings)))
- (concat open-paren
- (make-regexp half1) "\\|" (make-regexp half2)
- close-paren))))))))))
-
-;; This stuff is realy for font-lock...
-
-;; Ahhh, the wonders of lisp...
-(defun regexp-span (regexp &optional start)
- "Return the span or depth of REGEXP.
-This means the number of \"\\\\(...\\\\)\" pairs in REGEXP, optionally from START."
- (let ((match (string-match (regexp-quote "\\(") regexp (or start 0))))
- (if (not match) 0 (1+ (regexp-span regexp (match-end 0))))))
-
-;; The basic idea is to concat the regexps together, keeping count of the span
-;; of the regexps so that we can get the correct match for hilighting.
-(defun make-regexps (&rest regexps)
- "Return a regexp to match REGEXPS
-Each item of REGEXPS should be of the form:
-
- STRING ; A STRING to be used literally.
- (STRING MATCH FACE DATA) ; Match STRING at depth MATCH with FACE
- ; and highlight according to DATA.
- (STRINGS FACE DATA) ; STRINGS is a list of strings FACE is
- ; to highlight according to DATA.
-
-Returns a list of the form:
-
- (REGEXP (MATCH FACE DATA) ...)
-
-For example:
-
- (make-regexps \"^(\"
- '((\"defun\" \"defalias\" \"defsubst\" \"defadvice\") keyword)
- \"[ \t]*\"
- '(\"\\\\([a-zA-Z-]+\\\\)?\" 1 function-name nil t))
-
- =>
-
- (\"^(\\\\(def\\\\(a\\\\(dvice\\\\|lias\\\\)\\\\|subst\\\\|un\\\\)\\\\)[ ]*\\\\([a-zA-Z-]+\\\\)?\"
- (1 keyword) (4 function-name nil t))
-
-Uses `make-regexp' to make efficient regexps."
- (let ((regexp "") (data ()))
- (while regexps
- (cond ((stringp (car regexps))
- (setq regexp (concat regexp (car regexps))))
- ((stringp (nth 0 (car regexps)))
- (setq data (cons (cons (+ (regexp-span regexp)
- (nth 1 (car regexps)))
- (nthcdr 2 (car regexps)))
- data)
- regexp (concat regexp (nth 0 (car regexps)))))
- (t
- (setq data (cons (cons (1+ (regexp-span regexp))
- (cdr (car regexps)))
- data)
- regexp (concat regexp (make-regexp (nth 0 (car regexps))
- t)))))
- (setq regexps (cdr regexps)))
- (cons regexp (nreverse data))))
-
-;; timing functions removed due to name collisions with Gnus
-
-(provide 'make-regexp)
-
-;;; make-regexp.el ends here
+++ /dev/null
-This is news.info, produced by makeinfo version 6.5 from news.texi.
-
-Changes and New Features in 19.04 (unreleased):
-
- * 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
- <language>-mode-hook and <language>-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. See
- *Note (ess)Controlling buffer display:: for more information and
- examples.
-
- * '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.
-
- * 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.
-
- 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 <https://github.com/polymode/poly-R/>,
- <https://polymode.github.io/>, or markdown-mode with edit-indirect
- <https://jblevins.org/projects/markdown-mode>.
-
- * 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" <ess-config-here>)' 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. *Note (ess)Activating and Loading ESS:: for more
- information on this feature.
-
- * 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
-
-
-\1f
-Tag Table:
-\1f
-End Tag Table
+++ /dev/null
-;;; ess-eldoc.el --- Use eldoc to report R function names.
-
-;; Copyright (C) 1997--2009 A.J. Rossini, Richard M. Heiberger, Martin
-;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
-
-;; Author: Stephen Eglen
-;; Created: 2007-06-30
-;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
-
-;; 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
-;; http://www.r-project.org/Licenses/
-
-;;; Commentary:
-
-;;;;; eldoc funcitonality 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 addresed 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
+++ /dev/null
-;;; ess-mouse.el --- Support for mouse- or cursor-sensitive actions
-
-;; Copyright (C) 2001 Richard M. Heiberger <rmhNOSPAMtemple.edu>
-;; Copyright (C) 2002--2004 A.J. Rossini, Richard M. Heiberger, Martin
-;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
-
-;; Author: Richard M. Heiberger <rmhNOSPAMtemple.edu>
-;; Created: 25 Mar 2001
-;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
-
-;; 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:
-
-;; Support for mouse- or cursor-sensitive actions. This is based on
-;; and uses mouseme.el. mouseme.el only does mouse sensititivity.
-;; 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:
-
-\f ; 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)))
- (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) (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))))
-
-
-\f ; 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
+++ /dev/null
-;;; ess-noweb-font-lock-mode.el --- edit noweb files with GNU Emacs
-
-;; Copyright (C) 1999 by Adnan Yaqub (AYaqubNOSPAMorga.com)
-;; and Mark Lunt (mark.luntNOSPAMmrc-bsu.cam.ac.uk
-;; Copyright (C) 2002 by A.J. Rossini <rossiniNOSPAMu.washington.edu>
-;; Copyright (C) 2003--2004 A.J. Rossini, Richard M. Heiberger, Martin
-;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
-
-;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
-
-;; 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 2, 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.
-;;
-;; A copy of the GNU General Public License is available at
-;; https://www.r-project.org/Licenses/
-;;
-
-;;; Commentary:
-
-;; Code-dependent highlighting
-;; *****
-;;
-;; Adding highlighting to ess-noweb-mode.el
-;;
-;; Here is a description of how one can add highlighting via the
-;; font-lock package to noweb buffers. It uses the hooks provided by
-;; ess-noweb-mode.el. The solution provides the following features:
-;; 1) The documentation chunks are highlighted in the ess-noweb-doc-mode
-;; (e.g., LaTeX).
-;; 2) The code chunks without mode comments (-*- mode -*-) are
-;; highlighted in the ess-noweb-code-mode.
-;; 3) The code chunks with mode comments (-*- mode -*-) on the first
-;; line of the first chunk with this name are highlighted in the mode
-;; in the comment.
-;;
-;; For example, given the file:
-;;
-;; % -*- mode: Noweb; ess-noweb-code-mode: c-mode -*-
-;;
-;; \begin{itemize}
-;; \item a main routine written in C,
-;; \item a log configuration file parser written in YACC, and
-;; \item a lexical analyzer written in Lex.
-;; \end{itemize}
-;;
-;; <<warning c comment>>=
-;; /* DO NOT EDIT ME! */
-;; /* This file was automatically generated from %W% (%G%). */
-;; @
-;;
-;; <<warning nroff comment>>=
-;; .\" -*- nroff -*-
-;; .\" DO NOT EDIT ME!
-;; .\" This file was automatically generated from %W% (%G%).
-;; @
-;;
-;; The LaTeX list is highlighted in latex-mode (the default noweb doc
-;; mode), the chunk <<warning c comment>> is highlighted in c-mode (the
-;; default noweb code mode), and the chunk <<warning nroff comment>> is
-;; highlighted in nroff-mode due to the "-*- nroff -*-" comment.
-;;
-;; Chunks are highlighted each time point moves into them from a
-;; different mode. They are also fontified 'on the fly', but this is
-;; less reliable, since the syntax can depend on the context. It's as
-;; good as you would get outside ess-noweb-mode, though.
-;;
-;; To use it, you must add
-;; (require 'ess-noweb-font-lock-mode) to your .emacs file.
-;; Then, if you use either global-font-lock or turn-on-font-lock
-;; statements, any ess-noweb-mode buffers will be fontified
-;; appropriately. (We have to redefine turn-on-font-lock, but it
-;; saves breaking other packages (in particular ESS, which I use a
-;; lot), that assume that turn-on-font-lock is the way to turn on
-;; font locking.
-
-;; Alternatively, you can turn ess-noweb-font-lock-mode on and off by
-;; using M-x ess-noweb-font-lock-mode. However, turning
-;; ess-noweb-font-lock-mode off when global-font-lock-mode is t makes it
-;; impossible to use font-locking in that buffer subsequently, other
-;; than by turning ess-noweb-font-lock-mode back on.
-
-;; 2) The highlighting sometimes get confused, but this is no longer
-;; a noweb problem. Highlighting should work as well within a chunk
-;; as it does without ess-noweb-mode.
-;; There are some problems with, for example latex-mode: a `$' in a
-;; verbatim environment with throw the font-locking out.
-;; One slight blemish is that code-quotes are highlighted as comments
-;; as they are being entered. They are only highlighted correctly
-;; after `ess-noweb-font-lock-fontify-chunk' has been run, either as a
-;; command or through changing to a different chunk and back again
-;; (unless they lie on a single line, in which case they are
-;; fontified correctly once they are completed).
-
-;;; Code:
-
-(require 'ess-noweb-mode)
-(require 'font-lock)
-
-(defvar ess-noweb-font-lock-mode nil
- "Buffer local variable, t iff this buffer is using `ess-noweb-font-lock-mode'.")
-
-(defvar ess-noweb-use-font-lock-mode t
- "DO NOT CHANGE THIS VARIABLE
-If you use `nw-turn-on-font-lock' to turn on font-locking, then turn it
-off again, it would come back on again of its own accord when you
-changed major-mode. This variable is used internally to stop it.")
-
-(defvar ess-noweb-font-lock-mode-hook nil
- "Hook that is run after entering ess-noweb-font-lock mode.")
-
-(defvar ess-noweb-font-lock-max-initial-chunks 30
- "Maximum number of chunks to fontify initially.
-If nil, will fontify the entire buffer when
-ess-noweb-font-lock-initial-fontify-buffer is called" )
-
-;; (defvar old-beginning-of-syntax nil
-;; "Stores the function used to find the beginning of syntax in the
-;; current major mode. ess-noweb-font-lock-mode needs a different one." )
-
-(defvar ess-noweb-font-lock-doc-start-face font-lock-reference-face
- "Face to use to highlight the `@' at the start of each doc chunk")
-
-(defvar ess-noweb-font-lock-brackets-face font-lock-reference-face
- "Face to use to highlight `<<', `>>' `[[' and `]]' ")
-
-(defvar ess-noweb-font-lock-chunk-name-face font-lock-keyword-face
- "Face to use to highlight the between `<<' and `>>'")
-
-(defvar ess-noweb-font-lock-code-quote-face font-lock-keyword-face
- "Face to use to highlight the between `[[' and `]]'")
-
-;; Now we add [[ess-noweb-font-lock-mode]] to the list of existing minor
-;; modes. The string ``NWFL'' will be added to the mode-line: ugly, but
-;; brief.
-
-(if (not (assq 'ess-noweb-font-lock-mode minor-mode-alist))
- (setq minor-mode-alist (append minor-mode-alist
- (list '(ess-noweb-font-lock-mode " NWFL")))))
-
-;; An ugly kludge to get around problems with global-font-lock, which
-;; fontifies the entire buffer in the new major mode every time you
-;; change mode, which is time-consuming and makes a pigs trotters of
-;; it. Trying to stop it looks tricky, but using this function as your
-;; `font-lock-fontify-buffer' function stops it wasting your time
-
-(defalias 'nwfl-donowt #'ignore)
-
-;; The following function is just a wrapper for ess-noweb-font-lock-mode,
-;; enabling it to be called as ess-noweb-font-lock-minor-mode instead.
-
-(define-obsolete-function-alias 'ess-noweb-font-lock-minor-mode
- #'ess-noweb-font-lock-mode "ESS-16.11")
-
-;; Here we get to the meat of the problem
-;;;###autoload
-(defun ess-noweb-font-lock-mode ( &optional arg)
- ;; FIXME: Don't define a new minor mode. Instead, arrange for normal
- ;; font-lock to call our functions such as
- ;; ess-noweb-font-lock-fontify-chunk-by-number.
- "Minor mode for syntax highlighting when using `ess-noweb-mode' to edit noweb files.
-Each chunk is fontified in accordance with its own mode."
- (interactive "P")
- (if (or ess-noweb-mode ess-noweb-font-lock-mode)
- (progn
- ;; This bit is tricky: copied almost verbatim from bib-cite-mode.el
- ;; It seems to ensure that the variable ess-noweb-font-lock-mode is made
- ;; local to this buffer. It then sets ess-noweb-font-lock-mode to `t' if
- ;; 1) It was called with a prefix argument greater than 0
- ;; or 2) It was called with no argument, and ess-noweb-font-lock-mode is
- ;; currently nil
- ;; ess-noweb-font-lock-mode is nil if the prefix argument was <= 0 or there
- ;; was no prefix argument and ess-noweb-font-lock-mode is currently `t'
- (set (make-local-variable 'ess-noweb-font-lock-mode)
- (if arg
- (> (prefix-numeric-value arg) 0)
- (not ess-noweb-font-lock-mode)))
- ;; Now, if ess-noweb-font-lock-mode is true, we want to turn
- ;; ess-noweb-font-lock-mode on
- (cond
- (ess-noweb-font-lock-mode ;Setup the minor-mode
- (when (and (boundp 'global-font-lock-mode) global-font-lock-mode)
- (mapc #'ess-noweb-make-variable-permanent-local
- '(font-lock-fontify-buffer-function
- font-lock-unfontify-buffer-function))
- (setq font-lock-fontify-buffer-function #'nwfl-donowt)
- (setq font-lock-unfontify-buffer-function #'nwfl-donowt))
- (mapc #'ess-noweb-make-variable-permanent-local
- '(ess-noweb-font-lock-mode
- font-lock-dont-widen
- ;; font-lock-beginning-of-syntax-function
- syntax-begin-function
- ess-noweb-use-font-lock-mode
- after-change-functions))
- (setq ess-noweb-font-lock-mode t
- font-lock-dont-widen t)
- (add-hook 'after-change-functions
- #'font-lock-after-change-function nil t)
- ;; FIXME: Why add ess-noweb-font-lock-mode-fn to our own hook,
- ;; instead of just calling ess-noweb-font-lock-mode-fn directly?
- (add-hook 'ess-noweb-font-lock-mode-hook #'ess-noweb-font-lock-mode-fn)
- (add-hook 'ess-noweb-changed-chunk-hook
- #'ess-noweb-font-lock-fontify-this-chunk)
- (run-hooks 'ess-noweb-font-lock-mode-hook)
- (message "ess-noweb-font-lock mode: use `M-x ess-noweb-font-lock-describe-mode' for more info"))
- ;; If we didn't do the above, then we want to turn ess-noweb-font-lock-mode
- ;; off, no matter what (hence the condition `t')
- (t
- (when (and (boundp 'global-font-lock-mode) global-font-lock-mode)
- ;; (setq font-lock-fontify-buffer-function
- ;; 'font-lock-default-fontify-buffer)
- ;; Get back our unfontify buffer function
- (setq font-lock-unfontify-buffer-function
- #'font-lock-default-unfontify-buffer))
- (remove-hook 'ess-noweb-font-lock-mode-hook #'ess-noweb-font-lock-mode-fn)
- (remove-hook 'ess-noweb-changed-chunk-hook
- #'ess-noweb-font-lock-fontify-this-chunk)
- (remove-hook 'after-change-functions
- #'font-lock-after-change-function )
- (font-lock-default-unfontify-buffer)
- (setq ess-noweb-use-font-lock-mode nil)
- (message "ess-noweb-font-lock-mode removed"))))
- (message "ess-noweb-font-lock-mode can only be used with ess-noweb-mode")))
-
-(defun ess-noweb-start-of-syntax ()
- "Go to the place to start fontifying from"
- (interactive)
- (goto-char (car (ess-noweb-chunk-region))))
-
-(defvar font-latex-extend-region-functions)
-(defvar syntax-begin-function)
-
-(defun ess-noweb-font-lock-fontify-chunk-by-number ( chunk-num )
- "Fontify chunk CHUNK-NUM based on the current major mode."
- (save-excursion
- (font-lock-set-defaults)
- ;; (setq old-beginning-of-syntax font-lock-beginning-of-syntax-function)
- (setq font-lock-keywords
- ;; (append font-lock-keywords
- ;; '(("\\(\\[\\[\\)\\([^]]*\\]*\\)\\(\\]\\]\\|\\$\\)"
- ;; (1 ess-noweb-font-lock-brackets-face prepend )
- ;; (2 ess-noweb-font-lock-code-quote-face prepend)
- ;; (3 ess-noweb-font-lock-brackets-face prepend))
- ;; ("^[ \t\n]*\\(<<\\)\\([^>]*\\)\\(>>=?\\)"
- ;; (1 ess-noweb-font-lock-brackets-face prepend )
- ;; (2 ess-noweb-font-lock-chunk-name-face prepend)
- ;; (3 ess-noweb-font-lock-brackets-face prepend))
- ;; ("^@[ \t\n]+"
- ;; (0 ess-noweb-font-lock-doc-start-face prepend )))))
- (append font-lock-keywords
- '(("^[ \t\n]*\\(<<\\)\\([^>]*\\)\\(>>=?\\)"
- ;; FIXME: Why not use ess-noweb-font-lock-brackets-face?
- (1 font-lock-reference-face prepend )
- ;; FIXME: Why not use ess-noweb-font-lock-chunk-name-face?
- (2 font-lock-keyword-face prepend)
- (3 font-lock-reference-face prepend))
- ("^@[ \t\n]+"
- (0 font-lock-reference-face prepend )))))
-
-
- (let ((r (cons (marker-position (cdr (aref ess-noweb-chunk-vector
- chunk-num)))
- (marker-position (cdr (aref ess-noweb-chunk-vector
- (1+ chunk-num))))))
- (font-latex-extend-region-functions nil);; don't extend anything
- (font-lock-extend-region-functions nil)) ;; this infloops :(
- (save-restriction
- (narrow-to-region (car r) (cdr r))
- ;; (sit-for 3)
- (font-lock-fontify-region (car r) (cdr r)))
- t)))
-
-
-(defun ess-noweb-font-lock-fontify-this-chunk ()
- "Fontify this chunk according to its own major mode.
-Since we are in the chunk, the major mode will already have been set
-by ess-noweb-mode.el"
- (interactive)
- (ess-noweb-font-lock-fontify-chunk-by-number (ess-noweb-find-chunk-index-buffer)))
-
-(defun ess-noweb-font-lock-initial-fontify-buffer ()
- "Applies syntax highlighting to some or all chunks in a noweb buffer.
-The number of chunks is set by `ess-noweb-font-lock-max-initial-chunks': if
-this is nil, the entire buffer is fontified.
-It is intended to be called when first entering `ess-noweb-font-lock-mode'.
-For other purposes, use `ess-noweb-font-lock-fontify-chunks'."
- (interactive)
- ;; This will be tricky. It will be very slow to go throught the chunks
- ;; in order, switching major modes all the time.
- ;; So, we will do the documentation in one pass, the code in a second
- ;; pass. This could still be a little slow if we have to swap between
- ;; different code modes regularly, but it should be bearable. It should
- ;; only happen when the file is first read in, anyway
- (save-excursion
- (let (start-chunk end-chunk this-chunk)
- (setq this-chunk (ess-noweb-find-chunk-index-buffer))
- (if ess-noweb-font-lock-max-initial-chunks
- (progn
- (setq start-chunk
- (max 0
- (- this-chunk
- (/ ess-noweb-font-lock-max-initial-chunks 2))))
- ;; Don't you just love hairy lisp syntax ? The above means set the
- ;; starting chunk to the current chunk minus half of
- ;; ess-noweb-font-lock-max-initial-chunks, unless that is negative in
- ;; which case set it to 0
- (setq end-chunk (+ start-chunk ess-noweb-font-lock-max-initial-chunks))
- (if (> end-chunk (- (length ess-noweb-chunk-vector) 2))
- (setq end-chunk (- (length ess-noweb-chunk-vector) 2))))
- ;; If ess-noweb-font-lock-max-initial-chunks is nil, do the whole buffer
- (progn
- (setq start-chunk 0)
- (setq end-chunk (- (length ess-noweb-chunk-vector) 2))))
- (ess-noweb-font-lock-fontify-chunks start-chunk end-chunk))))
-
-(defun ess-noweb-font-lock-fontify-buffer ()
- "This function will fontify each chunk in the buffer appropriately."
- (interactive)
- (let ((start-chunk 0)
- (end-chunk (- (length ess-noweb-chunk-vector) 2)))
- (ess-noweb-font-lock-fontify-chunks start-chunk end-chunk)))
-
-(defun ess-noweb-font-lock-fontify-chunks (start-chunk end-chunk)
- "Fontify a noweb file from START-CHUNK to END-CHUNK."
- (interactive)
- (let ((chunk-counter start-chunk))
- (save-excursion
- (message "Fontifying from %d to %d" start-chunk end-chunk)
- ;; Want to set DOC mode for the first Doc chunk, not for the others
- (while (stringp (car (aref ess-noweb-chunk-vector chunk-counter)))
- (setq chunk-counter (+ chunk-counter 1)))
- (goto-char (cdr (aref ess-noweb-chunk-vector chunk-counter)))
- (ess-noweb-select-mode)
- ;; Now go through the chunks, fontifying the documentation ones.
- (while (<= chunk-counter end-chunk)
- (if (not (stringp (car (aref ess-noweb-chunk-vector chunk-counter))))
- (ess-noweb-font-lock-fontify-chunk-by-number chunk-counter))
- (message "Fontifying documentation chunks: chunk %d" chunk-counter)
- (setq chunk-counter (+ 1 chunk-counter)))
- ;; Go back to the start and go through the chunks, fontifying the code ones.
- (setq chunk-counter start-chunk)
- (message "About to do code chunks")
- (while (<= chunk-counter end-chunk)
- (when (stringp (car (aref ess-noweb-chunk-vector chunk-counter)))
- ;; It's a code chunk: goto it to set the correct code mode, then
- ;; fontify it.
- (message "Fontifying code chunks: chunk %d" chunk-counter)
- (goto-char (cdr (aref ess-noweb-chunk-vector chunk-counter)))
- (ess-noweb-select-mode)
- (ess-noweb-font-lock-fontify-this-chunk))
- (setq chunk-counter (1+ chunk-counter))))
- (ess-noweb-select-mode)))
-
-(defun ess-noweb-font-lock-mode-fn()
- "Function that is intended to be attached to ess-noweb-font-lock-mode-hook."
- (ess-noweb-font-lock-initial-fontify-buffer))
-
-;; This is a wee bit of a hack. If people attach `turn-on-font-lock'
-;; to their major mode hook, it will play hell with
-;; ess-noweb-font-lock-mode. I had hoped that providing a replacement
-;; `nw-turn-on-font-lock' would solve the problem, but it didn't
-;; (sometimes turn-on-font-lock appears in places other than
-;; `.emacs', such as in ESS). So rather than have it fall over if
-;; turn-on-lock was around, I redefined turn-on-font-lock to do the
-;; right thing.
-
-(define-obsolete-function-alias 'nw-turn-on-font-lock
- #'turn-on-font-lock "ESS-16.11")
-
-(defadvice turn-on-font-lock (around ess-noweb-font-lock activate)
- ;; FIXME: An advice on turn-on-font-lock is definitely not sufficient,
- ;; since font-lock can be enabled without going through turn-on-font-lock!
- (if (not ess-noweb-mode)
- ad-do-it
- (if (and (not ess-noweb-font-lock-mode) ess-noweb-use-font-lock-mode)
- (ess-noweb-font-lock-mode))))
-
-(provide 'ess-noweb-font-lock-mode)
-;; *****
-;;
-;; Adnan Yaqub (AYaqubNOSPAMorga.com)
-;; ORGA Kartensysteme GmbH // An der Kapelle 2 // D-33104 Paderborn // Germany
-;; Tel. +49 5254 991-823 //Fax. +49 5254 991-749
-
-
-;;; ess-noweb-font-lock-mode.el ends here
+++ /dev/null
-;;; ess-noweb-mode.el --- edit noweb files with GNU Emacs
-
-;; Copyright (C) 1995 by Thorsten.Ohl @ Physik.TH-Darmstadt.de
-;; with a little help from Norman Ramsey <normanNOSPAMbellcore.com>
-;; and Mark Lunt <mark.luntNOSPAMmrc-bsu.cam.ac.uk>
-;; and A.J. Rossini <rossiniNOSPAMbiostat.washington.edu>
-;; Copyright (C) 1999--2010 A.J. Rossini, Richard M. Heiberger, Martin
-;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
-;; Copyright (C) 2011--2012 A.J. Rossini, Richard M. Heiberger, Martin Maechler,
-;; Kurt Hornik, Rodney Sparapani, Stephen Eglen and Vitalie Spinu.
-
-;; ESS-related Changes first added by Mark Lunt and A.J. Rossini, March, 1999.
-
-;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
-
-;; 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 2, 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.
-;;
-;; A copy of the GNU General Public License is available at
-;; https://www.r-project.org/Licenses/
-
-;; See bottom of this file for information on language-dependent
-;; highlighting, and recent changes.
-;;
-
-;; BASED ON: (from Mark Lunt).
-;; -- Id: ess-noweb-mode.el,v 1.11 1999/03/21 20:14:41 root Exp --
-
-\f
-;;; NEWS:
-
-;; * [tho] M-n q, aka: M-x ess-noweb-fill-chunk
-;;
-;; * [tho] `M-n TAB', aka: `M-x ess-noweb-complete-chunk'
-;;
-;; * [tho] ess-noweb-occur
-;;
-;; * [nr] use `M-n' instead of `C-c n' as default command prefix
-;;
-;; * [nr] don't be fooled by
-;;
-;; @
-;; <<foo>>=
-;; int foo;
-;; @ %def foo
-;; Here starts a new documentation chunk!
-;; <<bar>>=
-;; int bar;
-;;
-;; * [nr] switch mode changing commands off during isearch-mode
-;;
-;; * [tho] ess-noweb-goto-chunk proposes a default
-;;
-;; * commands for tangling, weaving,.. for Sweave: --> ./ess-swv.el
-;;
-\f
-
-;;; TODO:
-
-;; * _maybe_ replace our `ess-noweb-chunk-vector' by text properties. We
-;; could then use highlighting to jazz up the visual appearance.
-;; (Highlighting is sorted: `ess-noweb-chunk-vector' can be
-;; ditched. It is simple to determine if we are in a doc or code
-;; chunk.)
-;;
-;; * wrapped `ess-noweb-goto-next' and `ess-noweb-goto-previous'
-;;
-;; * more range checks and error exits
-;;
-;; * `ess-noweb-hide-code-quotes' should be superfluous now, and could
-;; be removed. For ESS 5.3.10, we disable these, using the new variable
-;; ess-noweb-code-quote-handling. If nobody misses that code-protecting
-;; behavior, all that should be removed entirely.
-
-;;; Code:
-
-(require 'ess-custom)
-(require 'ess-utils)
-
-(defcustom Rnw-mode-hook nil
- "Hook run when entering Rnw mode."
- :type 'hook
- :group 'ess-R)
-
-(defvar-local ess--make-local-vars-permanent nil
- "If this variable is non-nil in a buffer make all variable permannet.
-Used in noweb modes.")
-(put 'ess--make-local-vars-permanent 'permanent-local t)
-
-(defvar weave-process)
-
-\f
-;;; Variables
-
-;; (defconst ess-noweb-mode-RCS-Id
-;; "Imported to ESS Subversion repository and RCS ids not maintained.")
-
-;; (defconst ess-noweb-mode-RCS-Name
-;; " ")
-
-(defvar-local ess--make-local-vars-permanent nil
- "If this variable is non-nil in a buffer make all variable permannet.
-Used in noweb modes.")
-(put 'ess--make-local-vars-permanent 'permanent-local t)
-
-(defvar ess-noweb-mode-prefix "\M-n"
- "Prefix key to use for noweb mode commands.
-The value of this variable is checked as part of loading noweb mode.
-After that, changing the prefix key requires manipulating keymaps.")
-
-(defvar ess-noweb-mode-load-hook nil
- "Hook that is run after noweb mode is loaded.")
-
-(defvar ess-noweb-mode-hook nil
- "Hook that is run after entering noweb mode.")
-
-(defvar ess-noweb-select-code-mode-hook nil
- "Hook that is run after the code mode is selected.
-This is the place to overwrite keybindings of the ess-noweb-CODE-MODE.")
-
-(defvar ess-noweb-select-doc-mode-hook nil
- "Hook that is run after the documentation mode is selected.
-This is the place to overwrite keybindings of the ess-noweb-DOC-MODE.")
-
-(defvar ess-noweb-select-mode-hook nil
- "Hook that is run after the documentation or the code mode is selected.
-This is the place to overwrite keybindings of the other modes.")
-
-(defvar ess-noweb-changed-chunk-hook nil
- "Hook that is run every time point moves from one chunk to another.
-It will be run whether or not the major-mode changes.")
-
-(defvar ess-noweb-default-code-mode 'fundamental-mode
- "Default major mode for editing code chunks.
-This is set to FUNDAMENTAL-MODE by default, but you might want to
-change this in the Local Variables section of your file to something
-more appropriate, like C-MODE, FORTRAN-MODE, or even
-INDENTED-TEXT-MODE.")
-
-(defvar ess-noweb-code-mode 'c-mode
- "Major mode for editing this particular code chunk.
-It defaults to ess-noweb-default-code-mode, but can be reset by a comment
-on the first line of the chunk containing the string
-\"-*- NEWMODE -*-\" or
-\"-*- NEWMODE-mode -*-\" or
-\"-*- mode: NEWMODE -*- \" or
-\"-*- mode: NEWMODE-mode -*- \"
-Option three is recommended, as it is the closest to standard emacs usage.")
-
-(defvar ess-noweb-default-doc-mode 'latex-mode
- "Major mode for editing documentation chunks.
-Sensible choices would be tex-mode, latex-mode, sgml-mode, or
-html-mode. Maybe others will exist someday.")
-
-(defvar ess-noweb-doc-mode-syntax-table nil
- "A syntax-table syntax table that makes quoted code in doc chunks to
-behave.")
-
-(defvar ess-noweb-last-chunk-index 0
- "This keeps track of the chunk we have just been in. If this is not
-the same as the current chunk, we have to check if we need to change
-major mode.")
-
-(defvar ess-noweb-chunk-vector nil
- "Vector of the chunks in this buffer.")
-
-(defvar ess-noweb-narrowing nil
- "If not NIL, the display will always be narrowed to the
-current chunk pair.")
-
-(defvar ess-noweb-electric-@-and-< t
- "If not nil, the keys `@' and `<' will be bound to ess-noweb-ELECTRIC-@
-and ess-noweb-ELECTRIC-<, respectively.")
-
-(defvar ess-noweb-use-mouse-navigation t
- "If not nil, enables moving between chunks using mouse-1.
-Clicking on the '<<' at the beginning of a chunk name takes you to the
-previous occurence of that chunk name, clicking on the '>>' takes you
-to the next.
-Assumes mouse-1 is bound to mouse-set-point, so if you have rebound
-mouse-1, this will override your binding.")
-
-(defvar ess-noweb-code-quotes-handling nil
- "If not nil, the function pair \\[ess-noweb-hide-code-quotes] and
-\\[ess-noweb-restore-code-quotes] are used to \"protect\" code inside
-\"[[\" .. \"]]\" pairs. Note that rarely this has been found to be buggy
-with the \"catastrophic\" consequence of whole parts of your document being
-replaced by sequences of '*'.")
-
-(defvar ess-noweb-doc-mode ess-noweb-default-doc-mode
- "Default major mode for editing noweb documentation chunks.
-It is not possible to have more than one doc-mode in a file.
-However, this variable is used to determine whether the doc-mode needs
-to by added to the mode-line")
-
-;; The following is apparently broken -- dangling code that was
-;; commented out. Need to see if we can get it working?
-
-(defvar ess-noweb-weave-options "-delay")
-(defvar ess-noweb-latex-viewer "xdvi")
-(defvar ess-noweb-html-viewer "netscape")
-
-(defun ess-noweb-weave (&optional name)
- (interactive)
- (let ((buffer (get-buffer-create "Weave Buffer")))
- (if (not name)
- (progn
- ;; Assume latex documentation, but set to html if appropriate
- (if (eq ess-noweb-doc-mode 'html-mode)
- (setq name (concat (substring (buffer-file-name) 0
- (string-match ".nw" name))
- ".html"))
- (setq name (concat (substring (buffer-file-name) 0
- (string-match ".nw" name))
- ".tex")))))
- (setq name (concat "> " name))
- (setq ess-noweb-weave-options (concat ess-noweb-weave-options name))
- (start-process weave-process buffer "noweave" ess-noweb-weave-options)))
-;;(defun ess-noweb-view ())
-
-\f
-;;; Setup
-(defvar ess-noweb-mode nil
- "Buffer local variable, T iff this buffer is edited in noweb mode.")
-
-;; For some reason that I do not understand, `newline' does not do the
-;; right thing in quoted code. If point is not preceded by whitespace,
-;; it moves to the beginning of the current line, not the beginning of
-;; the new line. `newline 1' works fine, hence the kludge. I'd love to
-;; understand what's going on, though. Try running M-x newline in the
-;; middle of a code quote in a doc chunk to see
-;; what I mean: its odd.
-
-(defun ess-noweb-newline (&optional arg)
- "A kludge to get round very odd behaviour of newline in quoted code."
- (interactive "p")
- (if arg (newline arg) (newline 1))
- (ess-noweb-indent-line))
-
-(defvar ess-noweb-mode-prefix-map
- (let ((map (make-sparse-keymap)))
- (define-key map "\C-\M-x" 'ess-eval-chunk)
- (define-key map "\C-c" 'ess-eval-chunk-and-step)
- (define-key map "\C-n" 'ess-noweb-next-chunk)
- (define-key map "\C-p" 'ess-noweb-previous-chunk)
- (define-key map "\M-n" 'ess-noweb-goto-next)
- (define-key map "\M-m" 'ess-noweb-insert-default-mode-line)
- (define-key map "\M-p" 'ess-noweb-goto-previous)
- (define-key map "c" 'ess-noweb-next-code-chunk)
- (define-key map "C" 'ess-noweb-previous-code-chunk)
- (define-key map "d" 'ess-noweb-next-doc-chunk)
- (define-key map "D" 'ess-noweb-previous-doc-chunk)
- (define-key map "g" 'ess-noweb-goto-chunk)
- (define-key map "\C-l" 'ess-noweb-update-chunk-vector)
- (define-key map "\M-l" 'ess-noweb-update-chunk-vector)
- (define-key map "w" 'ess-noweb-copy-chunk-as-kill)
- (define-key map "W" 'ess-noweb-copy-chunk-pair-as-kill)
- (define-key map "k" 'ess-noweb-kill-chunk)
- (define-key map "K" 'ess-noweb-kill-chunk-pair)
- (define-key map "m" 'ess-noweb-mark-chunk)
- (define-key map "M" 'ess-noweb-mark-chunk-pair)
- (define-key map "n" 'ess-noweb-narrow-to-chunk)
- (define-key map "N" 'ess-noweb-narrow-to-chunk-pair)
- (define-key map "t" 'ess-noweb-toggle-narrowing)
- (define-key map "\t" 'ess-noweb-complete-chunk)
- (define-key map "q" 'ess-noweb-fill-chunk)
- (define-key map "i" 'ess-noweb-new-chunk)
- (define-key map "o" 'ess-noweb-occur)
- ;;(define-key map "v" 'ess-noweb-mode-version)
- (define-key map "h" 'ess-noweb-describe-mode)
- ;; do *NOT* override C-h (give all keybindings startings with M-n!
- map)
- "noweb minor-mode prefix keymap")
-
-(defvar ess-noweb-minor-mode-map
- (let ((map (make-sparse-keymap)))
- (if ess-noweb-electric-@-and-<
- (progn
- (define-key map "@" 'ess-noweb-electric-@)
- (define-key map "<" 'ess-noweb-electric-<)))
- (define-key map "\M-q" 'ess-noweb-fill-paragraph-chunk)
- (define-key map [(control meta ?\\)] 'ess-noweb-indent-region)
- ;;(define-key map "\C-c\C-n" 'ess-noweb-indent-line) ; Override TeX-normal!
- (define-key map "\t" 'ess-noweb-indent-line)
- ;; (define-key map [tab] 'ess-noweb-indent-line) ;; interferes with ac
- (define-key map "\r" 'ess-noweb-newline)
- ;; (define-key map [return] 'ess-noweb-newline) ;; interferes with ac
- (define-key map [mouse-1] 'ess-noweb-mouse-first-button)
- (define-key map ess-noweb-mode-prefix ess-noweb-mode-prefix-map)
- map)
- "ESS Noweb minor mode keymap")
-
-(easy-menu-define
- ess-noweb-minor-mode-menu ess-noweb-minor-mode-map
- "Menu keymap for noweb."
- '("Noweb"
- ("Movement"
- ["Previous chunk" ess-noweb-previous-chunk t]
- ["Next chunk" ess-noweb-next-chunk t]
- ["Previous chunk of same name" ess-noweb-goto-previous t]
- ["Next chunk of same name" ess-noweb-goto-next t]
- ["Goto chunk" ess-noweb-goto-chunk t]
- ["Previous code chunk" ess-noweb-previous-code-chunk t]
- ["Next code chunk" ess-noweb-next-code-chunk t]
- ["Previous documentation chunk" ess-noweb-previous-doc-chunk t]
- ["Next documentation chunk" ess-noweb-next-doc-chunk t])
- ("Editing"
- ["Copy chunk" ess-noweb-copy-chunk-as-kill t]
- ["Copy chunk pair" ess-noweb-copy-chunk-pair-as-kill t]
- ["Kill chunk" ess-noweb-kill-chunk t]
- ["Kill chunk pair" ess-noweb-kill-chunk-pair t]
- ["Mark chunk" ess-noweb-mark-chunk t]
- ["Mark chunk pair" ess-noweb-mark-chunk-pair t])
- ("Narrowing"
- ["Narrow to chunk" ess-noweb-narrow-to-chunk t]
- ["Narrow to chunk pair" ess-noweb-narrow-to-chunk-pair t]
- ["Toggle auto narrowing" ess-noweb-toggle-narrowing t]
- ["Widen" widen t])
- ("Modes"
- ["Set documentation mode" ess-noweb-set-doc-mode t]
- ["Set default code mode" ess-noweb-set-code-mode t]
- ["Set code mode for this chunk" ess-noweb-set-this-code-mode t]
- ["Insert default mode line" ess-noweb-insert-default-mode-line t])
- ("Tangling"
- ["Tangle current chunk" ess-noweb-tangle-chunk t]
- ["Tangle current thread" ess-noweb-tangle-current-thread t]
- ["Tangle named thread" ess-noweb-tangle-thread t])
- ("Miscellaneous"
- ["Complete chunk name" ess-noweb-complete-chunk t]
- ["Fill current chunk" ess-noweb-fill-chunk t]
- ["Insert new chunk" ess-noweb-new-chunk t]
- ["Update the chunk vector" ess-noweb-update-chunk-vector t]
- ["Chunk occurrences" ess-noweb-occur t])
- "--"
- ["Help" ess-noweb-describe-mode t]
- ;;["Version" ess-noweb-mode-version t]
- ))
-
-;; Add ess-noweb-mode to the list of minor modes
-(if (not (assq 'ess-noweb-mode minor-mode-alist))
- (setq minor-mode-alist (append minor-mode-alist
- (list '(ess-noweb-mode " Noweb")))))
-;; Add ess-noweb-minor-mode-map to the list of minor-mode keymaps
-;; available. Then, whenever ess-noweb-mode is activated, the keymap is
-;; automatically activated
-(if (not (assq 'ess-noweb-mode minor-mode-map-alist))
- (setq minor-mode-map-alist
- (cons (cons 'ess-noweb-mode ess-noweb-minor-mode-map)
- minor-mode-map-alist)))
-
-(defun ess-noweb-minor-mode (&optional arg)
- "Minor meta mode for editing noweb files. See ess-noweb-mode."
- (interactive)
- (ess-noweb-mode arg)) ; this was ess-noweb-minor-mode??? (truly recursive)
-
-(declare-function ess-noweb-font-lock-mode "ess-noweb-font-lock-mode")
-
-;;;###autoload
-(defun ess-noweb-mode ( &optional arg )
- "Minor meta mode for editing noweb files.
-`Meta' refers to the fact that this minor mode is switching major
-modes depending on the location of point.
-
-The following special keystrokes are available in noweb mode:
-
-Movement:
-\\[ess-noweb-next-chunk] \tgoto the next chunk
-\\[ess-noweb-previous-chunk] \tgoto the previous chunk
-\\[ess-noweb-goto-previous] \tgoto the previous chunk of the same name
-\\[ess-noweb-goto-next] \tgoto the next chunk of the same name
-\\[ess-noweb-goto-chunk] \t\tgoto a chunk
-\\[ess-noweb-next-code-chunk] \t\tgoto the next code chunk
-\\[ess-noweb-previous-code-chunk] \t\tgoto the previous code chunk
-\\[ess-noweb-next-doc-chunk] \t\tgoto the next documentation chunk
-\\[ess-noweb-previous-doc-chunk] \t\tgoto the previous documentation chunk
-
-Copying/Killing/Marking/Narrowing:
-\\[ess-noweb-copy-chunk-as-kill] \t\tcopy the chunk the point is in into the kill ring
-\\[ess-noweb-copy-chunk-pair-as-kill] \t\tcopy the pair of doc/code chunks the point is in
-\\[ess-noweb-kill-chunk] \t\tkill the chunk the point is in
-\\[ess-noweb-kill-chunk-pair] \t\tkill the pair of doc/code chunks the point is in
-\\[ess-noweb-mark-chunk] \t\tmark the chunk the point is in
-\\[ess-noweb-mark-chunk-pair] \t\tmark the pair of doc/code chunks the point is in
-\\[ess-noweb-narrow-to-chunk] \t\tnarrow to the chunk the point is in
-\\[ess-noweb-narrow-to-chunk-pair] \t\tnarrow to the pair of doc/code chunks the point is in
-\\[widen] \twiden
-\\[ess-noweb-toggle-narrowing] \t\ttoggle auto narrowing
-
-Filling and Indenting:
-\\[ess-noweb-fill-chunk] \tfill (or indent) the chunk at point according to mode
-\\[ess-noweb-fill-paragraph-chunk] \tfill the paragraph at point, restricted to chunk
-\\[ess-noweb-indent-line] \tindent the line at point according to mode
-
-Insertion:
-\\[ess-noweb-insert-default-mode-line] \tinsert a line to set this file's code mode
-\\[ess-noweb-new-chunk] \t\tinsert a new chunk at point
-\\[ess-noweb-complete-chunk] \tcomplete the chunk name before point
-\\[ess-noweb-electric-@] \t\tinsert a `@' or start a new doc chunk
-\\[ess-noweb-electric-<] \t\tinsert a `<' or start a new code chunk
-
-Modes:
-\\[ess-noweb-set-doc-mode] \t\tset the major mode for editing doc chunks
-\\[ess-noweb-set-code-mode] \tset the major mode for editing code chunks
-\\[ess-noweb-set-this-code-mode] \tset the major mode for editing this code chunk
-
-Misc:
-\\[ess-noweb-occur] \t\tfind all occurrences of the current chunk
-\\[ess-noweb-update-chunk-vector] \tupdate the markers for chunks
-\\[ess-noweb-describe-mode] \tdescribe ess-noweb-mode
-" (interactive "P")
- ;; This bit is tricky: copied almost verbatim from bib-cite-mode.el
- ;; It seems to ensure that the variable ess-noweb-mode is made
- ;; local to this buffer. It then sets ess-noweb-mode to `t' if
- ;; 1) It was called with an argument greater than 0
- ;; or 2) It was called with no argument, and ess-noweb-mode is
- ;; currently nil
- ;; ess-noweb-mode is nil if the argument was <= 0 or there
- ;; was no argument and ess-noweb-mode is currently `t'
- (kill-all-local-variables)
- (set (make-local-variable 'ess-noweb-mode)
- (if arg
- (> (prefix-numeric-value arg) 0)
- (not ess-noweb-mode)))
- ;; Now, if ess-noweb-mode is true, we want to turn
- ;; ess-noweb-mode on
- (cond
- (ess-noweb-mode ;Setup the minor-mode
- (mapc 'ess-noweb-make-variable-permanent-local
- '(ess-noweb-mode
- ess-local-process-name ;; also made permanent in ess-mode, but let it be
- ess-dialect
- ess-language
- ess-use-flymake
- after-change-functions
- before-change-functions
- ess-noweb-narrowing
- ess-noweb-chunk-vector
- post-command-hook
- isearch-mode-hook
- isearch-mode-end-hook
- ess-noweb-doc-mode
- ess-noweb-code-mode
- ess-noweb-default-code-mode
- ess-noweb-last-chunk-index))
- (setq-local ess-use-flymake nil)
- (ess-noweb-update-chunk-vector)
- (setq ess-noweb-last-chunk-index
- (if (equal 0 (ess-noweb-find-chunk-index-buffer)) 1 0))
- (if font-lock-mode
- (progn
- (font-lock-mode -1)
- (ess-noweb-font-lock-mode 1)))
- (add-hook 'post-command-hook 'ess-noweb-post-command-function)
-
- (add-hook 'after-change-functions 'ess-noweb-after-change-function nil t)
- (add-hook 'before-change-functions 'ess-noweb-before-change-function nil t)
-
- (add-hook 'ess-noweb-select-doc-mode-hook 'ess-noweb-auto-fill-doc-mode)
- (add-hook 'ess-noweb-select-code-mode-hook 'ess-noweb-auto-fill-code-mode)
- (add-hook 'isearch-mode-hook 'ess-noweb-note-isearch-mode)
- (add-hook 'isearch-mode-end-hook 'ess-noweb-note-isearch-mode-end)
- (setq ess-noweb-doc-mode-syntax-table nil)
- (run-hooks 'ess-noweb-mode-hook)
- (message
- "noweb mode: use `M-x ess-noweb-describe-mode' for further information"))
- ;; If we didn't do the above, then we want to turn ess-noweb-mode
- ;; off, no matter what (hence the condition `t')
- (t
- (remove-hook 'post-command-hook 'ess-noweb-post-command-function)
-
- (remove-hook 'after-change-functions 'ess-noweb-after-change-function t)
- (remove-hook 'before-change-functions 'ess-noweb-before-change-function t)
-
- (remove-hook 'ess-noweb-select-doc-mode-hook 'ess-noweb-auto-fill-doc-mode)
- (remove-hook 'ess-noweb-select-code-mode-hook 'ess-noweb-auto-fill-code-mode)
- (remove-hook 'isearch-mode-hook 'ess-noweb-note-isearch-mode)
- (remove-hook 'isearch-mode-end-hook 'ess-noweb-note-isearch-mode-end)
- (if (and (boundp 'ess-noweb-font-lock-mode)
- ess-noweb-font-lock-mode)
- (progn
- (ess-noweb-font-lock-mode -1)
- (message "ESS-Noweb and ESS-Noweb-Font-Lock Modes Removed"))
- (message "ESS-Noweb mode removed")))))
-
-(defun ess-noweb-make-variable-permanent-local (var)
- "Declare VAR buffer local, but protect it from beeing killed
-by major mode changes."
- (make-variable-buffer-local var)
- (put var 'permanent-local 't))
-
-(defun ess-noweb-note-isearch-mode ()
- "Take note of an incremental search in progress"
- (remove-hook 'post-command-hook 'ess-noweb-post-command-function))
-
-(defun ess-noweb-note-isearch-mode-end ()
- "Take note of an incremental search having ended"
- (add-hook 'post-command-hook 'ess-noweb-post-command-function))
-
-(defun ess-noweb-post-command-function ()
- "The hook being run after each command in noweb mode."
- (ess-noweb-select-mode))
-
-(defvar ess-noweb-chunk-boundary-changed nil
- "Whether the current change affects a chunk boundary.")
-
-(defvar ess-noweb-chunk-boundary-regexp "^\\(@[^@]\\)\\|\\(<<\\)")
-
-(defun ess-noweb-before-change-function (begin end)
- "Record changes to chunk boundaries."
- (save-excursion
- (goto-char begin)
- (setq ess-noweb-chunk-boundary-changed
- (re-search-forward ess-noweb-chunk-boundary-regexp end t))))
-
-(defun ess-noweb-after-change-function (begin end length)
- "Function to run after every change in a noweb buffer.
-If the changed region contains a chunk boundary, it will update
-the chunk vector"
- (save-excursion
- (goto-char begin)
- (when (or ess-noweb-chunk-boundary-changed
- (re-search-forward ess-noweb-chunk-boundary-regexp end t))
- (ess-noweb-update-chunk-vector)
- (setq ess-noweb-chunk-boundary-changed nil))))
-
-\f
-;;; Chunks
-
-(defun ess-noweb-update-chunk-vector ()
- "Scan the whole buffer and place a marker at each \"^@\" and \"^<<\".
-Record them in ess-noweb-CHUNK-VECTOR."
- (interactive)
- (save-excursion
- (goto-char (point-min))
- (let ((chunk-list (list (cons 'doc (point-marker)))))
- (while (re-search-forward "^\\(@\\( \\|$\\|\\( %def\\)\\)\\|<<\\(.*\\)>>=\\)" nil t)
- (goto-char (match-beginning 0))
- ;; If the 3rd subexpression matched @ %def, we're still in a code
- ;; chunk (sort of), so don't place a marker here.
- (if (not (match-beginning 3))
- (setq chunk-list
- ;; If the 4th subexpression matched inside <<...>>,
- ;; we're seeing a new code chunk.
- (cons (cons (if (match-beginning 4)
- ;;buffer-substring-no-properties better
- ;;than buffer-substring if highlighting
- ;;may be used
- (buffer-substring-no-properties
- (match-beginning 4) (match-end 4))
- 'doc)
- (point-marker))
- chunk-list))
- ;; Scan forward either to !/^@ %def/, which will start a docs chunk,
- ;; or to /^<<.*>>=$/, which will start a code chunk.
- (progn
- (forward-line 1)
- (while (looking-at "@ %def")
- (forward-line 1))
- (setq chunk-list
- ;; Now we can tell code vs docs
- (cons (cons (if (looking-at "<<\\(.*\\)>>=")
- (buffer-substring-no-properties
- (match-beginning 1) (match-end 1))
- 'doc)
- (point-marker))
- chunk-list))))
- (forward-line 1))
- (setq chunk-list (cons (cons 'doc (point-max-marker)) chunk-list))
- (setq ess-noweb-chunk-vector (vconcat (reverse chunk-list))))))
-
-(defun ess-noweb-find-chunk ()
- "Return a pair consisting of the name (or 'DOC) and the
-marker of the current chunk."
- (if (not ess-noweb-chunk-vector)
- (ess-noweb-update-chunk-vector))
- (aref ess-noweb-chunk-vector (ess-noweb-find-chunk-index-buffer)))
-
-(defun ess-noweb-chunk-is-code (index)
- "Return t if the chunk 'index' is a code chunk, nil otherwise"
- (interactive)
- (stringp (car (ess-noweb-chunk-vector-aref index))))
-
-(defun ess-noweb-in-code-chunk ()
- "Return t if we are in a code chunk, nil otherwise."
- (interactive)
- (ess-noweb-chunk-is-code (ess-noweb-find-chunk-index-buffer)))
-
-(defun ess-noweb-in-mode-line ()
- "Return the name of the mode to use if we are in a mode line, nil
-otherwise."
- (interactive)
- (let (beg end mode)
- (save-excursion
- (beginning-of-line 1)
- (and (progn
- (ess-write-to-dribble-buffer
- (format "(n-i-m-l: 1)"))
- (search-forward "-*-"
- (save-excursion (end-of-line) (point))
- t))
- (progn
- (ess-write-to-dribble-buffer
- (format "(n-i-m-l: 2)"))
- (skip-chars-forward " \t")
- (setq beg (point))
- (search-forward "-*-"
- (save-excursion (end-of-line) (point))
- t))
- (progn
- (ess-write-to-dribble-buffer
- (format "(n-i-m-l: 3)"))
- (forward-char -3)
- (skip-chars-backward " \t")
- (setq end (point))
- (goto-char beg)
- (setq mode (concat
- (downcase (buffer-substring beg end))
- "-mode"))
- (if (and (>= (length mode) 11))
- (progn
- (if
- (equal (substring mode -10 -5) "-mode")
- (setq mode (substring mode 0 -5)))
- (if
- (equal (substring mode 0 5) "mode:")
- (setq mode (substring mode 6))))))
- (progn
- (ess-write-to-dribble-buffer
- (format "(n-i-m-l: 3) mode=%s" mode))
- (intern mode))))))
-
-(defun ess-noweb-find-chunk-index-buffer ()
- "Return the index of the current chunk in ess-noweb-CHUNK-VECTOR."
- (ess-noweb-find-chunk-index 0 (1- (length ess-noweb-chunk-vector))))
-
-(defun ess-noweb-find-chunk-index (low hi)
- (if (= hi (1+ low))
- low
- (let ((med (/ (+ low hi) 2)))
- (if (< (point) (cdr (aref ess-noweb-chunk-vector med)))
- (ess-noweb-find-chunk-index low med)
- (ess-noweb-find-chunk-index med hi)))))
-
-(defun ess-noweb-chunk-region ()
- "Return a pair consisting of the beginning and end of the current chunk."
- (interactive)
- (let ((start (ess-noweb-find-chunk-index-buffer)))
- (cons (marker-position (cdr (aref ess-noweb-chunk-vector start)))
- (marker-position (cdr (aref ess-noweb-chunk-vector (1+ start)))))))
-
-(defun ess-noweb-copy-code-chunk ()
- "Copy the current code chunk to the kill ring, excluding the chunk name.
-This will be particularly useful when interfacing with ESS."
- (interactive)
- (let ((r (ess-noweb-chunk-region)))
- (save-excursion
- (goto-char (car r))
- (if (ess-noweb-in-code-chunk)
- (progn
- (beginning-of-line 2)
- (copy-region-as-kill (point) (cdr r)))))))
-
-(defun ess-noweb-extract-code-chunk ()
- "Create a new buffer with the same name as the current code chunk,
-and copy all code from chunks of the same name to it."
- (interactive)
- (save-excursion
- (if (ess-noweb-in-code-chunk)
- (progn
- (let ((chunk-name (car (ess-noweb-find-chunk)))
- (chunk-counter 0)
- (copy-counter 0)
- (this-chunk) (oldbuf (current-buffer)))
- (if (get-buffer chunk-name)
- (progn
- (set-buffer-modified-p nil)
- (kill-buffer chunk-name)))
- (get-buffer-create chunk-name)
- (message "Created buffer %s" chunk-name)
- (while (< chunk-counter (- (length ess-noweb-chunk-vector) 2))
- (setq this-chunk (ess-noweb-chunk-vector-aref
- chunk-counter))
- (message "Current buffer is %s" (car this-chunk))
- (if (equal chunk-name (car this-chunk))
- (progn
- (setq copy-counter (+ copy-counter 1))
- (goto-char (cdr this-chunk))
- (ess-noweb-copy-code-chunk)
- (set-buffer chunk-name)
- (goto-char (point-max))
- (yank)
- (set-buffer oldbuf)))
- (setq chunk-counter (+ chunk-counter 1)))
- (message "Copied %d bits" copy-counter)
- (set-buffer chunk-name)
- (copy-region-as-kill (point-min)(point-max)))))))
-
-(defun ess-noweb-chunk-pair-region ()
- "Return a pair consisting of the beginning and end of the current pair of
-documentation and code chunks."
- (interactive)
- (let* ((start (ess-noweb-find-chunk-index-buffer))
- (end (1+ start)))
- (if (ess-noweb-chunk-is-code start)
- (cons (marker-position (cdr (aref ess-noweb-chunk-vector (1- start))))
- (marker-position (cdr (aref ess-noweb-chunk-vector end))))
- (while (not (ess-noweb-chunk-is-code end))
- (setq end (1+ end)))
- (cons (marker-position (cdr (aref ess-noweb-chunk-vector start)))
- (marker-position (cdr (aref ess-noweb-chunk-vector (1+ end))))))))
-
-(defun ess-noweb-chunk-vector-aref (i)
- (if (< i 0)
- (error "Before first chunk."))
- (if (not ess-noweb-chunk-vector)
- (ess-noweb-update-chunk-vector))
- (if (>= i (length ess-noweb-chunk-vector))
- (error "Beyond last chunk."))
- (aref ess-noweb-chunk-vector i))
-
-(defun ess-noweb-complete-chunk ()
- "Complete the chunk name before point, if any."
- (interactive)
- (if (ess-noweb-in-code-chunk)
- (let ((end (point))
- (beg (save-excursion
- (if (re-search-backward "<<"
- (save-excursion
- (beginning-of-line)
- (point))
- t)
- (match-end 0)
- nil))))
- (if beg
- (let* ((pattern (buffer-substring beg end))
- (alist (ess-noweb-build-chunk-alist))
- (completion (try-completion pattern alist)))
- (cond ((eq completion t))
- ((null completion)
- (message "Can't find completion for \"%s\"" pattern)
- (ding))
- ((not (string= pattern completion))
- (delete-region beg end)
- (insert completion)
- (if (not (looking-at ">>"))
- (insert ">>")))
- (t
- (message "Making completion list...")
- (with-output-to-temp-buffer "*Completions*"
- (display-completion-list (all-completions pattern alist)))
- (message "Making completion list...%s" "done"))))
- (message "Not at chunk name...")))
- (message "Not in code chunk...")))
-
-\f
-;;; Filling, etc
-
-(defun ess-noweb-hide-code-quotes ()
- "Replace all non blank characters in [[...]] code quotes
-in the current buffer (you might want to narrow to the interesting
-region first) by `*'. Return a list of pairs with the position and
-value of the original strings."
- (save-excursion
- (let ((quote-list nil))
- (goto-char (point-min))
- (while (re-search-forward "\\[\\[" nil 'move)
- (let ((beg (match-end 0))
- (end (if (re-search-forward "\\]\\]" nil t)
- (match-beginning 0)
- (point-max))))
- (goto-char beg)
- (while (< (point) end)
- ;; Move on to the next word:
- (let ((b (progn
- (skip-chars-forward " \t\n" end)
- (point)))
- (e (progn
- (skip-chars-forward "^ \t\n" end)
- (point))))
- (if (> e b)
- ;; Save the string and a marker to the end of the
- ;; replacement text. A marker to the beginning is
- ;; useless. See ess-noweb-RESTORE-CODE-QUOTES.
- (save-excursion
- (setq quote-list (cons (cons (copy-marker e)
- (buffer-substring b e))
- quote-list))
- (goto-char b)
- (insert-char ?* (- e b) t)
- (delete-char (- e b))))))))
- (reverse quote-list))))
-
-(defun ess-noweb-restore-code-quotes (quote-list)
- "Reinsert the strings modified by `ess-noweb-hide-code-quotes'."
- (save-excursion
- (mapcar (lambda (q)
- (let* ((e (marker-position (car q)))
- ;; Slightly inefficient, but correct way to find
- ;; the beginning of the word to be replaced.
- ;; Using the marker at the beginning will loose
- ;; if whitespace has been rearranged
- (b (save-excursion
- (goto-char e)
- (skip-chars-backward "*")
- (point))))
- (delete-region b e)
- (goto-char b)
- (insert (cdr q))))
- quote-list)))
-
-(defun ess-noweb-fill-chunk ()
- "Fill the current chunk according to mode.
-Run `fill-region' on documentation chunks and `indent-region' on code
-chunks."
- (interactive)
- (save-excursion
- (save-restriction
- (ess-noweb-narrow-to-chunk)
- (if (ess-noweb-in-code-chunk)
- (progn
- ;; Narrow to the code section proper; w/o the first and any
- ;; index declaration lines.
- (narrow-to-region (progn
- (goto-char (point-min))
- (forward-line 1)
- (point))
- (progn
- (goto-char (point-max))
- (forward-line -1)
- (while (looking-at "@")
- (forward-line -1))
- (forward-line 1)
- (point)))
- (if (or indent-region-function indent-line-function)
- (indent-region (point-min) (point-max) nil)
- (error "No indentation functions defined in %s!" major-mode)))
- (if ess-noweb-code-quotes-handling
- (let ((quote-list (ess-noweb-hide-code-quotes)))
- (fill-region (point-min) (point-max))
- (ess-noweb-restore-code-quotes quote-list))
- (fill-region (point-min) (point-max)))))))
-
-(defun ess-noweb-indent-region (beg end)
- "If region fits inside current chunk, narrow to chunk and then
-indent according to mode."
- (interactive "r")
- (let* ((inx (ess-noweb-find-chunk-index-buffer))
- (ch-beg (marker-position (cdr (aref ess-noweb-chunk-vector inx))))
- (ch-end (marker-position (cdr (aref ess-noweb-chunk-vector (1+ inx))))))
-
- (if (and (< ch-beg beg) (> ch-end end))
- (save-excursion
- (save-restriction
- (setq beg (max beg (progn (goto-char ch-beg)
- (forward-line 1)
- (point))))
- (setq end (min end (progn (goto-char ch-end)
- (forward-line -1)
- (point))))
- (narrow-to-region beg end)
- (indent-region beg end)))
- (indent-region beg end))))
-
-
-(defun ess-noweb-indent-line ()
- "Indent the current line according to mode, after narrowing to this chunk."
- (interactive)
- (ess-noweb-update-chunk-vector)
- (save-restriction
- (ess-noweb-narrow-to-chunk)
- (if (ess-noweb-in-code-chunk)
- (progn
- ;; Narrow to the code section proper; w/o the first and any
- ;; index declaration lines.
- (save-excursion
- (narrow-to-region (progn
- (goto-char (point-min))
- (forward-line 1)
- (point))
- (progn
- (goto-char (point-max))
- (forward-line -1)
- (while (looking-at "@")
- (forward-line -1))
- (forward-line 1)
- (point))))))
- (indent-according-to-mode)))
-
-(defun ess-noweb-fill-paragraph-chunk (&optional justify)
- "Fill a paragraph in the current chunk."
- (interactive "P")
- (ess-noweb-update-chunk-vector)
- (save-excursion
- (save-restriction
- (ess-noweb-narrow-to-chunk)
- (if (ess-noweb-in-code-chunk)
- (progn
- ;; Narrow to the code section proper; w/o the first and any
- ;; index declaration lines.
- (narrow-to-region (progn
- (goto-char (point-min))
- (forward-line 1)
- (point))
- (progn
- (goto-char (point-max))
- (forward-line -1)
- (while (looking-at "@")
- (forward-line -1))
- (forward-line 1)
- (point)))
- (fill-paragraph justify))
- (if ess-noweb-code-quotes-handling
- (let ((quote-list (ess-noweb-hide-code-quotes)))
- (fill-paragraph justify)
- (ess-noweb-restore-code-quotes quote-list))
- (fill-paragraph justify))))))
-
-(defun ess-noweb-auto-fill-doc-chunk ()
- "Replacement for `do-auto-fill'."
- (save-restriction
- (narrow-to-region (car (ess-noweb-chunk-region))
- (save-excursion
- (end-of-line)
- (point)))
- (if ess-noweb-code-quotes-handling
- (let ((quote-list (ess-noweb-hide-code-quotes)))
- (do-auto-fill)
- (ess-noweb-restore-code-quotes quote-list))
- (do-auto-fill))))
-
-(defun ess-noweb-auto-fill-doc-mode ()
- "Install the improved auto fill function, iff necessary."
- (if auto-fill-function
- (setq auto-fill-function 'ess-noweb-auto-fill-doc-chunk)))
-
-(defun ess-noweb-auto-fill-code-chunk ()
- "Replacement for do-auto-fill. Cancel filling in chunk headers"
- (unless (save-excursion
- (beginning-of-line)
- (looking-at "<<"))
- (do-auto-fill)))
-
-(defun ess-noweb-auto-fill-code-mode ()
- "Install the default auto fill function, iff necessary."
- (if auto-fill-function
- (setq auto-fill-function 'ess-noweb-auto-fill-code-chunk)))
-\f
-;;; Marking
-
-(defun ess-noweb-mark-chunk ()
- "Mark the current chunk."
- (interactive)
- (let ((r (ess-noweb-chunk-region)))
- (goto-char (car r))
- (push-mark (cdr r) nil t)))
-
-(defun ess-noweb-mark-chunk-pair ()
- "Mark the current pair of documentation and code chunks."
- (interactive)
- (let ((r (ess-noweb-chunk-pair-region)))
- (goto-char (car r))
- (push-mark (cdr r) nil t)))
-
-\f
-;;; Narrowing
-
-(defun ess-noweb-toggle-narrowing (&optional arg)
- "Toggle if we should narrow the display to the current pair of
-documentation and code chunks after each movement. With argument:
-switch narrowing on."
- (interactive "P")
- (if (or arg (not ess-noweb-narrowing))
- (progn
- (setq ess-noweb-narrowing t)
- (ess-noweb-narrow-to-chunk-pair))
- (setq ess-noweb-narrowing nil)
- (widen)))
-
-(defun ess-noweb-narrow-to-chunk ()
- "Narrow the display to the current chunk."
- (interactive)
- (let ((r (ess-noweb-chunk-region)))
- (narrow-to-region (car r) (cdr r))))
-
-(defun ess-noweb-narrow-to-chunk-pair ()
- "Narrow the display to the current pair of documentation and code chunks."
- (interactive)
- (let ((r (ess-noweb-chunk-pair-region)))
- (narrow-to-region (car r) (cdr r))))
-
-\f
-;;; Killing
-
-(defun ess-noweb-kill-chunk ()
- "Kill the current chunk."
- (interactive)
- (let ((r (ess-noweb-chunk-region)))
- (kill-region (car r) (cdr r))))
-
-(defun ess-noweb-kill-chunk-pair ()
- "Kill the current pair of chunks."
- (interactive)
- (let ((r (ess-noweb-chunk-pair-region)))
- (kill-region (car r) (cdr r))))
-
-(defun ess-noweb-copy-chunk-as-kill ()
- "Place the current chunk on the kill ring."
- (interactive)
- (let ((r (ess-noweb-chunk-region)))
- (copy-region-as-kill (car r) (cdr r))))
-
-(defun ess-noweb-copy-chunk-pair-as-kill ()
- "Place the current pair of chunks on the kill ring."
- (interactive)
- (let ((r (ess-noweb-chunk-pair-region)))
- (copy-region-as-kill (car r) (cdr r))))
-
-\f
-;;; Movement
-
-(defun ess-noweb-sign (n)
- "Return the sign of N."
- (if (< n 0) -1 1))
-
-(defun ess-noweb-next-doc-chunk (&optional cnt)
- "Goto to the Nth documentation chunk from point."
- (interactive "p")
- (widen)
- (let ((start (ess-noweb-find-chunk-index-buffer))
- (i 1))
- (while (<= i (abs cnt))
- (setq start (+ (ess-noweb-sign cnt) start))
- (while (ess-noweb-chunk-is-code start)
- (setq start (+ (ess-noweb-sign cnt) start)))
- (setq i (1+ i)))
- (goto-char (marker-position (cdr (ess-noweb-chunk-vector-aref start))))
- (forward-char 1))
- (if ess-noweb-narrowing
- (ess-noweb-narrow-to-chunk-pair)))
-
-(defun ess-noweb-previous-doc-chunk (&optional n)
- "Goto to the -Nth documentation chunk from point."
- (interactive "p")
- (ess-noweb-next-doc-chunk (- n)))
-
-(defun ess-noweb-next-code-chunk (&optional cnt)
- "Goto to the Nth code chunk from point."
- (interactive "p")
- (widen)
- (let ((start (ess-noweb-find-chunk-index-buffer))
- (i 1))
- (while (<= i (abs cnt))
- (setq start (+ (ess-noweb-sign cnt) start))
- (while (not (ess-noweb-chunk-is-code start))
- (setq start (+ (ess-noweb-sign cnt) start)))
- (setq i (1+ i)))
- (goto-char (marker-position (cdr (ess-noweb-chunk-vector-aref start))))
- (forward-line 1))
- (if ess-noweb-narrowing
- (ess-noweb-narrow-to-chunk-pair)))
-
-(defun ess-noweb-previous-code-chunk (&optional n)
- "Goto to the -Nth code chunk from point."
- (interactive "p")
- (ess-noweb-next-code-chunk (- n)))
-
-(defun ess-noweb-next-chunk (&optional n)
- "If in a documentation chunk, goto to the Nth documentation
-chunk from point, else goto to the Nth code chunk from point."
- (interactive "p")
- (if (ess-noweb-in-code-chunk)
- (ess-noweb-next-code-chunk n)
- (ess-noweb-next-doc-chunk n)))
-
-(defun ess-noweb-previous-chunk (&optional n)
- "If in a documentation chunk, goto to the -Nth documentation
-chunk from point, else goto to the -Nth code chunk from point."
- (interactive "p")
- (ess-noweb-next-chunk (- n)))
-
-(defvar ess-noweb-chunk-history nil
- "")
-
-(defun ess-noweb-goto-chunk ()
- "Goto the named chunk."
- (interactive)
- (widen)
- (let* ((completion-ignore-case t)
- (alist (ess-noweb-build-chunk-alist))
- (chunk (ess-completing-read
- "Chunk" (delete "" (mapcar 'car alist)) nil t nil
- ess-noweb-chunk-history (ess-noweb-goto-chunk-default))))
- (goto-char (cdr (assoc chunk alist))))
- (if ess-noweb-narrowing
- (ess-noweb-narrow-to-chunk-pair)))
-
-(defun ess-noweb-goto-chunk-default ()
- (save-excursion
- (if (re-search-backward "<<"
- (save-excursion
- (beginning-of-line)
- (point))
- 'move)
- (goto-char (match-beginning 0)))
- (if (re-search-forward "<<\\(.*\\)>>"
- (save-excursion
- (end-of-line)
- (point))
- t)
- (buffer-substring (match-beginning 1) (match-end 1))
- nil)))
-
-(defun ess-noweb-build-chunk-alist ()
- (if (not ess-noweb-chunk-vector)
- (ess-noweb-update-chunk-vector))
- ;; The naive recursive solution will exceed MAX-LISP-EVAL-DEPTH in
- ;; buffers w/ many chunks. Maybe there is a tail recursivce solution,
- ;; but iterative solutions should be acceptable for dealing with vectors.
- (let ((alist nil)
- (i (1- (length ess-noweb-chunk-vector))))
- (while (>= i 0)
- (let* ((chunk (aref ess-noweb-chunk-vector i))
- (name (car chunk))
- (marker (cdr chunk)))
- (if (and (stringp name)
- (not (assoc name alist)))
- (setq alist (cons (cons name marker) alist))))
- (setq i (1- i)))
- alist))
-
-(defun ess-noweb-goto-next (&optional cnt)
- "Goto the continuation of the current chunk."
- (interactive "p")
- (widen)
- (if (not ess-noweb-chunk-vector)
- (ess-noweb-update-chunk-vector))
- (let ((start (ess-noweb-find-chunk-index-buffer)))
- (if (not (ess-noweb-chunk-is-code start))
- (setq start (1+ start)))
- (if (ess-noweb-chunk-is-code start)
- (let ((name (car (ess-noweb-chunk-vector-aref start)))
- (i 1))
- (while (<= i (abs cnt))
- (setq start (+ (ess-noweb-sign cnt) start))
- (while (not (equal (car (ess-noweb-chunk-vector-aref start))
- name))
- (setq start (+ (ess-noweb-sign cnt) start)))
- (setq i (1+ i)))
- (goto-char (marker-position
- (cdr (ess-noweb-chunk-vector-aref start))))
- (forward-line 1))))
- (if ess-noweb-narrowing
- (ess-noweb-narrow-to-chunk-pair)))
-
-(defun ess-noweb-goto-previous (&optional cnt)
- "Goto the previous chunk."
- (interactive "p")
- (ess-noweb-goto-next (- cnt)))
-
-(defun ess-noweb-occur (arg)
- "Find all occurences of the current chunk.
-This function simply runs OCCUR on \"<<NAME>>\"."
- (interactive "P")
- (let ((n (if (and arg
- (numberp arg))
- arg
- 0))
- (idx (ess-noweb-find-chunk-index-buffer)))
- (if (ess-noweb-chunk-is-code idx)
- (occur (regexp-quote (concat "<<"
- (car (aref ess-noweb-chunk-vector idx))
- ">>"))
- n)
- (setq idx (1+ idx))
- (while (not (ess-noweb-chunk-is-code idx))
- (setq idx (1+ idx)))
- (occur (regexp-quote (concat "<<"
- (car (aref ess-noweb-chunk-vector idx))
- ">>"))
- n))))
-
-\f
-;;; Insertion
-
-(defun ess-noweb-new-chunk (name)
- "Insert a new chunk."
- (interactive "sChunk name: ")
- (insert "@ \n<<" name ">>=\n")
- (save-excursion
- (insert "@ %def \n"))
- (ess-noweb-update-chunk-vector))
-
-(defun ess-noweb-at-beginning-of-line ()
- (equal (save-excursion
- (beginning-of-line)
- (point))
- (point)))
-
-(defun ess-noweb-electric-@ (arg)
- "Smart incarnation of `@', starting a new documentation chunk, maybe.
-If given an numerical argument, it will act just like the dumb `@'.
-Otherwise and if at the beginning of a line in a code chunk:
-insert \"@ \" and update the chunk vector."
- (interactive "P")
- (if arg
- (self-insert-command (if (numberp arg) arg 1))
- (if (and (ess-noweb-at-beginning-of-line)
- (ess-noweb-in-code-chunk))
- (progn
- (insert "@ ")
- (ess-noweb-update-chunk-vector))
- (self-insert-command 1))))
-
-(defun ess-noweb-electric-< (arg)
- "Smart incarnation of `<', starting a new code chunk, maybe.
-If given an numerical argument, it will act just like the dumb `<'.
-Otherwise and if at the beginning of a line in a documentation chunk:
-insert \"<<>>=\", a closing \"@\" and a newline if necessary. Leave point
-in the middle and and update the chunk vector."
- (interactive "P")
- (if arg
- (self-insert-command (if (numberp arg) arg 1))
- (if (and (ess-noweb-at-beginning-of-line)
- (not (ess-noweb-in-code-chunk)))
- (progn
- (insert "<<")
- (save-excursion
- (insert ">>=\n@ ")
- (if (not (looking-at "\\s *$"))
- (newline)))
- (ess-noweb-update-chunk-vector))
- (self-insert-command 1))))
-
-\f
-;;; Modes
-
-(defun ess-noweb-set-chunk-code-mode ()
- "Set the ess-noweb-code-mode for the current chunk"
- (interactive)
- (if (ess-noweb-in-code-chunk)
- (progn
- ;; Reset code-mode to default and then check for a mode comment.
- (setq ess-noweb-code-mode ess-noweb-default-code-mode)
- (let (mode chunk-name)
- (save-excursion
- (save-restriction
- (end-of-line)
- (re-search-backward "^[ \t]*<<\\(.*\\)>>=" nil t)
- (setq chunk-name (match-string 1))
- (widen)
- (goto-char (point-min))
- (re-search-forward (concat "^<<" (regexp-quote chunk-name) ">>=") nil t)
- (beginning-of-line 2)
- (setq mode (ess-noweb-in-mode-line))
- (if (functionp mode)
- (setq ess-noweb-code-mode mode))))))
- (error "This only makes sense in a code chunk")))
-
-(defun ess-noweb-set-doc-syntax-table ()
- "Sets the doc-mode syntax-table to treat code quotes as comments."
- (interactive)
- (let ((square-bracket-string (char-to-string (char-syntax ?\[))))
- (if (string= square-bracket-string "(")
- (progn
- (modify-syntax-entry ?\[ "(]12b" ess-noweb-doc-mode-syntax-table)
- (modify-syntax-entry ?\] ")[34b" ess-noweb-doc-mode-syntax-table))
- (progn
- (modify-syntax-entry ?\[
- (concat square-bracket-string " 12b")
- ess-noweb-doc-mode-syntax-table)
- (modify-syntax-entry ?\]
- (concat square-bracket-string " 34b")
- ess-noweb-doc-mode-syntax-table)))))
-
-(defun ess-noweb-select-mode ()
- "Select ess-noweb-DOC-MODE or ess-noweb-CODE-MODE, as appropriate."
- (interactive)
- (let ((this-chunk-index (ess-noweb-find-chunk-index-buffer)))
- ;; Has the last change to the buffer taken us into a different
- ;; chunk ?
- (if (not (equal this-chunk-index ess-noweb-last-chunk-index))
- (progn
- (setq ess-noweb-last-chunk-index this-chunk-index)
- (if (ess-noweb-in-code-chunk)
- ;; Inside a code chunk
- (progn
- ;; Find out which code mode to use
- (ess-noweb-set-chunk-code-mode)
- ;; If we aren't already using it, use it.
- (if (not (equal major-mode ess-noweb-code-mode))
- (progn
- (funcall ess-noweb-code-mode)
- (run-hooks 'ess-noweb-select-mode-hook)
- (run-hooks 'ess-noweb-select-code-mode-hook))))
- ;; Inside a documentation chunk
- (progn
- (if (not (equal major-mode ess-noweb-doc-mode))
- (progn
- (funcall ess-noweb-doc-mode)))
- (if (not ess-noweb-doc-mode-syntax-table)
- (progn
- (message "Setting up syntax table")
- (setq ess-noweb-doc-mode-syntax-table
- (make-syntax-table (syntax-table)))
- (ess-noweb-set-doc-syntax-table)))
- (set-syntax-table ess-noweb-doc-mode-syntax-table)
- (run-hooks 'ess-noweb-select-mode-hook)
- (run-hooks 'ess-noweb-select-doc-mode-hook)))
- (run-hooks 'ess-noweb-changed-chunk-hook)))))
-
-(defun ess-noweb-set-doc-mode (mode)
- "Change the major mode for editing documentation chunks."
- (interactive "CNew major mode for documentation chunks: ")
- (setq ess-noweb-doc-mode mode)
- (setq ess-noweb-doc-mode-syntax-table nil)
- ;;Pretend we've changed chunk, so the mode will be reset if necessary
- (setq ess-noweb-last-chunk-index (1- ess-noweb-last-chunk-index))
- (ess-noweb-select-mode))
-
-(defun ess-noweb-set-code-mode (mode)
- "Change the major mode for editing all code chunks."
- (interactive "CNew major mode for all code chunks: ")
- (setq ess-noweb-default-code-mode mode)
- ;;Pretend we've changed chunk, so the mode will be reset if necessary
- (setq ess-noweb-last-chunk-index (1- ess-noweb-last-chunk-index))
- (ess-noweb-select-mode))
-
-(defun ess-noweb-set-this-code-mode (mode)
- "Change the major mode for editing this code chunk.
-The only sensible way to do this is to add a mode line to the chunk"
- (interactive "CNew major mode for this code chunk: ")
- (if (ess-noweb-in-code-chunk)
- (progn
- (setq ess-noweb-code-mode mode)
- (save-excursion
- (save-restriction
- (let (chunk-name)
- (widen)
- (end-of-line)
- (re-search-backward "^[ \t]*<<\\(.*\\)>>=" nil t)
- (setq chunk-name (match-string 1))
- (goto-char (point-min))
- (re-search-forward (concat "^<<" (regexp-quote chunk-name) ">>=") nil t)
- (beginning-of-line 2))
- ;; remove mode-line, if there is one
- (if (ess-noweb-in-mode-line)
- (progn
- (kill-line)
- (kill-line)))
- (if (not (equal ess-noweb-code-mode ess-noweb-default-code-mode))
- (progn
- (setq mode (substring (symbol-name mode) 0 -5))
- ;; Need to set major mode so that we can comment out
- ;; the mode line
- (funcall ess-noweb-code-mode)
- (if (not (boundp 'comment-start))
- (setq comment-start "#"))
- (insert comment-start
- " -*- " mode
- " -*- " comment-end "\n")))
- (setq ess-noweb-last-chunk-index (1- ess-noweb-last-chunk-index)))))
- (message "This only makes sense in a code chunk.")))
-\f
-;;; Misc
-
-(defvar ess-version)
-(defun ess-noweb-mode-version ()
- "Echo the RCS identification of noweb mode."
- (interactive)
- (message "Thorsten's ess-noweb-mode, now part of ESS version %s" ess-version))
-
-(defun ess-noweb-describe-mode ()
- "Describe noweb mode."
- (interactive)
- (describe-function 'ess-noweb-mode))
-
-(defun ess-noweb-insert-default-mode-line ()
- "Insert line that will set the noweb mode of this file in emacs.
-The file is set to use the current doc and default-code modes, so
-ensure they are set correctly (with ess-noweb-set-code-mode and
-ess-noweb-set-doc-mode) before calling this function"
- (interactive)
- (save-excursion
- (goto-char 1)
- (if (ess-noweb-in-mode-line)
- (progn
- (kill-line)
- (kill-line)))
- (if (not (eq major-mode ess-noweb-doc-mode))
- (ess-noweb-select-mode))
- (insert comment-start " -*- mode: noweb; ess-noweb-default-code-mode: "
- (symbol-name ess-noweb-default-code-mode)
- (if (not (eq ess-noweb-doc-mode ess-noweb-default-doc-mode))
- (concat "; ess-noweb-doc-mode: " (symbol-name
- ess-noweb-doc-mode) ";")
- ";")
- " -*-" comment-end "\n"))
- (ess-noweb-select-mode))
-
-(defun ess-noweb-mouse-first-button (event)
- (interactive "e")
- (mouse-set-point event)
- (if (and ess-noweb-use-mouse-navigation
- (eq (save-excursion
- (end-of-line)
- (re-search-backward "^[\t ]*\\(<<\\)\\(.*\\)\\(>>\\)" nil t))
- (save-excursion
- (beginning-of-line) (point))))
- (progn
- (if (< (point) (match-beginning 2))
- (let ((chunk-name (buffer-substring-no-properties
- (match-beginning 2)
- (match-end 2))))
- (re-search-backward (concat "<<" (regexp-quote chunk-name) ">>") nil t))
- (if (and (<= (match-end 2) (point))
- (> (+ 2 (match-end 2)) (point)))
- (let ((chunk-name (buffer-substring-no-properties
- (match-beginning 2)
- (match-end 2))))
- (re-search-forward (concat "<<" (regexp-quote chunk-name) ">>") nil t)))))))
-
-\f
-;;; Debugging
-
-(defun ess-noweb-log (s)
- (let ((b (current-buffer)))
- (pop-to-buffer-same-window (get-buffer-create "*noweb-log*"))
- (goto-char (point-max))
- (setq buffer-read-only nil)
- (insert s)
- (setq buffer-read-only t)
- (pop-to-buffer-same-window b)))
-
-
-
-
-
-(defvar ess-noweb-thread-alist nil
- "A list of threads in the current buffer.
-Each entry in the list contains 5 elements:
-1) The name of the threads
-2) The name of the immdiate parent thread in which it is used (nil if
- it is a \"top-level\" thread which is not used anywhere).
-3) The name of the top-level parent thread in which it is used (i.e. a
- thread in which it is used but which is not itself used anywhere:
- nil if this thread is not used anywhere.
-4) The format string to use to define line numbers in the output
- file of this thread. Should only be set if this thread is not used
- anywhere: if a thread is used as part of another thread, the parent
- thread's format string should be used.
-5) If this is nil, tabs are converted to spaces in the tangled
- file. If it is a number, tabs are copied to the tangled file
- unchanged, and tabs are also used for indentation, with the number
- of spaces per tab defined by this number. This MUST be set in order
- to tangle makefiles, which depend on tabs.Should only be set if
- this thread is not used anywhere. otherwise set to nil. "
- )
-
-(defun ess-noweb-update-thread-alist ()
- "Updates the list of threads in the current buffer.
-Each entry in the list contains 5 elements:
-1) The name of the thread
-2) The name of the immdiate parent thread in which it is used (nil if
- it is a \"top-level\" thread which is not used anywhere).
-3) The name of the top-level parent thread in which it is used (i.e. a
- thread in which it is used but which is not itself used anywhere:
- nil if this thread is not used anywhere.
-4) The format string to use to define line numbers in the output
- file of this thread. Should only be set if this thread is not used
- anywhere: if a thread is used as part of another thread, the parent
- thread's format string should be used.
-5) If this is nil, tabs are converted to spaces in the tangled
- file. If it is a number, tabs are copied to the tangled file
- unchanged, and tabs are also used for indentation, with the number
- of spaces per tab defined by this number. This MUST be set in order
- to tangle makefiles, which depend on tabs.Should only be set if
- this thread is not used anywhere. otherwise set to nil. "
- (interactive)
- (save-excursion
- (goto-char (point-min))
- (let ((thread-alist) (thread-list-entry) (chunk-use-name)
- (current-thread) (new-thread-alist))
- (while (re-search-forward
- "^[ \t]*<<\\(.*\\)>>\\(=\\)?" nil t)
- (goto-char (match-beginning 0))
- ;; Is this the definition of a chunk ?
- (if (match-beginning 2)
- ;;We have a chunk definition
- (progn
- ;; Get the thread name
- (setq current-thread
- (buffer-substring-no-properties (match-beginning 1)
- (match-end 1)))
- ;; Is this thread already in our list ?
- (if (assoc current-thread thread-alist)
- nil
- (progn
- ;; If not, create an entry with 4 nils at the end
- (setq thread-list-entry
- (list (cons current-thread
- (make-list 4 nil))))
- ;; And add it to the list
- (setq thread-alist
- (append thread-alist thread-list-entry)))))
-
- ;; Not a definition but a use
- (progn
- ;; Get the thread name
- (setq chunk-use-name
- (buffer-substring-no-properties (match-beginning 1)
- (match-end 1)))
- ;; Has the thread already been defined before being used ?
- (if (setq thread-list-entry (assoc chunk-use-name
- thread-alist))
- ;; If it has, set its parent to be the thread we are in at the moment
- (setcar (cdr thread-list-entry) current-thread)
- ;; If not, add it to the list, with its parent name and 3 nils
- (progn
- (setq thread-list-entry
- (list (cons chunk-use-name
- (cons current-thread
- (make-list 3 nil)))))
- (setq thread-alist (append thread-alist thread-list-entry)))))
- )
- ;;Go to the next line
- (beginning-of-line 2))
- ;; Now, the second element of each entry points to that thread's
- ;; immediate parent. Need to set it to the thread's ultimate
- ;; parent.
- (let ((thread-counter 0)
- (this-thread)
- (this-thread-parent))
- (while (<= thread-counter (1- (length thread-alist)))
- (setq this-thread (nth thread-counter thread-alist))
- (setq this-thread-parent (assoc
- (car (cdr this-thread))
- thread-alist))
- (while (not (equal nil (car (cdr this-thread-parent))))
- (setq this-thread-parent (assoc
- (car (cdr this-thread-parent))
- thread-alist)))
- (setq this-thread (cons (car this-thread)
- (cons (car (cdr this-thread))
- (cons (car this-thread-parent)
- (nthcdr 2 this-thread)))))
- (setq new-thread-alist (append new-thread-alist (list this-thread)))
- (setq thread-counter (1+ thread-counter))))
-
- (setq ess-noweb-thread-alist new-thread-alist))))
-
-
- ; Option setting functions to go here
-
-(defun ess-noweb-set-thread-line-format ())
-
-(defun ess-noweb-set-thread-tabs ())
-
-
-(defvar ess-noweb-default-line-number-format nil
- "The format string to use to define line numbers in this thread.
-If nil, do not use line numbers.")
-
-(defvar ess-noweb-default-line-number-skip-lines 0
- "The number of initial lines to output before the line number.
-This may be useful in shell scripts, where the first line (or two) must have a
- specific form.")
-
-(defvar ess-noweb-default-tab-width 8
- "If a number, convert tabs to that number of spaces in the output. If nil, let tabs through to the output unaltered.")
-
-(defvar ess-noweb-line-number-format ess-noweb-default-line-number-format
- "The format string to use to define line numbers in this thread.
-If nil, do not use line numbers.")
-
-(defvar ess-noweb-line-number-skip-lines ess-noweb-default-line-number-skip-lines
- "The number of initial lines to output before the line number.
-This may be useful in shell scripts, where the first line (or two) must have a
- specific form.")
-
-(defvar ess-noweb-tab-width ess-noweb-default-tab-width
- "If a number, convert tabs to that number of spaces in the output. If nil, let tabs through to the output unaltered.")
-
-(defun ess-noweb-get-thread-local-variables ()
- "Get the values of the variables that are local to a thread."
- (interactive)
- (save-excursion
- (save-restriction
- (end-of-line)
- (re-search-backward "^[ \t]*<<\\(.*\\)>>=" nil t)
- (let ((chunk-name (match-string 1)))
- (widen)
- (goto-char (point-min))
- (re-search-forward (concat "^<<" (regexp-quote chunk-name) ">>=") nil t)
- (beginning-of-line 2)
- (while (looking-at ".*-\*-.*-\*-")
- (let ((this-line (buffer-substring-no-properties
- (point)
- (progn (end-of-line) (point)))))
- (if (string-match
- "mode:[ \t]*\\([^\t ]*\\)" this-line)
- (setq ess-noweb-code-mode
- (match-string-no-properties 1 this-line)))
- (if (string-match
- "ess-noweb-line-number-format:[ \t]*\"\\([^\"]*\\)\"" this-line)
- (setq ess-noweb-line-number-format
- (match-string-no-properties 1 this-line)))
- (if (string-match
- "ess-noweb-line-number-skip-lines:[ \t]*\\([^\t ]*\\)" this-line)
- (setq ess-noweb-line-number-skip-lines
- (string-to-number
- (match-string-no-properties 1 this-line))))
- (if (string-match
- "ess-noweb-tab-width:[ \t]*\\([^\t ]*\\)" this-line)
- (setq ess-noweb-tab-width
- (string-to-number
- (match-string-no-properties 1 this-line))))
- (beginning-of-line 2)))))))
-
-(defun ess-noweb-reset-thread-local-variables ()
- "Resets the thread-local variables to their default values"
- (setq ess-noweb-tab-width ess-noweb-default-tab-width)
- (setq ess-noweb-line-number-format ess-noweb-default-line-number-format)
- (setq ess-noweb-line-number-skip-lines ess-noweb-default-line-number-skip-lines))
-
-(defun ess-noweb-write-line-number (line-number-format buffer)
- (if line-number-format
- (progn
- (let ((this-line (count-lines (point-min)(point))))
- (while (string-match ".*\\(%L\\).*" line-number-format)
- (setq line-number-format
- (replace-match
- (format "%d" this-line) t t line-number-format 1)))
- (while (string-match ".*\\(%F\\).*" line-number-format)
- (setq line-number-format
- (replace-match
- (format "%s" (buffer-file-name)) t t line-number-format 1)))
- (while (string-match ".*\\(%N\\).*" line-number-format)
- (setq line-number-format
- (replace-match "\n" t t line-number-format 1)))
- (with-current-buffer buffer
- (insert line-number-format))))))
-
-
-(defun ess-noweb-tangle-chunk ( &optional buffer prefix-string)
- "Generate the code produced by this chunk, & any threads used in this chunk."
- (interactive)
- (save-excursion
- (ess-noweb-reset-thread-local-variables)
- (ess-noweb-get-thread-local-variables)
- (ess-noweb-update-chunk-vector)
- (let*
- ((chunk-end (progn
- (end-of-line)
- (re-search-forward "^@" nil t)
- (beginning-of-line)
- (point)))
- ;;get name and start point of this chunk
- (chunk-start (progn
- (re-search-backward "^<<\\([^>]*\\)>>=$" nil t)
- (beginning-of-line 2)
- (point)))
- (chunk-name (buffer-substring-no-properties
- (match-end 1)
- (match-beginning 1)))
- ;; get end of this chunk
- ;; Get information we need about this thread
- (thread-info (assoc chunk-name ess-noweb-thread-alist))
- (thread-tabs (nth 4 thread-info))
- (line-number-format (nth 3 thread-info))
- (thread-name-re) (post-chunk) (pre-chunk)
- (first-line t)
- (tangle-buffer (generate-new-buffer "Tangle Buffer")))
-
- (progn
- (goto-char chunk-start)
- ;; If this is a mode-line, ignore it
- (while (looking-at ".*-\\*-.*-\\*-")
- (beginning-of-line 2))
- ;; If we want to include line numbers, write one
- (if line-number-format
- (while (> ess-noweb-line-number-skip-lines 0)
- (append-to-buffer tangle-buffer
- (point)
- (save-excursion
- (progn
- (end-of-line)
- (point))))
- (beginning-of-line 2)
- (1- ess-noweb-line-number-skip-lines))
- (ess-noweb-write-line-number line-number-format buffer))
- (message "Now at %d" (point))
-
- (while (< (point) chunk-end)
- (untabify (point) (save-excursion (beginning-of-line 2)(point)))
- ;; This RE gave me trouble. Without the `\"', it
- ;; recognised itself and so could not copy itself
- ;; correctly.
- (if (looking-at
- "\\([^\n\"@]*\\)<<\\(.*\\)\\(>>\\)\\([^\n\"]*\\)$")
- (progn
- (save-excursion
- (save-restriction
- (setq thread-name-re
- (concat "<<"
- (regexp-quote (match-string 2))
- ">>="))
- (setq pre-chunk (match-string 1))
- (if prefix-string
- (setq pre-chunk (concat prefix-string
- pre-chunk)))
- (setq post-chunk (match-string 4))
- (widen)
- (goto-char (point-min))
- (while (re-search-forward thread-name-re nil t)
- (ess-noweb-tangle-chunk tangle-buffer pre-chunk)
- (forward-line 1)))
- (if post-chunk
- (with-current-buffer tangle-buffer
- (backward-char)
- (insert post-chunk)
- (beginning-of-line 2)))))
-
- ;; Otherwise, just copy this line
- (setq pre-chunk
- (buffer-substring
- (point)
- (save-excursion
- (beginning-of-line 2)
- (point))))
- ;; Add a prefix if necessary
- (if (and prefix-string
- (> (length pre-chunk) 1))
- (setq pre-chunk (concat prefix-string
- pre-chunk)))
- ;; And copy it to the buffer
- (with-current-buffer tangle-buffer
- (insert pre-chunk)))
- ;; If this is the first line of the chunk, we need to change
- ;; prefix-string to consist solely of spaces
- (if (and first-line
- prefix-string)
- (progn
- (setq prefix-string
- (make-string (length prefix-string) ?\ ))
- (setq first-line nil)))
- ;; Either way, go to the next line
- (beginning-of-line 2))
-
- (with-current-buffer tangle-buffer
- (goto-char (point-min))
- (while (re-search-forward "\@\<<" nil t)
- (replace-match "<<" nil nil)
- (forward-char 3))
- (if thread-tabs
- (progn
- (setq tab-width thread-tabs)
- (tabify (point-min)(point-max)))
- (untabify (point-min)(point-max))))
-
- (if buffer
- (with-current-buffer buffer
- (insert-buffer-substring tangle-buffer)
- (kill-buffer tangle-buffer)))
- ))))
-
-(defun ess-noweb-tangle-thread ( name &optional buffer)
- "Given the name of a thread, tangles the thread to buffer.
-If no buffer is given, create a new one with the same name as the
-thread."
- (interactive "sWhich thread ? ")
- (if (not buffer)
- (progn
- (setq buffer (get-buffer-create name))
- (with-current-buffer buffer
- (erase-buffer))))
- (save-excursion
- (goto-char (point-min))
- (let ((chunk-counter 0))
- (while (re-search-forward
- "^<<\\(.*\\)>>=[\t ]*" nil t)
- (if (string= (match-string 1)
- name)
- (progn
- (setq chunk-counter (1+ chunk-counter))
- (message "Found %d chunks" chunk-counter)
- (ess-noweb-tangle-chunk buffer)))))))
-
-(defun ess-noweb-tangle-current-thread ( &optional buffer)
- (interactive)
- (save-excursion
- (let* ((chunk-start
- (progn
- (re-search-backward "^<<\\([^>]*\\)>>=[\t ]*$"
- nil t)
- (beginning-of-line 2)
- (point)))
- (chunk-name (buffer-substring-no-properties
- (match-end 1)
- (match-beginning 1))))
- (ess-noweb-tangle-thread chunk-name buffer))))
- ;menu functions
-
-;;;###autoload
-(defun Rnw-mode ()
- "Major mode for editing Sweave(R) source.
-See `ess-noweb-mode' and `R-mode' for more help."
- (interactive)
- (require 'ess-noweb);; << probably someplace else
- (setq ess--make-local-vars-permanent t)
- (ess-noweb-mode 1); turn it on
- (ess-noweb-set-doc-mode 'latex-mode)
- (ess-noweb-set-code-mode 'R-mode)
- (setq ess--local-handy-commands
- (append '(("weave" . ess-swv-weave)
- ("tangle" . ess-swv-tangle))
- ess-handy-commands)
- ess-dialect "R"
- ess-language "S")
- (put 'ess--local-handy-commands 'permanent-local t)
- (run-mode-hooks 'Rnw-mode-hook))
-
-(fset 'Snw-mode 'Rnw-mode); just a synonym (for now or ever)
-
-;;;###autoload
-(add-to-list 'auto-mode-alist '("\\.[rR]nw\\'" . Rnw-mode))
-;;;###autoload
-(add-to-list 'auto-mode-alist '("\\.[sS]nw\\'" . Snw-mode))
-
-\f
-;;; Finale
-
-(run-hooks 'ess-noweb-mode-load-hook)
-(provide 'ess-noweb-mode)
-
-;; Changes made by Mark Lunt (mark.luntNOSPAMmrc-bsu.cam.ac.uk) 22/03/1999
-
-;; The possibility of having code chunks using more than one language
-;; was added. This was first developed by Adnan Yaqub
-;; (AYaqubNOSPAMorga.com) for syntax highlighting, but even people who hate
-;; highlighting may like to maintain their Makefile with their code,
-;; or test-scripts with their programs, or even user documentation as
-;; latex-mode code chunks.
-;; This required quite a few changes to ess-noweb-mode:
-;; 1) A new variable `ess-noweb-default-code-mode' was create to do the job
-;; `ess-noweb-code-mode' used to.
-;; 2) ess-noweb-code-mode now contains the code-mode of the current chunk
-;; 3) Each chunk can now have its own mode-line to tell emacs what
-;; mode to use to edit it. The function `ess-noweb-in-mode-line'
-;; recognises such mode-lines, and the function
-;; `ess-noweb-set-this-code-mode' sets the code mode for the current
-;; chunk and adds a mode-line if necessary. If several chunks have
-;; the same name, the mode-line must appear in the first chunk with
-;; that name.
-;; 4) The mechanism for deciding whether to change mode was altered,
-;; since the old method assumed a single code mode. Now,
-;; `ess-noweb-last-chunk-index' keeps track of which chunk we were in
-;; last. If we have moved to a different chunk, we have to check
-;; which mode we should be in, and change if necessary.
-
-;; The keymap and menu-map handling was changed. Easymenu was used to
-;; define the menu, and it the keymap was attached to the 'official'
-;; minor-modes-keymaps list. This means that
-;; 1) It was automatically loaded when ess-noweb-mode was active and
-;; unloaded when it was inactive.
-;; 2) There was no need to worry about the major mode map clobbering
-;; it , since it takes precedence over the major mode
-;; map. `ess-noweb-setup-keymap' is therefore now superfluous
-;; The menu was also reorganised to make it less cluttered, so there
-;; would be room for adding tangling and weaving commands (one day).
-
-;; Mouse navigation (at least under Emacs (AJR)) is supported, in so
-;; far as clicking mouse-1 on the '<<' of a chunk name moves to the
-;; previous instance of that chunk name, and clicking in the '>>'
-;; moves to the next instance. They are not mouse-hightlighted,
-;; though: too much hassle for zero added functionality.
-
-;; ess-noweb-doc-mode has been given its own syntax-table. It is the same
-;; as the current doc-mode syntax-table, except that [[ is a comment
-;; start and ]] a comment end. Fixes some ugliness in LaTeX-mode if
-;; `$' or `%' appear in quoted code (or even `<<', which happens often
-;; in C++).
-;; (This should make ess-noweb-hide-code-quotes and
-;; ess-noweb-restore-code-quotes unnecessary, but I have not yet removed
-;; them, nor the calls to them).
-
-;; A new function `ess-noweb-indent-line' was defined and bound by default
-;; to the tab key. This should indent the current line correctly in
-;; whichever mode we are currently in. Previously, c-mode in
-;; particular did not behave well with indentation (although
-;; `ess-noweb-fill-chunk' worked fine). Indentation is only accurate
-;; within the chunk: it does not know the syntax at the end of the
-;; previous chunk, so it does not know where to start indenting in
-;; this chunk. However, provided the indentation within each chunk is correct,
-;; notangle will correctly indented code.
-
-;; (I think it would be good to separate filling and indenting,
-;; though, since `indent-region' and `fill-region' have completely
-;; different meanings in LaTeX-mode (and both are useful))
-
-;; ess-noweb-mode and ess-noweb-minor-mode were given an optional argument, so
-;; that (ess-noweb-mode -1) turns it off, (ess-noweb-mode 1) turns it on, and
-;; (ess-noweb-mode) toggles it. This is considered normal for minor modes.
-
-;; buffer-substring changed to buffer-substring-no-properties:
-;; comparisons with buffer-substring can be unreliable if highlighting
-;; is used.
-
-;; New functions `ess-noweb-in-code-chunk' & `ess-noweb-chunk-is-code' created
-;; to replace (if (stringp (car (ess-noweb-find-chunk)))) and
-;; (if (stringp (car (ess-noweb-chunk-vector-aref index)))).
-
-;; `ess-noweb-insert-mode-line' was renamed
-;; `ess-noweb-insert-default-mode-line' and modified to put the mode-line
-;; at the start of the file and remove any existing mode-line.
-
-;; a '<=' in `ess-noweb-find-chunk-index' changed to '<', so we get the
-;; right answer if point is on the first character in a chunk
-
-;; The name of `ess-noweb-post-command-hook' changed to
-;; `ess-noweb-post-command-function', since it is a function.
-
-;; All the highlighting code moved to a separate file:
-;; (ess-noweb-font-lock-mode.el)
-
-;; Menu driven tangling is in the process of being added. It can
-;; currently tangle a single chunk or a series of chunks with the
-;; same name (which I refer to as a thread) into a separate
-;; buffer. This buffer can then be saved to a file, sent to an
-;; interpreter, whatever. I haven't tested using line-numbers as yet.
-
-;;; ess-noweb-mode.el ends here
+++ /dev/null
-;;; ess-noweb.el --- support for Literate Data Analysis
-
-;; Copyright (C) 1999 Mark Lunt
-;; Copyright (C) 1999--2004 A.J. Rossini, Richard M. Heiberger, Martin
-;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
-
-;; Author: Mark Lunt <mark.luntNOSPAMmrc-bsu.cam.ac.uk>
-;; A.J. Rossini <rossiniNOSPAMu.washington.edu>
-;; Created: April 18, 1999
-;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
-
-;; Keywords: statistics, languages
-;; Summary: Noweb support for ESS
-
-;; 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:
-
-;; Code for ESS and Literate Data Analysis.
-
-;;; Code:
-
-\f ; Requires and autoloads
-
-(require 'ess-custom)
-(require 'ess-inf)
-(require 'ess-noweb-mode)
-
-\f ; Variables
-
-(defvar ess-noweb-use-font-lock font-lock-mode
- "Set to t if you want to use font-locking in ESS noweb buffers.")
-
-(if ess-noweb-use-font-lock
- (require 'ess-noweb-font-lock-mode))
-
-\f ; Functions
-
-;;*;; Code Chunk evaluation.
-
-(defun ess-noweb-create-tangle-buffer (name)
- (let ((buff (get-buffer-create name))
- (elca (eval ess-local-customize-alist)))
- (with-current-buffer buff
- (erase-buffer)
- (ess-setq-vars-local elca buff))
- buff))
-
-(defun ess-eval-chunk (vis)
- "Tangle the current chunk and send it to the inferior ESS process.
-Arg has same meaning as for `ess-eval-region'."
- (interactive "P")
- (let ((process-name ess-local-process-name)
- new-process-name
- (cbuf (current-buffer))
- (temp-buffer (ess-noweb-create-tangle-buffer "Tangle Buffer")))
- (save-excursion
- (ess-noweb-tangle-chunk temp-buffer)
- (set-buffer temp-buffer)
- ;; When the temp buffer is created, it does not inherit any value
- ;; of ess-local-process-name from the .Rnw buffer, so we have to set it
- ;; here. If ess-local-process-name is not set in the .Rnw buffer,
- ;; it will inherit the value that is chosen here.
- (set (make-local-variable 'ess-local-process-name) process-name)
- (ess-eval-region (point-min) (point-max) vis "Eval Chunk")
- (if process-name
- (kill-buffer temp-buffer)
- ;; if process-name was nil, source buffer did not have a local process
- ;; so keep value from temp buffer before killing it.
- (setq new-process-name ess-local-process-name)
- (kill-buffer temp-buffer)
- (set-buffer cbuf)
- (set (make-local-variable 'ess-local-process-name) new-process-name)))))
-
-
-(defun ess-eval-chunk-and-step (&optional vis)
- "Tangle the current chunk and send it to the inferior ESS process and
-step to the next chunk"
- (interactive)
- (ess-eval-chunk vis)
- (ess-noweb-next-code-chunk 1))
-
-(defun ess-eval-chunk-and-go (vis)
- "Tangle the current chunk, send to the ESS process, and go there.
-Arg has same meaning as for `ess-eval-region'."
- (interactive "P")
- (ess-eval-chunk vis)
- (ess-switch-to-ESS t))
-
-;;*;; Thread code chunk evaluation
-
-;;
-;; Threads are code chunks which fit into the same "buffer" (I'm (AJR)
-;; abusing terminology, but what I mean is things like:
-;; <<thing1>>=
-;; code for thing1
-;; @
-;; Documentation
-;; <<thing1>>=
-;; continuing code for thing1
-;; @
-;;
-
-(defun ess-eval-thread (vis)
- "Tangle all chunks in the current chunk-thread and send to the ESS process.
-Arg has same meaning as for `ess-eval-region'."
- (interactive "P")
- (let ((temp-buffer (ess-noweb-create-tangle-buffer "Tangle Buffer")))
- (ess-noweb-tangle-current-thread temp-buffer)
- (set-buffer temp-buffer)
- (ess-eval-region (point-min) (point-max) vis "Eval buffer")
- (kill-buffer temp-buffer)))
-
-(defun ess-eval-thread-and-go (vis)
- "Tangle all chunks in the current chunk-thread, send to ESS process,
-and go there. Arg has same meaning as for `ess-eval-region'."
- (interactive "P")
- (ess-eval-thread vis)
- (ess-switch-to-ESS t))
-
-\f ; Provide package
-
-(provide 'ess-noweb)
-
-;;; ess-noweb.el ends here
+++ /dev/null
-;;; ess-r-a.el -- Possible local customizations for R with ESS. -*- lexical-binding: t; -*-
-
-;; Copyright (C) 1997--2005 A.J. Rossini, Richard M. Heiberger, Martin
-;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
-
-;; Author: A.J. Rossini <blindglobeNOSPAMgmail.com>
-;; Created: 17 November 1999
-;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
-
-;; Keywords: languages
-
-;; 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:
-
-;; 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))
-
-
-\f ; Provide package
-
-(provide 'ess-r-a)
-
-;;; ess-r-a.el ends here
+++ /dev/null
-;;; ess-r-args.el --- Insert R function's arguments
-
-;; Copyright (C) 2007 Sven Hartenstein <mail at svenhartenstein dot de>
-;; Copyright (C) 2007 A.J. Rossini, Richard M. Heiberger, Martin
-;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
-
-;; 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
-;; http://www.r-project.org/Licenses/
-
-;; Last update: 2012-02-27
-
-;;; Commentary:
-
-;; == DOCUMENTATION ==
-
-;; This file provides some functions that show or insert a
-;; R-function's arguments (and their default values) by using R's
-;; args() function. This code requires ESS (http://ess.r-project.org).
-;; For screenshots as well as information on requirements,
-;; installation, configuration and troubleshooting, please visit
-;; http://www.svenhartenstein.de/emacs-ess.php
-
-;; == Requirements ==
-
-;; * ESS mode must be loaded and running.
-;; * A R process must be running within ESS.
-;; * For the tooltip option to work, Emacs must not run within a
-;; terminal but (directly) under the X window system (in case of
-;; GNU/Linux).
-
-;; == Installation ==
-
-;; To make Emacs aware of the functions defined in this file load it
-;; into Emacs by including something like the following in your
-;; ~/.emacs file (adapt "/PATH/TO"!).
-;;
-;; (add-hook 'ess-mode-hook (lambda () (load "/PATH/TO/ess-r-args.el")))
-;;
-;; This file is included with ESS; if you are reading this file as
-;; part of the ESS distribution, then you do not need to add the above
-;; line.
-
-;; == Configuration ==
-
-;; Configuration should be done by setting some variables in your
-;; ~/.emacs file, the following is an example only, adjust it to your
-;; needs.
-
-;; ;; ess-r-args-noargsmsg is printed, if no argument information
-;; ;; could be found. You could set it to an empty string ("") for no
-;; ;; message.
-;; (setq ess-r-args-noargsmsg "No args found.")
-;;
-;; ;; ess-r-args-show-as determines how (where) the information is
-;; ;; displayed. Set it to 'tooltip little tooltip windows or to
-;; ;; 'message (the default) which will use the echo area at the bottom of
-;; ;; your Emacs frame.
-;; (setq ess-r-args-show-as nil)
-;;
-;; ;; ess-r-args-show-prefix is a string that is printed in front of
-;; ;; the arguments list. The default is "ARGS: ".
-;; (setq ess-r-args-show-prefix "ARGS: ")
-
-;; == Usage ==
-
-;; The functions should be called when point (text cursor) is between
-;; two parentheses of a R function call (see screenshots above). It
-;; will then (invisibly) query R for which arguments the respective
-;; function knows as well as their default values and show or insert
-;; the result.
-
-;; There are currently two functions: ess-r-args-show echoes the
-;; arguments in the echo area or as tooltip, ess-r-args-insert prints
-;; the arguments at point.
-
-;; In order to not having to type the whole function name each time
-;; you want to see the arguments list, you most probably want to bind
-;; the functions to a key which again should be done in your ~/.emacs
-;; file. You can also let Emacs call the function each time you insert
-;; an opening parenthesis ("(").
-
-;; -----> do this below
-
-;; Again, the following is an example only:
-
-;; bind ess-r-args-show to F2
-;; (define-key ess-mode-map [f2] 'ess-r-args-show)
-
-;; bind ess-r-args-insert to F3
-;; (define-key ess-mode-map [f3] 'ess-r-args-insert)
-
-;; == Setting the tooltip position ==
-
-;; Unfortunately (?), tooltips are by default shown at the mouse
-;; pointer's position, which is not necessarily where you are looking
-;; at. If you use Emacs' mouse-avoidance-mode with option "banish"
-;; then the mouse pointer will automatically be put at the upper right
-;; corner of the Emacs window so that you know where to look for the
-;; tooltip. Emacs also allows for setting the tooltip position
-;; relative to the upper left corner of your screen. If you know how
-;; to let Emacs determine the point (text cursor) position in pixels
-;; from the upper left corner of the screen, please let me know. It
-;; would then be possible to show the tooltip near the point, which I
-;; would consider preferably.
-;; SJE: see code at bottom 2009-01-30...
-
-;; ;; Put mouse away when using keyboard
-;; (mouse-avoidance-mode 'banish)
-
-;; ;; Set the tooltip position in absolute pixels from the upper left
-;; ;; corner of the screen
-;; (setq tooltip-frame-parameters
-;; '((name . "tooltip")
-;; (left . 20)
-;; (top . 20)))
-
-;; == Changelog ==
-
-;; * 2007-04-03: The function should now do nothing (instead of
-;; irritating cursor movement) if the current ESS process is
-;; anything but R.
-;; * 2007-04-05: Function names changed. Much more modular. GPLed. New
-;; prefix configuration variable. Minor changes.
-;; * 2007-04-30: Error handling added. Bugfix: Emacs used to lock up
-;; when function was called within parentheses following the "#"
-;; character (Thanks to John Bullock for his bug report!).
-
-;; == Troubleshooting ==
-
-;; Before sending reports of problems, please check the following.
-
-;; * Doublecheck the requirements section above.
-;; * Please be sure you tried both the "tooltip" option and the "echo
-;; area" option and tell me whether both failed or just one.
-;; * Check whether it is a key binding problem. Run the function with
-;; M-x ess-r-args-show RET. If it works but not the key binding, try
-;; binding it to another key. Some window managers might not pass
-;; the function key keystrokes to Emacs.
-
-;; If you encounter problems, please send me detailed bug reports.
-;; Please also indicate the ESS version you are running and the Emacs
-;; type (GNU vs. X) and operating system. I will do my best to help
-;; but please be aware that I'm everything but an emacs lisp expert.
-
-;; == TODO ==
-
-;; These are things that I would like to see improved. Please let me
-;; know if you know how it could be done.
-
-;; * As mentioned above, I would like to place the tooltip near the
-;; point (text cursor) but I do not see how this could be done.
-;; * Both the message in the echo area and the tooltip automatically
-;; disappear as soon as a key is pressed. That is, you will need to
-;; call the function again if you have entered the first
-;; parameter(s) and wonder what additional parameters are possible.
-;; I would prefer the information to be shown, say, five seconds or
-;; so.
-
-;;; Code:
-
-(require 'ess-custom)
-(require 'ess-inf)
-(require 'ess-utils)
-(eval-when-compile
- (require 'tooltip)); for tooltip-show
-
-;; These defvars were previously defcustoms in ess-custom
-(defvar ess-r-args-noargsmsg "No args found."
- "Message returned if \\[ess-r-args-get] cannot find a list of arguments.")
-(make-obsolete-variable 'ess-r-args-noargsmsg "Use `eldoc-mode' instead." "ESS 18.10")
-
-(defvar ess-r-args-show-prefix "ARGS: "
- "A prefix string that is shown before the arguments list.")
-(make-obsolete-variable 'ess-r-args-show-prefix "Use `eldoc-mode' instead." "ESS 18.10")
-
-(defvar ess-r-args-show-as 'message
- "How ess-r-args-show should show the argument list. Possible values
-are: 'message' (the default) or 'tooltip'.")
-(make-obsolete-variable 'ess-r-args-show-as "Use `eldoc-mode' instead." "ESS 18.10")
-
-(defvar ess-r-args-keep-silent ess-S-non-functions
- "List of functions names which should *not* trigger \\[ess-r-args-show];
-Defaults to `ess-S-non-functions'.")
-(make-obsolete-variable 'ess-r-args-keep-silent "Use `eldoc-mode' instead." "ESS 18.10")
-
-(defvar ess-r-args-electric-paren nil
- "Non-nil means re-assign \"(\" to \\[ess-r-args-auto-show].")
-(make-obsolete-variable 'ess-r-args-electric-paren "Use `eldoc-mode' instead." "ESS 18.10")
-
-(defun ess-message (format-string &rest args)
- "Shortcut for \\[message] only if `ess-show-load-messages' is non-nil."
- (when (bound-and-true-p ess-show-load-messages)
- (message format-string args)))
-
-(defun ess-r-args-current-function ()
- "Returns the name of the R function assuming point is currently
-within the argument list or nil if no possible function name is
-found."
- (save-excursion
- (condition-case nil (up-list -1)
- (error (message "Can't find opening parenthesis.")))
- (let ((posend (point)))
- (backward-sexp 1)
- (let ((rfunname (buffer-substring-no-properties posend (point))))
- (if (posix-string-match "^[a-zA-Z0-9_\.]+$" rfunname)
- rfunname nil)))))
-(make-obsolete 'ess-r-args-current-function "See `eldoc-mode'" "ESS 18.10")
-
-(defun ess-r-args-get (&optional function trim)
- "Returns string of arguments and their default values of R
-function FUNCTION or nil if no possible function name
-found. Calls `ess-r-args-current-function' if no argument given.
-If TRIM is non-nill remove tabs and newlines and replace ' = '
-with '=' (useful for display in minibuffer to avoid window and
-buffer readjustments for multiline string)."
- (if (null function)
- (setq function (ess-r-args-current-function)))
- (when (and function
- (or ess-current-process-name
- (called-interactively-p 'any)))
- (ess-force-buffer-current "R process to use: ")
- ;; ^^^^^^^^^^^^^^^ has own error handler
- (mapconcat (lambda (arg) (concat (car arg) "=" (cdr arg)))
- (cadr (ess-function-arguments function))
- ", ")))
-
-(make-obsolete 'ess-r-args-get "See `eldoc-mode'" "ESS 18.10")
-
-;;;###autoload
-(defun ess-r-args-show (&optional function)
- "Show arguments and their default values of R function. Calls
-\\[ess-r-args-current-function] if called without argument."
- (interactive "*")
- (ess-message "(ess-r-args-show): start")
- (if (null function)
- (setq function (ess-r-args-current-function)))
- (ess-message ".... function='%s'" function)
- (when function
- (let* ((tt (equal ess-r-args-show-as 'tooltip))
- (args (concat ess-r-args-show-prefix
- (ess-r-args-get function (not tt)))))
- (ess-message "(ess-r-args-show): args='%s'" args)
- (when args
- (if (not tt)
- (message args)
- (require 'tooltip)
- ;; value of 30 in next call is just a guess,
- ;; should really be based
- ;; on something like pixel height of 1-2 vertical
- ;; lines of text
- (ess-tooltip-show-at-point args 0 30))
- ))))
-(make-obsolete 'ess-r-args-show "See `eldoc-mode'" "ESS 18.10")
-
-;;;###autoload
-(defun ess-r-args-auto-show ()
- "Typically assigned to \"(\": If there's an ess-process, automatically show arguments
-and their default values of an R function. Built on \\[ess-r-args-show]."
- (interactive)
- (insert "("); (skeleton-pair-insert-maybe nil)
- (if (and (not eldoc-mode)
- ess-local-process-name ; has a process and it must still be running
- (ess-get-process ess-local-process-name))
- (ess-r-args-show)))
-(make-obsolete 'ess-r-args-auto-show "See `eldoc-mode'" "ESS 18.10")
-
-;; MM: I would strongly discourage use of the following:
-;; it leads to clueless newbie-users who indeed
-;; explicitly call a function with all its default arguments;
-;; instead of only setting the required arguments
-(defun ess-r-args-insert (&optional function)
- "Insert arguments and their default values of function. Calls
-ess-r-args-current-function if no argument given."
- (interactive "*")
- (if (null function)
- (setq function (ess-r-args-current-function)))
- (if function
- (let ((args (ess-r-args-get function))
- (pointpos (point)))
- (insert args)
- (goto-char pointpos))))
-(make-obsolete 'ess-r-args-insert "See `eldoc-mode'" "ESS 18.10")
-
-
-;; (defvar ess-r-object-tooltip-alist
-;; '((numeric . "summary")
-;; (integer . "summary")
-;; (factor . "table")
-;; (lm . "summary")
-;; (other . "str"))
-;; "List of (<class> . <R-function>) to be used in \\[ess-r-object-tooltip].
-;; For example, when called while point is on a factor object, a table of that
-;; factor will be shown in the tooltip.
-;; The special key \"other\" in the alist defines which function to call when
-;; the class is not mached in the alist. The default, str(), is a fairly useful
-;; default for many, including data.frame and function objects.")
-
-;; From Erik Iversion, slightly modified,
-;; http://www.sigmafield.org/2009/10/01/r-object-tooltips-in-ess/
-;; (defun ess-r-object-tooltip ()
-;; "Get info for object at point, and display it in a tooltip."
-;; (interactive)
-;; (let ((proc (ess-get-process))
-;; (objname (current-word))
-;; (curbuf (current-buffer))
-;; (tmpbuf (get-buffer-create " *ess-r-object-tooltip*"))
-;; bs)
-;; (when objname
-;; (ess-write-to-dribble-buffer
-;; (format "ess-r-object-tooltip: objname='%s'\n" objname))
-;; (ess-command (concat "class(" objname ")\n") tmpbuf nil nil nil proc)
-;; (with-current-buffer tmpbuf
-;; (goto-char (point-min))
-;; ;; CARE: The following can only work in an English language locale!
-;; ;; .lang. <- Sys.getenv("LANGUAGE"); Sys.setenv(LANGUAGE="en")
-;; ;; .lc. <- Sys.getlocale("LC_MESSAGES"); Sys.setlocale("LC_MESSAGES","en_US.utf-8")
-;; ;; and *afterward* Sys.setenv(LANGUAGE=.lang.); Sys.setlocale("LC_MESSAGES", .lc.)
-;; ;; but that fails sometimes, e.g., on Windows
-;; (unless (re-search-forward "\(object .* not found\)\|unexpected" nil t)
-;; (re-search-forward "\"\\(.*\\)\"" nil t)
-;; (let* ((objcls (match-string 1))
-;; (myfun (or (cdr (assoc-string objcls ess-r-object-tooltip-alist))
-;; (cdr (assoc 'other ess-r-object-tooltip-alist)))))
-;; (ess-command (concat myfun "(" objname ")\n") tmpbuf nil nil nil proc))
-;; (setq bs (buffer-string)))))
-;; (if bs
-;; (ess-tooltip-show-at-point bs 0 30))))
-
-;; Erik: my default key map
-;;(define-key ess-mode-map "\C-c\C-g" 'ess-r-object-tooltip)
-
-;; On http://www.sigmafield.org/2009/10/01/r-object-tooltips-in-ess/
-;; in the comments, "Charlie" recommended
-
-;; (custom-set-faces
-;; '(tooltip ((t (:background "white" :foreground "blue" :foundry "fixed")))))
-
-
-
-(provide 'ess-r-args)
-
-;;; ess-r-args.el ends here
+++ /dev/null
-;;; ess-rutils.el --- Convenience features for package and object control. -*- lexical-binding: t; -*-
-
-;; Author: J. Alexander Branham
-;; Maintainer: ESS-Core
-;; Keywords: processes
-
-;; Copyright (c) 2019 Free Software Foundation
-;; Copyright (c) 2013-2019 ESS Core
-;; Copyright (c) 2005-2013 Sebastian P. Luque
-
-;; This program is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; This program is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-;;; History:
-
-;; This file was originally written by Sebastian Luque in 2004. It was
-;; completely rewritten in 2019 and then merged into ess-r-mode as
-;; part of contributing ESS to GNU Emacs.
-
-;;; Commentary:
-
-;; This file used to have support for listing packages and a few other
-;; misc functions. That is now in ess-r-mode. This file is provided
-;; only so that users who have (require 'ess-rutils) in their init
-;; files don't encounter errors when they update ESS.
-
-;;; Code:
-
-(provide 'ess-rutils)
-
-;;; ess-rutils.el ends here
+++ /dev/null
-;;; ess-swv.el --- Some simple functions for ESS and Sweave
-
-;; Copyright (C) 2005 David Whiting, A.J. Rossini, Richard M. Heiberger, Martin
-;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
-;; Copyright (C) 2006-2008 A.J. Rossini, Richard M. Heiberger, Martin Maechler,
-;; Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
-
-;; Author: David Whiting <david.whitingNOSPAMncl.ac.uk>
-;; Created: 15 April 2005
-;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
-
-;; Keywords: statistics, tools
-
-;; 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:
-
-;;
-;; Some simple functions for ESS and Sweave
-;; david.whiting at ncl.ac.uk
-;; Wed Sep 1 14:55:52 CEST 2004
-
-;; I have written some very simple elisp functions that I have found
-;; useful and thought others might like to see. I dabble with elisp
-;; occasionally at best so there are probably better ways to do what I
-;; have done, but so far this seems to work for me. There are several
-;; things that are hard-coded, I use Linux and I think that this would
-;; probably not work in Windows (not as it is now anyway).
-
-;; With these functions and key bindings all I need to do is open a .Rnw
-;; file and, assuming R is running, I press:
-
-;; M-n s to Sweave the file, then
-;; M-n l to run latex on the results of Sweave, then
-;; M-n p to make and display a postscript file , or
-;; M-n P to make and display a PDF version.
-
-;; David Whiting to Anthony Rossini, Mar 30
-;; On Wed, Mar 30, 2005 at 11:51:26AM +0200, A.J. Rossini wrote:
-;; > I'm going to go ahead and add this stuff to the distribution tonight
-;; > if you don't mind. I'd forgotten about it!
-;; It would make me very happy indeed.
-;; > (however, need permission to do so).
-;; Permission granted!
-
-;; Dave
-;; --
-;; David Whiting
-;; School of Clinical Medical Sciences, The Medical School
-;; University of Newcastle upon Tyne, NE2 4HH, UK.
-
-
-;;; TODO:
-;;;
-;;; 1. I want to be able to send ess-swv-latex a parameter to tell it
-;;; the number of times to run LaTeX (to get references updated
-;;; correctly).
-;;;
-;;; 2. Also need to add ess-swv-Bibtex.
-;;;
-;;; 3. Might be good to have a way to chain commands.
-;;;
-;;; 4. ADD to the ../doc/ess.texi !!
-
-
-;;; Code:
-
-;;; Autoloads and Requires
-
-(eval-when-compile
- (require 'ess-custom))
-
-(require 'ess-utils)
-(require 'ess-noweb-mode)
-(require 'ess-r-mode); for Rnw-mode
-(require 'easymenu)
-
-
-
-(defvar TeX-command-list)
-(defvar TeX-command-default)
-(defvar TeX-file-extensions)
-(declare-function TeX-normal-mode "tex")
-
-(defgroup ess-sweave nil
- "Mode for editing Sweave (*.[SR]nw) files."
- :group 'ess-S
- :prefix "ess-")
-
-(defcustom ess-pdf-viewer-pref nil
- "External pdf viewer you like to use from ESS.
-Can be a string giving a name of the program or a list with car
-giving heprogram and the tail giving the arguments. For example
-'(\"okular\" \"--unique\")."
- :type '(choice (const nil) (repeat :tag "Command with arguments" string) (string :tag "Command")))
-
-(defcustom ess-ps-viewer-pref nil
- "External PostScript viewer you like to use from ESS.
-If nil, ESS will try finding one from a list."
- :type '(choice (const nil) string))
-
-(defcustom ess-swv-pdflatex-commands '("texi2pdf" "pdflatex" "make")
- "Commands to run a version of pdflatex in \\[ess-swv-PDF];
-the first entry is the default command."
- :group 'ess-sweave
- :type '(repeat string))
-
-(defcustom ess-swv-plug-into-AUCTeX-p nil
- "Non-nil means add commands to AUCTeX's \\[TeX-command-list]
-to sweave the current noweb file and latex the result."
- :group 'ess-sweave
- :type '(choice (const :tag "Off" nil)
- (const :tag "On" t)))
-
-(defcustom ess-swv-processing-command ".ess_weave(%s, %s)"
- "Command used by `ess-swv-run-in-R'.
-
-First %s is literally replaced by the processing command (for
-example: Sweave) second %s is replaced with a string containing a
-processed file and possibly additional argument encoding (example:
-\"path/to/foo.Rnw\", encoding='utf-8')
-
-.ess_weave changes the working directory to that of the supplied
-file.
-
-If you want to simply call knitr or Sweave in global environment
-set this command to \"%s(%s)\"."
- :group 'ess-R
- :type 'string)
-
-;; currently use exactly for "Sweave", "Stangle", "knit", and "purl"
-(defun ess-swv-run-in-R (cmd &optional choose-process block)
- "Run \\[cmd] on the current .Rnw file. Utility function not called by user."
- (let* ((rnw-buf (current-buffer)))
- (if choose-process ;; previous behavior
- (ess-force-buffer-current "R process to load into: ")
- ;; else
- (update-ess-process-name-list)
- (cond ((= 0 (length ess-process-name-list))
- (message "no ESS processes running; starting R")
- (sit-for 1); so the user notices before the next msgs/prompt
- (run-ess-r)
- (set-buffer rnw-buf)
- )
- ((not (string= "R" (ess-make-buffer-current))); e.g. Splus, need R
- (ess-force-buffer-current "R process to load into: "))
- ))
-
- (save-excursion
- ;; (ess-execute (format "require(tools)")) ;; Make sure tools is loaded.
- (basic-save-buffer); do not Sweave/Stangle old version of file !
- (let* ((sprocess (ess-get-process ess-current-process-name))
- (sbuffer (process-buffer sprocess))
- (rnw-file (buffer-file-name))
- (Rnw-dir (file-name-directory rnw-file))
- (buf-coding (symbol-name buffer-file-coding-system))
- ;; could consider other encodings, but utf-8 is "R standard" for non-ASCII:
- (cmd-args (concat "\"" rnw-file "\""
- (if (string-match "^utf-8" buf-coding)
- ", encoding = \"utf-8\"")))
- (Sw-cmd
- (format ess-swv-processing-command cmd cmd-args)))
- (message "%s()ing %S" cmd rnw-file)
- ;; need to block when we are running ess-swv-weave-PDF so we
- ;; know when to start compiling the generated .tex file
- (if block
- (progn
- (ess-eval-linewise (concat Sw-cmd "\n") nil nil nil t)
- (message "Finished %s()ing %S" cmd rnw-file))
- (ess-execute Sw-cmd 'buffer nil nil)
- (pop-to-buffer-same-window rnw-buf)
- (display-buffer (buffer-name sbuffer)))))))
-
-(defcustom ess-swv-processor 'sweave
- "Processor to use for weaving and tangling.
-Currently 'sweave or 'knitr"
- :group 'ess-R
- :type '(choice (const sweave) (const knitr)))
-
-
-(defun ess-swv-tangle ()
- "Run Stangle/purl on the current .Rnw file.
-Depending on the `ess-swv-processor' used."
- (interactive)
- (ess-swv-run-in-R (cond ((eq ess-swv-processor 'sweave) "Stangle")
- ((eq ess-swv-processor 'knitr) "purl")
- (t (error "Not a valid processor %s" ess-swv-processor)))))
-
-(defun ess-swv-weave (&optional choose)
- "Run Sweave/knit on the current .Rnw file.
-Depending on the `ess-swv-processor' used.
-
-If CHOOSE is non-nil, offer a menu of available weavers.
-"
- (interactive "P")
- (let ((processor (if choose
- (ess-completing-read "Weaver" '("sweave" "knitr") nil t)
- (symbol-name ess-swv-processor))))
- (ess-swv-run-in-R (cond ((string= processor "sweave") "Sweave")
- ((string= processor "knitr") "knit")
- (t (error "Not a valid processor %s" processor))))))
-
-(defun ess-swv-sweave ()
- "Run Sweave on the current .Rnw file."
- (interactive)
- (ess-swv-run-in-R "Sweave"))
-
-(defun ess-swv-stangle ()
- "Run Stangle on the current .Rnw file."
- (interactive)
- (ess-swv-run-in-R "Stangle"))
-
-(defun ess-swv-knit ()
- "Run knit on the current .Rnw file."
- (interactive)
- (ess-swv-run-in-R "knit"))
-
-(defun ess-swv-purl ()
- "Run purl on the current .Rnw file."
- (interactive)
- (ess-swv-run-in-R "purl"))
-
-;; trying different viewers; thanks to an original patch for
-;; ess-swv.el from Leo <sdlNOSPAMweb.de> :
-(defun ess-get-ps-viewer ()
- "Get external PostScript viewer to be used from ESS.
-Use `ess-ps-viewer-pref' when that is executably found by \\[executable-find].
-Otherwise try a list of fixed known viewers."
- (file-name-nondirectory
- (or (and ess-ps-viewer-pref ; -> ./ess-custom.el
- (executable-find ess-ps-viewer-pref))
- (executable-find "gv")
- (executable-find "evince")
- (executable-find "kghostview"))))
-
-(defun ess-get-pdf-viewer ()
- "Get external PDF viewer to be used from ESS.
-Use `ess-pdf-viewer-pref' when that is executably found by \\[executable-find].
-Otherwise try a list of fixed known viewers."
- (let ((viewer (or ess-pdf-viewer-pref
- ;; (and (stringp ess-pdf-viewer-pref) ; -> ./ess-custom.el
- ;; (executable-find ess-pdf-viewer-pref))
- (executable-find "evince")
- (executable-find "kpdf")
- (executable-find "okular")
- (executable-find "xpdf")
- (executable-find "acroread")
- (executable-find "xdg-open")
- ;; this one is wrong, (ok for time being as it is used only in swv)
- (when (fboundp 'ess-get-words-from-vector)
- (car (ess-get-words-from-vector
- "getOption(\"pdfviewer\")\n"))))))
- (when (stringp viewer)
- (setq viewer (file-name-nondirectory viewer)))
- viewer))
-
-(defun ess-swv-weave-PDF (&optional choose)
- "Sweave/knit, compile TeX, and display PDF.
-Run Sweave or knit depending on `ess-swv-processor' used.
-
-If CHOOSE is non-nil, offer a menu of available weavers.
-"
- (interactive "P")
- (let ((processor (if choose
- (ess-completing-read "Weaver" '("sweave" "knitr") nil t)
- (symbol-name ess-swv-processor))))
- (ess-swv-run-in-R (cond ((string= processor "sweave") "Sweave")
- ((string= processor "knitr") "knit")
- (t (error "Not a valid processor %s" processor)))
- nil t)
- (ess-swv-PDF nil t)))
-
-
-(defun ess-swv-latex ()
- "Run LaTeX on the product of Sweave()ing the current file."
- (interactive)
- (save-excursion
- (let* ((namestem (file-name-sans-extension (buffer-file-name)))
- (latex-filename (concat namestem ".tex"))
- (tex-buf (get-buffer-create " *ESS-tex-output*")))
- (message "Running LaTeX on '%s' ..." latex-filename)
- (switch-to-buffer tex-buf)
- (call-process "latex" nil tex-buf 1 latex-filename)
- (switch-to-buffer (buffer-name))
- (display-buffer tex-buf)
- (message "Finished running LaTeX" ))))
-
-
-(defun ess-swv-PS ()
- "Create a postscript file from a dvi file (name based on the current
-Sweave file buffer name) and display it."
- (interactive)
- (let* ((buf (buffer-name))
- (namestem (file-name-sans-extension (buffer-file-name)))
- (dvi-filename (concat namestem ".dvi"))
- (psviewer (ess-get-ps-viewer)))
- (shell-command (concat "dvips -o temp.ps " dvi-filename))
- (shell-command (concat psviewer " temp.ps & "))
- (switch-to-buffer buf)
- ))
-
-(defun ess-swv-PDF (&optional pdflatex-cmd hide-compile-buffer)
- "From LaTeX file, create a PDF (via 'texi2pdf' or 'pdflatex', ...), by
-default using the first entry of `ess-swv-pdflatex-commands' and display it."
- (interactive)
- (setq pdflatex-cmd
- (or pdflatex-cmd
- (and (eq (length ess-swv-pdflatex-commands) 1)
- (car ess-swv-pdflatex-commands))
- (ess-completing-read "pdf latex command"
- ess-swv-pdflatex-commands ; <- collection to choose from
- nil 'confirm ; or 'confirm-after-completion
- nil nil (car ess-swv-pdflatex-commands))))
- (let* ((buf (buffer-name))
- (namestem (file-name-sans-extension (buffer-file-name)))
- (latex-filename (concat namestem ".tex"))
- (tex-buf (get-buffer-create "*ESS-tex-output*"))
- (pdfviewer (ess-get-pdf-viewer))
- (pdf-status)
- (cmdstr-win (format "start \"%s\" \"%s.pdf\"" pdfviewer namestem))
- (pdffile (format "%s.pdf" namestem))
- (cmd (if (stringp pdfviewer)
- (list pdfviewer pdffile)
- (append pdfviewer (list pdffile)))))
-
- ;;(shell-command (concat "pdflatex " latex-filename))
- (message "Running '%s' on '%s' ..." pdflatex-cmd latex-filename)
- (with-current-buffer tex-buf (erase-buffer))
- (setq pdf-status
- (call-process pdflatex-cmd nil tex-buf t
- (if (string= "texi2" (substring pdflatex-cmd 0 5))
- ;; workaround (bug?): texi2pdf or texi2dvi *fail* to work with full path:
- (file-name-nondirectory latex-filename)
- latex-filename)))
- (if (not (= 0 pdf-status))
- (progn (message "** OOPS: error in '%s' (%d)!" pdflatex-cmd pdf-status)
- (display-buffer tex-buf))
- ;; else: pdflatex probably ok
- ;; (set-process-sentinel proc 'shell-command-sentinel)
- (if (and (and ess-microsoft-p
- ;; Silence byte compiler warns about w32-fns
- (fboundp 'w32-shell-dos-semantics))
- (w32-shell-dos-semantics))
- (shell-command cmdstr-win)
- (message "%s" (mapconcat 'identity cmd " "))
- (apply 'start-process (car cmd) nil cmd))
- (unless hide-compile-buffer (display-buffer tex-buf))
- (message "%s finished with status %d" pdflatex-cmd pdf-status))))
-
-
-(defun ess-insert-Sexpr ()
- "Insert Sexpr{} into the buffer at point."
- (interactive)
- (insert "\\Sexpr{}")
- (backward-char))
-
-
-;;; back-compatible wrappers:
-(defun ess-makeSweave () "old *DEPRECATED* version of \\[ess-swv-weave]."
- (interactive) (ding)
- (message
- "** warning: ess-makeSweave is deprecated. Do use (ess-swv-weave) instead!")
- (ess-swv-weave))
-
-(defun ess-makeLatex () "old *DEPRECATED* version of \\[ess-swv-latex]."
- (interactive) (ding)
- (message
- "** warning: ess-makeLatex is deprecated. Do use (ess-swv-latex) instead!")
- (ess-swv-latex))
-
-(defun ess-makePS () "old *DEPRECATED* version of \\[ess-swv-PS]."
- (interactive) (ding)
- (message
- "** warning: ess-makePS is deprecated. Do use (ess-swv-PS) instead!")
- (ess-swv-PS))
-
-(defun ess-makePDF () "old *DEPRECATED* version of \\[ess-swv-PDF]."
- (interactive) (ding)
- (message
- "** warning: ess-makePDF is deprecated. Do use (ess-swv-PDF) instead!")
- (ess-swv-PDF))
-
-
-;; AUCTeX integration. This is independent of this library, but it fits
-;; here nonetheless since it's an alternative way of Sweave'ing without
-;; starting iESS.
-
-(defun ess-swv-add-TeX-commands ()
- "Add commands to AUCTeX's \\[TeX-command-list]."
- (unless (and (featurep 'tex-site) (featurep 'tex))
- (error "AUCTeX does not seem to be loaded"))
- (add-to-list 'TeX-command-list
- '("Sweave" "R CMD Sweave %t"
- TeX-run-command nil (latex-mode) :help
- "Run Sweave") t)
- (add-to-list 'TeX-command-list
- '("LaTeXSweave" "%l %(mode) %s"
- TeX-run-TeX nil (latex-mode) :help
- "Run LaTeX after Sweave") t)
- (setq TeX-command-default "Sweave")
- (mapc (lambda (suffix)
- (add-to-list 'TeX-file-extensions suffix))
- '("nw" "Snw" "Rnw")))
-
-(defun ess-swv-remove-TeX-commands (x)
- "Helper function: check if car of X is one of the Sweave strings"
- (let ((swv-cmds '("Sweave" "LaTeXSweave")))
- (unless (member (car x) swv-cmds) x)))
-
-(defun ess-swv-plug-into-AUCTeX ()
- "Add commands to AUCTeX's \\[TeX-command-list] to sweave the current noweb
-file and latex the result."
- (if ess-swv-plug-into-AUCTeX-p
- (add-hook 'Rnw-mode-hook 'ess-swv-add-TeX-commands)
- (remove-hook 'Rnw-mode-hook 'ess-swv-add-TeX-commands)
- (setq TeX-command-list (mapcar 'ess-swv-remove-TeX-commands TeX-command-list)
- ;; this will remove the items, leaving nils, so remove them.
- TeX-command-list (delq nil TeX-command-list))))
-;; as ess-swv-plug-into-AUCTeX-p is customizable ... :
-(if ess-swv-plug-into-AUCTeX-p
- (eval-after-load "tex" '(ess-swv-plug-into-AUCTeX)))
-
-(defun ess-swv-toggle-plug-into-AUCTeX ()
- "Toggle inclusion of commands to sweave noweb files and latex the results in
-\\[TeX-command-list] on and off. Commands are added via \\[Rnw-mode-hook]."
- (interactive)
- (unless (and (featurep 'tex-site) (featurep 'tex))
- (error "AUCTeX are not available"))
- (setq ess-swv-plug-into-AUCTeX-p (not ess-swv-plug-into-AUCTeX-p))
- (ess-swv-plug-into-AUCTeX)
- (TeX-normal-mode t)
- (if ess-swv-plug-into-AUCTeX-p
- (message "Sweave and LaTeXSweave are activated in AUCTeX.")
- (message "Sweave and LaTeXSweave are de-activated in AUCTeX.")))
-
-
-;;; Now bind some keys.
-(define-key ess-noweb-minor-mode-map "\M-ns" 'ess-swv-sweave)
-(define-key ess-noweb-minor-mode-map "\M-nT" 'ess-swv-tangle)
-(define-key ess-noweb-minor-mode-map "\M-nl" 'ess-swv-latex)
-(define-key ess-noweb-minor-mode-map "\M-np" 'ess-swv-PS)
-(define-key ess-noweb-minor-mode-map "\M-nP" 'ess-swv-PDF)
-(define-key ess-noweb-minor-mode-map "\M-nr" 'ess-swv-knit)
-(define-key ess-noweb-minor-mode-map "\M-nu" 'ess-swv-purl)
-(define-key ess-noweb-minor-mode-map "\M-nv" 'ess-swv-weave-PDF)
-(define-key ess-noweb-minor-mode-map "\M-nw" 'ess-swv-weave); depends on proc.
-
-(define-key ess-noweb-minor-mode-map "\M-nx" 'ess-insert-Sexpr)
-
-;; AND add these to the noweb menu we have anyway ! :
-(easy-menu-define ess-swv-menu
- ess-noweb-minor-mode-menu
- "Submenu for use in `Rnw-mode'."
-
- '("Sweaving, Tangling, ..."
- ["Sweave" ess-swv-sweave t]
- ["Tangle" ess-swv-tangle t]
- ["LaTeX" ess-swv-latex t]
- ["PDF(LaTeX)" ess-swv-PDF t]
- ["PS (dvips)" ess-swv-PS t]
- ["Knit" ess-swv-knit t]
- ["Purl" ess-swv-purl t]
- ["View PDF" ess-swv-weave-PDF t]
- ["Weave (Sweave/Knit)" ess-swv-weave t]
- ["Insert Sexpr" ess-insert-Sexpr t]
- ["AUCTeX Interface" ess-swv-toggle-plug-into-AUCTeX
- :style toggle :selected ess-swv-plug-into-AUCTeX-p]
- ))
-
-(easy-menu-add-item ess-noweb-minor-mode-menu
- nil ;; <= path
- ess-swv-menu)
-
-\f ; provides
-
-(provide 'ess-swv)
-
-;;; ess-swv.el ends here
+++ /dev/null
-;;; mouseme.el --- mouse menu with commands that operate on strings
-
-;; Copyright (C) 1997 by Free Software Foundation, Inc.
-
-;; Author: Howard Melman <howardNOSPAMsilverstream.com>
-;; Keywords: mouse, menu
-
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
-;; any later version.
-
-;; GNU Emacs is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;; GNU General Public License for more details.
-
-;; A copy of the GNU General Public License is available at
-;; https://www.r-project.org/Licenses/
-
-;;; 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)
- :group 'mouseme)
-
-(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)
- :group 'mouseme)
-
-(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)
- :group 'mouseme)
-
-(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:
-;; <URL:http://foo.bar.com/sss/ss.html>
-;; <http://foo.bar.com/sss/ss.html>
-;; http://foo.bar.com/sss/ss.html
-;; http://www.ditherdog.com/howard/
-;; mailto:howardNOSPAMsilverstream.com
-;; howardNOSPAMsilverstream.com
-;; <howardNOSPAMsilverstream.com>
-;; import com.sssw.srv.agents.AgentsRsrc;
-;; public AgoHttpRequestEvent(Object o, String db, Request r)
-;; <DIV><A href=3D"http://www.amazon.com/exec/obidos/ASIN/156592391X"><IMG =
-;; <A HREF="http://www.suntimes.com/ebert/ebert.html">
-;; 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 p)
- (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))
- beg end)
- (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 begining 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)))
- (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
+++ /dev/null
-;;; msdos.el --- Run an MS-DOS shell in an NTemacs buffer with bash as the shell
-
-;; Copyright (C) 1999 Richard M. Heiberger <rmhNOSPAMtemple.edu>
-;; Copyright (C) 2000--2004 A.J. Rossini, Richard M. Heiberger, Martin
-;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
-
-;; Author: Richard M. Heiberger <rmhNOSPAMtemple.edu>
-;; Created: February 1999
-;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
-
-;; Keywords: processes
-
-;; 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
-;; http://www.r-project.org/Licenses/
-
-;;; 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.
-
-;; I've listed it as part of ESS (emacs speaks statistics) for now. I
-;; will be happy to sign it over to FSF and have it become part of the
-;; standard distribution for windows machines.
-
-;;; 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
+++ /dev/null
-This is onews.info, produced by makeinfo version 6.5 from onews.texi.
-
-Changes 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 <https://github.com/emacs-ess/ESS/pull/65>
- * 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 softare, 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 sugested 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
- 'inferor-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 documention
- 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;
- <https://ess.r-project.org/Manual/ess.html>
- * 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 agressive.
- * 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.VehtariNOSPAMhut.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:brendanNOSPAMessex.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:brahmNOSPAMalum.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.
-
-
-\1f
-Tag Table:
-\1f
-End Tag Table
+++ /dev/null
-This is readme.info, produced by makeinfo version 6.5 from readme.texi.
-
-\1f
-File: readme.info, Node: General Information
-
-1 General Information: README
-*****************************
-
-This is the README file for the distribution of ESS version
-18.10.3snapshot
-
- 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
-(<rossiniNOSPAMblindglobe.net>) did the initial port to XEmacs and has been
-the primary coder. Martin Maechler (<maechlerNOSPAMstat.math.ethz.ch>) and
-Kurt Hornik (<Kurt.HornikNOSPAMR-project.org>) have assisted with the S
-family and XLispStat. Stephen Eglen (<stephenNOSPAMgnu.org>) has worked
-mostly on R support. Richard M. Heiberger (<rmhNOSPAMtemple.edu>) has
-assisted with S/S-PLUS development for Windows. Richard and Rodney A.
-Sparapani (<rsparapaNOSPAMmcw.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).
-
-* Menu:
-
-* License::
-* Installation::
-* Starting up::
-* Current Features::
-* New Features::
-* Reporting Bugs::
-* Mailing Lists::
-* Authors::
-
-\1f
-File: readme.info, Node: License, Next: Installation, Prev: General Information, Up: General Information
-
-1.1 License
-===========
-
-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.
-
-\1f
-File: readme.info, Node: Installation, Next: Starting up, Prev: License, Up: General Information
-
-1.2 Installation
-================
-
-ESS 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.
-
- 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 *note Activating and Loading ESS:: for more details.
-
-* Menu:
-
-* Installing from a third-party repository::
-* Installing from source::
-* Activating and Loading ESS::
-* Check Installation::
-
-\1f
-File: readme.info, Node: Installing from a third-party repository, Next: Installing from source
-
-1.3 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 MELPA's website (https://melpa.org/).
-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 *note Activating and Loading ESS::.
-Depending on install method, this may be taken care of automatically.
-
-\1f
-File: readme.info, Node: Installing from source, Next: Activating and Loading ESS, Prev: Installing from a third-party repository
-
-1.4 Installing from source
-==========================
-
-Stable versions of ESS are available at the ESS web page
-(https://ess.r-project.org) as a .tgz file or .zip file. ESS releases
-are GPG-signed, you should check the signature by downloading the
-accompanying '.sig' file and doing:
-
- gpg --verify ess-18.10.tgz.sig
-
- Alternatively, you may download the git repository. ESS is currently
-hosted on GitHub: <https://github.com/emacs-ess/ESS>. 'git clone
-https://github.com/emacs-ess/ESS.git' will download it to a new
-directory 'ESS' in the current working directory.
-
- We will refer to the location of the ESS source files as
-'/path/to/ESS/' hereafter.
-
- After installing, users should make sure they activate or load ESS in
-each Emacs session, see *note Activating and Loading ESS::
-
- Optionally, compile elisp files, build the documentation, and the
-autoloads:
- cd /path/to/ESS/
- make
- 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 'make install'. You might need
-administrative privileges:
-
- make install
-
- The files are installed into '/usr/share/emacs' directory. For this
-step to run correctly on macOS, you will need to adjust the 'PREFIX'
-path in 'Makeconf'. The necessary code and instructions are commented
-in that file.
-
-\1f
-File: readme.info, Node: Activating and Loading ESS, Next: Check Installation, Prev: Installing from source
-
-1.5 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 *note Check Installation::
-
- Otherwise, you may need to add the path to ESS to 'load-path' with:
-
- (add-to-list 'load-path "/path/to/ESS/lisp")
-
- 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 'make'):
-
- (load "ess-autoloads")
-
- To require ESS on startup, you can either put
-
- (require 'ess-site)
-
- or
-
- (require 'ess-r-mode)
-
- In your configuration file, depending on whether you want all ESS
-features or only R related features.
-
-\1f
-File: readme.info, Node: Check Installation, Prev: Activating and Loading ESS
-
-1.6 Check Installation
-======================
-
-Restart Emacs and check that ESS was loaded from a correct location with
-'M-x ess-version'.
-
-\1f
-File: readme.info, Node: Starting up, Next: Current Features, Prev: Installation, Up: General Information
-
-1.7 Starting an ESS process
-===========================
-
-To start an S session on Unix or on Windows when you use the Cygwin bash
-shell, simply type 'M-x S RET'.
-
- To start an S session on Windows when you use the MSDOS prompt shell,
-simply type 'M-x S+6-msdos RET'.
-
-\1f
-File: readme.info, Node: Current Features, Next: New Features, Prev: Starting up, Up: General Information
-
-1.8 Current Features
-====================
-
- * Languages Supported:
- * S family (R, S, and S+ AKA S-PLUS)
- * SAS
- * BUGS/JAGS
- * Stata
- * Julia
- * Editing source code (S family, SAS, BUGS/JAGS, Stata, Julia)
- * Syntactic indentation and highlighting of source code
- * Partial evaluation of code
- * Loading and error-checking of code
- * Source code revision maintenance
- * Batch execution (SAS, BUGS/JAGS)
- * Use of imenu to provide links to appropriate functions
- * Interacting with the process (S family, SAS, Stata, Julia)
- * Command-line editing
- * Searchable Command history
- * Command-line completion of S family object names and file
- names
- * Quick access to object lists and search lists
- * Transcript recording
- * Interface to the help system
- * Transcript manipulation (S family, Stata)
- * Recording and saving transcript files
- * Manipulating and editing saved transcripts
- * Re-evaluating commands from transcript files
- * Interaction with Help Pages and other Documentation (R)
- * Fast Navigation
- * Sending Examples to running ESS process.
- * Fast Transfer to Further Help Pages
- * Help File Editing (R)
- * Syntactic indentation and highlighting of source code.
- * Sending Examples to running ESS process.
- * Previewing
-
-\1f
-File: readme.info, Node: New Features, Next: Reporting Bugs, Prev: Current Features, Up: General Information
-
-1.9 New Features
-================
-
-Changes and New Features in 19.04 (unreleased):
-
- * 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
- <language>-mode-hook and <language>-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. See
- *Note (ess)Controlling buffer display:: for more information and
- examples.
-
- * '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.
-
- * 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.
-
- 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 <https://github.com/polymode/poly-R/>,
- <https://polymode.github.io/>, or markdown-mode with edit-indirect
- <https://jblevins.org/projects/markdown-mode>.
-
- * 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" <ess-config-here>)' 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. *Note (ess)Activating and Loading ESS:: for more
- information on this feature.
-
- * 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
-
-\1f
-File: readme.info, Node: Reporting Bugs, Next: Mailing Lists, Prev: New Features, Up: General Information
-
-1.10 Reporting Bugs
-===================
-
-Please send bug reports, suggestions etc. to <ESS-bugsNOSPAMr-project.org>,
-or post them on our github issue tracker
-(https://github.com/emacs-ess/ESS/issues)
-
- The easiest way to do this is within Emacs by typing
-
- '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.
-
-\1f
-File: readme.info, Node: Mailing Lists, Next: Authors, Prev: Reporting Bugs, Up: General Information
-
-1.11 Mailing Lists
-==================
-
-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 <ess-help-requestNOSPAMr-project.org>; contributions
-to the list may be mailed to <ess-helpNOSPAMr-project.org>. Rest assured,
-this is a fairly low-volume mailing list.
-
- The purposes of the mailing list include
-
- * helping users of ESS to get along with it.
- * discussing aspects of using ESS.
- * suggestions for improvements.
- * announcements of new releases of ESS.
- * posting small patches to ESS.
-
-\1f
-File: readme.info, Node: Authors, Prev: Mailing Lists, Up: General Information
-
-1.12 Authors
-============
-
- * A.J. Rossini (mailto:blindglobeNOSPAMgmail.com)
- * Richard M. Heiberger (mailto:rmhNOSPAMtemple.edu)
- * Kurt Hornik (mailto:Kurt.HornikNOSPAMR-project.org)
- * Martin Maechler (mailto:maechlerNOSPAMstat.math.ethz.ch)
- * Rodney A. Sparapani (mailto:rsparapaNOSPAMmcw.edu)
- * Stephen Eglen (mailto:stephenNOSPAMgnu.org)
- * Sebastian P. Luque (mailto:spluqueNOSPAMgmail.com)
- * Henning Redestig (mailto:henning.redNOSPAMgooglemail.com)
- * Vitalie Spinu (mailto:spinuvitNOSPAMgmail.com)
- * Lionel Henry (mailto:lionel.hryNOSPAMgmail.com)
- * J. Alexander Branham (mailto:alex.branhamNOSPAMgmail.com)
-
-
-\1f
-Tag Table:
-Node: General Information\7f73
-Node: License\7f1711
-Node: Installation\7f2381
-Node: Installing from a third-party repository\7f3298
-Node: Installing from source\7f4248
-Node: Activating and Loading ESS\7f5843
-Node: Check Installation\7f6920
-Node: Starting up\7f7143
-Node: Current Features\7f7526
-Node: New Features\7f9076
-Node: Reporting Bugs\7f28610
-Node: Mailing Lists\7f29508
-Node: Authors\7f30224
-\1f
-End Tag Table
+++ /dev/null
-This is requires.info, produced by makeinfo version 6.5 from
-requires.texi.
-
-ESS 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.
-
-\1f
-Tag Table:
-\1f
-End Tag Table
--- /dev/null
+This is the file .../info/dir, which contains the
+topmost node of the Info hierarchy, called (dir)Top.
+The first time you invoke Info you start off looking at this node.
+\1f
+File: dir, Node: Top This is the top of the INFO tree
+
+ This (the Directory node) gives a menu of major topics.
+ Typing "q" exits, "H" lists all Info commands, "d" returns here,
+ "h" gives a primer for first-timers,
+ "mEmacs<Return>" visits the Emacs manual, etc.
+
+ In Emacs, you can click mouse button 2 on a menu item or cross reference
+ to select it.
+
+* Menu:
+
+Emacs
+* ESS: (ess). Emacs Speaks Statistics (R/S/S+, SAS,
+ BUGS/JAGS and Stata).
--- /dev/null
+;;; ess-autoloads.el --- automatically extracted autoloads -*- lexical-binding: t -*-
+;;
+;;; Code:
+
+(add-to-list 'load-path (directory-file-name
+ (or (file-name-directory #$) (car load-path))))
+
+\f
+;;;### (autoloads nil "ess" "ess.el" (0 0 0 0))
+;;; Generated autoloads from ess.el
+
+(autoload 'ess-version "ess" "\
+Return a string with ESS version information." t nil)
+
+(autoload 'ess-submit-bug-report "ess" "\
+Submit a bug report to the ESS maintainers." t nil)
+
+(register-definition-prefixes "ess" '("ess"))
+
+;;;***
+\f
+;;;### (autoloads nil "ess-bugs-d" "ess-bugs-d.el" (0 0 0 0))
+;;; Generated autoloads from ess-bugs-d.el
+
+(autoload 'ess-bugs-mode "ess-bugs-d" "\
+Major mode for BUGS.
+
+\(fn)" t nil)
+
+(add-to-list 'auto-mode-alist '("\\.[Bb][Uu][Gg]\\'" . ess-bugs-mode))
+
+(add-to-list 'auto-mode-alist '("\\.[Bb][Oo][Gg]\\'" . ess-bugs-mode))
+
+(add-to-list 'auto-mode-alist '("\\.[Bb][Mm][Dd]\\'" . ess-bugs-mode))
+
+(register-definition-prefixes "ess-bugs-d" '("ess-"))
+
+;;;***
+\f
+;;;### (autoloads nil "ess-bugs-l" "ess-bugs-l.el" (0 0 0 0))
+;;; Generated autoloads from ess-bugs-l.el
+
+(register-definition-prefixes "ess-bugs-l" '("ess-bugs-"))
+
+;;;***
+\f
+;;;### (autoloads nil "ess-custom" "ess-custom.el" (0 0 0 0))
+;;; Generated autoloads from ess-custom.el
+
+(defvar ess-lisp-directory (file-name-directory (or load-file-name buffer-file-name)) "\
+Directory containing ess-site.el(c) and other ESS Lisp files.")
+
+(custom-autoload 'ess-lisp-directory "ess-custom" t)
+
+(add-to-list 'load-path (directory-file-name ess-lisp-directory))
+
+(add-to-list 'load-path (directory-file-name (expand-file-name "obsolete" ess-lisp-directory)))
+
+(put 'ess-indent-offset 'safe-local-variable #'numberp)
+
+(put 'ess-style 'safe-local-variable #'symbolp)
+
+(register-definition-prefixes "ess-custom" '("R-" "S+" "S-" "comint-highlight-prompt" "ess-" "inferior-"))
+
+;;;***
+\f
+;;;### (autoloads nil "ess-gretl" "ess-gretl.el" (0 0 0 0))
+;;; Generated autoloads from ess-gretl.el
+
+(autoload 'ess-gretl-mode "ess-gretl" "\
+Major mode for editing gretl source. See `ess-mode' for more help.
+
+\(fn)" t nil)
+
+(autoload 'gretl "ess-gretl" "\
+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'.
+
+\(fn &optional START-ARGS)" t nil)
+
+(register-definition-prefixes "ess-gretl" '("ess-gretl-" "gretl-" "inferior-gretl-args"))
+
+;;;***
+\f
+;;;### (autoloads nil "ess-help" "ess-help.el" (0 0 0 0))
+;;; Generated autoloads from ess-help.el
+
+(register-definition-prefixes "ess-help" '("ess-"))
+
+;;;***
+\f
+;;;### (autoloads nil "ess-inf" "ess-inf.el" (0 0 0 0))
+;;; Generated autoloads from ess-inf.el
+
+(autoload 'ess-load-file "ess-inf" "\
+Load FILENAME into an inferior ESS process.
+This handles Tramp when working on a remote.
+
+\(fn &optional FILENAME)" t nil)
+
+(register-definition-prefixes "ess-inf" '("ess-" "inferior-ess" "update-ess-process-name-list"))
+
+;;;***
+\f
+;;;### (autoloads nil "ess-jags-d" "ess-jags-d.el" (0 0 0 0))
+;;; Generated autoloads from ess-jags-d.el
+
+(autoload 'ess-jags-mode "ess-jags-d" "\
+Major mode for JAGS.
+
+\(fn)" t nil)
+
+(add-to-list 'auto-mode-alist '("\\.[Jj][Aa][Gg]\\'" . ess-jags-mode))
+
+(register-definition-prefixes "ess-jags-d" '("ess-jags-"))
+
+;;;***
+\f
+;;;### (autoloads nil "ess-julia" "ess-julia.el" (0 0 0 0))
+;;; Generated autoloads from ess-julia.el
+
+(autoload 'ess-julia-mode "ess-julia" "\
+Major mode for julia files.
+
+\(fn)" t nil)
+
+(autoload 'run-ess-julia "ess-julia" "\
+Start an inferior julia process.
+Optional prefix START-ARGS (\\[universal-argument]) allows to set
+command line arguments, such as --load=<file>. 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'.
+
+\(fn &optional START-ARGS)" t nil)
+
+(defalias 'julia #'run-ess-julia)
+
+(register-definition-prefixes "ess-julia" '("ac-source-ess-julia-objects" "company-ess-julia-objects" "ess-" "inferior-"))
+
+;;;***
+\f
+;;;### (autoloads nil "ess-mode" "ess-mode.el" (0 0 0 0))
+;;; Generated autoloads from ess-mode.el
+
+(autoload 'ess-mode "ess-mode" "\
+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.
+
+\(fn)" t nil)
+
+(register-definition-prefixes "ess-mode" '("ess-"))
+
+;;;***
+\f
+;;;### (autoloads nil "ess-r-completion" "ess-r-completion.el" (0
+;;;;;; 0 0 0))
+;;; Generated autoloads from ess-r-completion.el
+
+(register-definition-prefixes "ess-r-completion" '("ac-source-R" "company-R-" "ess-"))
+
+;;;***
+\f
+;;;### (autoloads nil "ess-r-flymake" "ess-r-flymake.el" (0 0 0 0))
+;;; Generated autoloads from ess-r-flymake.el
+
+(register-definition-prefixes "ess-r-flymake" '("ess-r-"))
+
+;;;***
+\f
+;;;### (autoloads nil "ess-r-mode" "ess-r-mode.el" (0 0 0 0))
+;;; Generated autoloads from ess-r-mode.el
+
+(autoload 'run-ess-r "ess-r-mode" "\
+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.
+
+\(fn &optional START-ARGS)" t nil)
+
+(autoload 'R "ess-r-mode" "\
+
+
+\(fn &optional START-ARGS)" t nil)
+
+(autoload 'ess-r-mode "ess-r-mode" "\
+Major mode for editing R source. See `ess-mode' for more help.
+
+\(fn)" t nil)
+
+(defalias 'R-mode #'ess-r-mode)
+
+(defalias 'r-mode #'ess-r-mode)
+
+(add-to-list 'auto-mode-alist '("/R/.*\\.q\\'" . ess-r-mode))
+
+(add-to-list 'auto-mode-alist '("\\.[rR]\\'" . ess-r-mode))
+
+(add-to-list 'auto-mode-alist '("\\.[rR]profile\\'" . ess-r-mode))
+
+(add-to-list 'auto-mode-alist '("NAMESPACE\\'" . ess-r-mode))
+
+(add-to-list 'auto-mode-alist '("CITATION\\'" . ess-r-mode))
+
+(autoload 'ess-r-transcript-mode "ess-r-mode" "\
+A Major mode for R transcript files.
+
+\(fn)" t nil)
+
+(add-to-list 'auto-mode-alist '("\\.[Rr]out\\'" . ess-r-transcript-mode))
+
+(add-to-list 'interpreter-mode-alist '("Rscript" . ess-r-mode))
+
+(add-to-list 'interpreter-mode-alist '("r" . ess-r-mode))
+
+(add-to-list 'auto-mode-alist '("/Makevars\\(\\.win\\)?\\'" . makefile-mode))
+
+(add-to-list 'auto-mode-alist '("DESCRIPTION\\'" . conf-colon-mode))
+
+(register-definition-prefixes "ess-r-mode" '("R-" "ess-" "inferior-ess-r-" "r-transcript-mode" "run-ess-r-newest"))
+
+;;;***
+\f
+;;;### (autoloads nil "ess-r-package" "ess-r-package.el" (0 0 0 0))
+;;; Generated autoloads from ess-r-package.el
+
+(register-definition-prefixes "ess-r-package" '("ess-"))
+
+;;;***
+\f
+;;;### (autoloads nil "ess-r-syntax" "ess-r-syntax.el" (0 0 0 0))
+;;; Generated autoloads from ess-r-syntax.el
+
+(register-definition-prefixes "ess-r-syntax" '("ess-"))
+
+;;;***
+\f
+;;;### (autoloads nil "ess-r-xref" "ess-r-xref.el" (0 0 0 0))
+;;; Generated autoloads from ess-r-xref.el
+
+(register-definition-prefixes "ess-r-xref" '("ess-r-xref-"))
+
+;;;***
+\f
+;;;### (autoloads nil "ess-rd" "ess-rd.el" (0 0 0 0))
+;;; Generated autoloads from ess-rd.el
+
+(autoload 'Rd-mode "ess-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)
+
+\(fn)" t nil)
+
+(add-to-list 'auto-mode-alist '("\\.Rd\\'" . Rd-mode))
+
+(register-definition-prefixes "ess-rd" '("Rd-"))
+
+;;;***
+\f
+;;;### (autoloads nil "ess-rdired" "ess-rdired.el" (0 0 0 0))
+;;; Generated autoloads from ess-rdired.el
+
+(autoload 'ess-rdired "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." t nil)
+
+(register-definition-prefixes "ess-rdired" '("ess-rdired-"))
+
+;;;***
+\f
+;;;### (autoloads nil "ess-roxy" "ess-roxy.el" (0 0 0 0))
+;;; Generated autoloads from ess-roxy.el
+
+(autoload 'ess-roxy-mode "ess-roxy" "\
+Minor mode for editing ROxygen documentation.
+
+This is a minor mode. If called interactively, toggle the
+`Ess-Roxy mode' mode. If the prefix argument is positive, enable
+the mode, and if it is zero or negative, disable the mode.
+
+If called from Lisp, toggle the mode if ARG is `toggle'. Enable
+the mode if ARG is nil, omitted, or is a positive number.
+Disable the mode if ARG is a negative number.
+
+To check whether the minor mode is enabled in the current buffer,
+evaluate `ess-roxy-mode'.
+
+The mode's hook is called both when the mode is enabled and when
+it is disabled.
+
+\(fn &optional ARG)" t nil)
+
+(register-definition-prefixes "ess-roxy" '("ess-"))
+
+;;;***
+\f
+;;;### (autoloads nil "ess-s-lang" "ess-s-lang.el" (0 0 0 0))
+;;; Generated autoloads from ess-s-lang.el
+
+(add-to-list 'auto-mode-alist '("\\.[Ss]t\\'" . S-transcript-mode))
+
+(add-to-list 'auto-mode-alist '("\\.Sout\\'" . S-transcript-mode))
+
+(register-definition-prefixes "ess-s-lang" '("S+common-cust-alist" "S-" "ess-" "inferior-S-language-start"))
+
+;;;***
+\f
+;;;### (autoloads nil "ess-sas-a" "ess-sas-a.el" (0 0 0 0))
+;;; Generated autoloads from ess-sas-a.el
+
+(register-definition-prefixes "ess-sas-a" '("ess-" "sas-program"))
+
+;;;***
+\f
+;;;### (autoloads nil "ess-sas-d" "ess-sas-d.el" (0 0 0 0))
+;;; Generated autoloads from ess-sas-d.el
+
+(autoload 'SAS-mode "ess-sas-d" "\
+Major mode for editing SAS source. See `ess-mode' for more help.
+
+\(fn)" t nil)
+
+(add-to-list 'auto-mode-alist '("\\.[Ss][Aa][Ss]\\'" . SAS-mode))
+
+(register-definition-prefixes "ess-sas-d" '("SAS" "ess-" "inferior-SAS-args"))
+
+;;;***
+\f
+;;;### (autoloads nil "ess-sas-l" "ess-sas-l.el" (0 0 0 0))
+;;; Generated autoloads from ess-sas-l.el
+
+(register-definition-prefixes "ess-sas-l" '("SAS-" "backward-page-top-of-window" "beginning-of-sas-" "ess-" "fix-page-breaks" "forward-page-top-of-window" "indent-sas-statement" "next-sas-proc" "sas-" "set-sas-file-" "submit-sas" "switch-to-"))
+
+;;;***
+\f
+;;;### (autoloads nil "ess-sp6-d" "ess-sp6-d.el" (0 0 0 0))
+;;; Generated autoloads from ess-sp6-d.el
+
+(autoload 'S+-mode "ess-sp6-d" "\
+Major mode for editing S+ source. See `ess-mode' for more help.
+
+\(fn &optional PROC-NAME)" t nil)
+
+(register-definition-prefixes "ess-sp6-d" '("S+" "ess-"))
+
+;;;***
+\f
+;;;### (autoloads nil "ess-toolbar" "ess-toolbar.el" (0 0 0 0))
+;;; Generated autoloads from ess-toolbar.el
+
+(register-definition-prefixes "ess-toolbar" '("ess-"))
+
+;;;***
+\f
+;;;### (autoloads nil "ess-tracebug" "ess-tracebug.el" (0 0 0 0))
+;;; Generated autoloads from ess-tracebug.el
+
+(register-definition-prefixes "ess-tracebug" '("ess-" "inferior-ess-" "org-"))
+
+;;;***
+\f
+;;;### (autoloads nil "ess-trns" "ess-trns.el" (0 0 0 0))
+;;; Generated autoloads from ess-trns.el
+
+(autoload 'ess-transcript-mode "ess-trns" "\
+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.
+
+\(fn)" t nil)
+
+(register-definition-prefixes "ess-trns" '("ess-transcript-"))
+
+;;;***
+\f
+;;;### (autoloads nil "ess-utils" "ess-utils.el" (0 0 0 0))
+;;; Generated autoloads from ess-utils.el
+
+(defvar ess-elisp-trace-mode nil "\
+Non-nil if Ess-Elisp-Trace mode is enabled.
+See the `ess-elisp-trace-mode' command
+for a description of this minor mode.
+Setting this variable directly does not take effect;
+either customize it (see the info node `Easy Customization')
+or call the function `ess-elisp-trace-mode'.")
+
+(custom-autoload 'ess-elisp-trace-mode "ess-utils" nil)
+
+(autoload 'ess-elisp-trace-mode "ess-utils" "\
+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.
+
+This is a minor mode. If called interactively, toggle the
+`Ess-Elisp-Trace mode' mode. If the prefix argument is positive,
+enable the mode, and if it is zero or negative, disable the mode.
+
+If called from Lisp, toggle the mode if ARG is `toggle'. Enable
+the mode if ARG is nil, omitted, or is a positive number.
+Disable the mode if ARG is a negative number.
+
+To check whether the minor mode is enabled in the current buffer,
+evaluate `(default-value \\='ess-elisp-trace-mode)'.
+
+The mode's hook is called both when the mode is enabled and when
+it is disabled.
+
+\(fn &optional ARG)" t nil)
+
+(register-definition-prefixes "ess-utils" '("ess-" "with-ess-process-buffer"))
+
+;;;***
+\f
+;;;### (autoloads nil "essd-els" "essd-els.el" (0 0 0 0))
+;;; Generated autoloads from essd-els.el
+
+(autoload 'ess-remote "essd-els" "\
+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
+
+\(fn &optional PROC-NAME DIALECT)" t nil)
+
+(register-definition-prefixes "essd-els" '("S+elsewhere" "ess-" "inferior-ess-remote-pager"))
+
+;;;***
+\f
+;;;### (autoloads nil nil ("ess-pkg.el" "ess-site.el") (0 0 0 0))
+
+;;;***
+\f
+;; Local Variables:
+;; version-control: never
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; coding: utf-8
+;; End:
+;;; ess-autoloads.el ends here
--- /dev/null
+;;; ess-bugs-d.el --- ESS[BUGS] dialect -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2008-2022 Free Software Foundation, Inc.
+
+;; Author: Rodney Sparapani
+;; Maintainer: ESS-help <ess-helpNOSPAMr-project.org>
+
+;; 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
+;; <http://www.gnu.org/licenses/>
+
+;;; 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 "\\<d\\(bern\\|beta\\|bin\\|cat\\|chisq\\|"
+ "dexp\\|dirch\\|exp\\|\\(gen[.]\\)?gamma\\|hyper\\|"
+ "interval\\|lnorm\\|logis\\|mnorm\\|mt\\|multi\\|"
+ "negbin\\|norm\\(mix\\)?\\|par\\|pois\\|sum\\|t\\|"
+ "unif\\|weib\\|wish\\)[ \t\n]*(")
+ font-lock-constant-face)
+
+ (cons (concat "\\<\\(abs\\|cos\\|C\\|dim\\|\\(i\\)?cloglog\\|equals\\|"
+ "exp\\|for\\|inprod\\|interp[.]line\\|inverse\\|length\\|"
+ "\\(i\\)?logit\\|logdet\\|logfact\\|loggam\\|max\\|mean\\|"
+ "mexp\\|min\\|phi\\|pow\\|probit\\|prod\\|rank\\|round\\|"
+ "sd\\|sin\\|sort\\|sqrt\\|step\\|sum\\|t\\|trunc\\|T\\)[ \t\n]*(")
+ font-lock-function-name-face)
+
+ ;; .bmd files
+ (cons (concat (regexp-opt '(
+ "dicClear" "dicSet" "dicStats"
+ "infoMemory" "infoModules" "infoNodeMethods"
+ "infoNodeTypes" "infoNodeValues"
+ "infoUpdatersbyDepth" "infoUpdatersbyName"
+ "modelCheck" "modelCompile" "modelData"
+ "modelDisable" "modelEnable" "modelGenInits"
+ "modelInits" "modelPrecision" "modelQuit"
+ "modelSaveState" "modelSetAP" "modelSetIts"
+ "modelSetOR" "modelSetRN" "modelUpdate"
+ "ranksClear" "ranksSet" "ranksStats"
+ "samplesAutoC" "samplesBgr" "samplesCoda"
+ "samplesDensity" "samplesHistory" "samplesSet"
+ "sampleStats" "samplesThin"
+ "summaryClear" "summarySet" "summaryStats"
+ ) 'words) "(")
+ font-lock-function-name-face)
+
+ (cons (concat (regexp-opt '("Local Variables" "End") 'words) ":")
+ font-lock-keyword-face)
+ )
+ "ESS[BUGS]: Font lock keywords."
+ )
+
+(defun ess-bugs-switch-to-suffix (suffix &optional bugs-chains bugs-monitor bugs-thin
+ bugs-burnin bugs-update)
+ "ESS[BUGS]: Switch to file with suffix."
+ (find-file (concat ess-bugs-file-dir ess-bugs-file-root suffix))
+
+ (if (equal 0 (buffer-size)) (progn
+ (if (equal ".bug" suffix) (progn
+ ;(insert "var ;\n")
+ (insert "model {\n")
+ (insert " for (i in 1:N) {\n \n")
+ (insert " }\n")
+ (insert "}\n")
+ (insert "#Local Variables" ":\n")
+ ; (insert "#enable-local-variables: :all\n")
+ (insert "#ess-bugs-chains:1\n")
+ (insert "#ess-bugs-monitor:(\"\")\n")
+ (insert "#ess-bugs-thin:1\n")
+ (insert "#ess-bugs-burnin:10000\n")
+ (insert "#ess-bugs-update:10000\n")
+ (insert "#End:\n")
+ ))
+
+ (if (equal ".bmd" suffix) (let
+ ((ess-bugs-temp-chains "") (ess-bugs-temp-monitor ""))
+
+ (if bugs-chains (setq ess-bugs-chains bugs-chains))
+ (if bugs-monitor (setq ess-bugs-monitor bugs-monitor))
+ (if bugs-thin (setq ess-bugs-thin bugs-thin))
+
+ (setq ess-bugs-temp-chains
+ (concat "modelCompile(" (format "%d" ess-bugs-chains) ")\n"))
+
+ (setq bugs-chains ess-bugs-chains)
+
+ (while (< 0 bugs-chains)
+ (setq ess-bugs-temp-chains
+ (concat ess-bugs-temp-chains
+ "modelInits('" ess-bugs-file-root
+ ".##" (format "%d" bugs-chains) "', "
+ (format "%d" bugs-chains) ")\n"))
+ (setq bugs-chains (- bugs-chains 1)))
+
+ (setq ess-bugs-temp-monitor "")
+
+ (while (and (listp ess-bugs-monitor) (consp ess-bugs-monitor))
+ (if (not (string-equal "" (car ess-bugs-monitor)))
+ (setq ess-bugs-temp-monitor
+ (concat ess-bugs-temp-monitor "samplesSet('"
+ (car ess-bugs-monitor)
+ ;", thin(" (format "%d" ess-bugs-thin)
+ "')\n")))
+ (setq ess-bugs-monitor (cdr ess-bugs-monitor)))
+
+ (insert "modelCheck('" ess-bugs-file-root ".bug')\n")
+ (insert "modelData('" ess-bugs-file-root ".bdt')\n")
+ (insert (ess-replace-in-string ess-bugs-temp-chains "##" "in"))
+ (insert "modelGenInits()\n")
+ (insert "modelUpdate(" (format "%d" bugs-burnin) ")\n")
+ ;(insert "modelUpdate(" (format "%d" (* bugs-thin bugs-burnin)) ")\n")
+ (insert ess-bugs-temp-monitor)
+ (insert "modelUpdate(" (format "%d" (* bugs-thin bugs-update)) ")\n")
+ ; (insert (ess-replace-in-string
+ ; (ess-replace-in-string ess-bugs-temp-chains
+ ; "modelCompile([0-9]+)" "#") "##" "to"))
+
+ (if (< 1 bugs-thin) (insert "samplesThin(" (format "%d" bugs-thin) ")\n"))
+
+ (insert "samplesCoda('*', '" ess-bugs-file-root "')\n")
+
+ ; (if ess-bugs-system (progn
+ ; (insert "system rm -f " ess-bugs-file-root ".ind\n")
+ ; (insert "system ln -s " ess-bugs-file-root "index.txt " ess-bugs-file-root ".ind\n")
+
+ ; (setq bugs-chains ess-bugs-chains)
+
+ ; (while (< 0 bugs-chains)
+ ; (setq ess-bugs-temp-chain (format "%d" bugs-chains))
+
+ ; ;.txt not recognized by BOA and impractical to over-ride
+ ; (insert "system rm -f " ess-bugs-file-root ess-bugs-temp-chain ".out\n")
+ ; (insert "system ln -s " ess-bugs-file-root "chain" ess-bugs-temp-chain ".txt "
+ ; ess-bugs-file-root ess-bugs-temp-chain ".out\n")
+ ; (setq bugs-chains (- bugs-chains 1)))))
+
+ (insert "modelQuit()\n")
+ (insert "Local Variables" ":\n")
+ ; (insert "enable-local-variables: :all\n")
+ (insert "ess-bugs-chains:" (format "%d" ess-bugs-chains) "\n")
+ (insert "ess-bugs-command:\"" ess-bugs-command "\"\n")
+ (insert "End:\n")
+ ))
+ ))
+ )
+
+(defun ess-bugs-na-bmd (bugs-command)
+ "ESS[BUGS]: Perform the Next-Action for .bmd."
+ ;(ess-save-and-set-local-variables)
+ (if (equal 0 (buffer-size)) (ess-bugs-switch-to-suffix ".bmd")
+ ;else
+ (shell)
+ (ess-sleep)
+
+ (when (and (when (fboundp 'w32-shell-dos-semantics)
+ (w32-shell-dos-semantics))
+ (string-equal ":" (substring ess-bugs-file 1 2)))
+ (insert (substring ess-bugs-file 0 2)))
+
+ (comint-send-input)
+ (insert "cd \"" ess-bugs-file-dir "\"")
+ (comint-send-input)
+
+ ; (let ((ess-bugs-temp-chains ""))
+ ;
+ ; (while (< 0 bugs-chains)
+ ; (setq ess-bugs-temp-chains
+ ; (concat (format "%d " bugs-chains) ess-bugs-temp-chains))
+ ; (setq bugs-chains (- bugs-chains 1)))
+
+ ;; (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 "' > " 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
--- /dev/null
+;;; ess-bugs-l.el --- ESS[BUGS] languages -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2006-2020 Free Software Foundation, Inc.
+
+;; Author: Rodney Sparapani
+;; Maintainer: ESS-help <ess-helpNOSPAMr-project.org>
+
+;; 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
+;; <http://www.gnu.org/licenses/>
+
+;;; 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
--- /dev/null
+;;; ess-custom.el --- Customize variables for ESS -*- lexical-binding: t; -*-
+
+;; Copyright (C) 1997-2020 Free Software Foundation, Inc.
+
+;; Author: Rodney Sparapani
+;; Maintainer: ESS-help <ess-helpNOSPAMr-project.org>
+;; 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-")
+
+
+\f ; 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 . "19.04"))
+
+(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 . "19.04"))
+
+;; 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 . "19.04"))
+
+(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 . "19.04"))
+
+(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 . "18.10"))
+
+(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 "18.10"))
+(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 . "18.10"))
+
+;;*;; 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 . "19.04"))
+
+;;*;; 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 . "18.10"))
+
+(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.")
+
+\f ; 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-mode-map>\\[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 . "19.04"))
+
+
+(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)
+
+
+\f ; 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 . "19.04")
+ :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)
+
+\f ; 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 <ess-lang>-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 "[-=+*></|&]+" 'ess-operator-face)
+ "Operators.")
+
+(defvar ess-S-fl-keyword:modifiers
+ (cons (regexp-opt ess-S-modifiers 'words)
+ 'ess-modifiers-face) ; modify search list or source (i.e. directives)
+ "Font lock keyword R modifiers.")
+
+(defvar ess-S-fl-keyword:fun-defs
+ (cons ess-S-function-name-regexp
+ '(1 font-lock-function-name-face t))
+ "Font-lock function definitions keyword.")
+
+(defvar ess-S-fl-keyword:keywords
+ (cons (regexp-opt ess-S-keywords 'words) 'ess-keyword-face))
+
+(defvar ess-S-fl-keyword:assign-ops
+ (cons (regexp-opt ess-S-assign-ops) 'ess-assignment-face)
+ "Font-lock assign operators.")
+
+(defvar ess-S-fl-keyword:constants
+ (cons (regexp-opt ess-S-constants 'words) 'ess-constant-face)
+ "Font-lock constants keyword.")
+
+(defcustom ess-S-font-lock-keywords
+ '((ess-S-fl-keyword:modifiers . t)
+ (ess-S-fl-keyword:fun-defs . t)
+ (ess-S-fl-keyword:keywords . t)
+ (ess-S-fl-keyword:assign-ops . t)
+ (ess-S-fl-keyword:constants . t)
+ (ess-fl-keyword:fun-calls)
+ (ess-fl-keyword:numbers)
+ (ess-fl-keyword:operators)
+ (ess-fl-keyword:delimiters)
+ (ess-fl-keyword:=))
+ "An alist of available font-lock keywords for the S mode.
+The key of each cons cell is a name of the keyword. The value
+should be t or nil to indicate if the keyword is activated by
+default or not."
+ :group 'ess-S
+ :group 'ess-faces
+ :type '(repeat (cons symbol boolean)))
+
+(defvar ess-R-fl-keyword:modifiers
+ '(eval . (cons (concat "\\(" (regexp-opt ess-R-modifiers 'words) "\\)\\s-*(")
+ '(1 ess-modifiers-face)))
+ "Font-lock keyword R modifiers.
+See `ess-R-modifiers' for the list of modifiers.")
+
+(defvar ess-R-fl-keyword:fun-defs
+ '(eval . (cons ess-R-function-name-regexp
+ '(1 font-lock-function-name-face nil)))
+ "Font-lock keyword for function names in function definitions.
+When this keyword is on, function names on the left hand side of
+<- are highlighted with `font-lock-function-name-face'.")
+
+(defvar ess-R-fl-keyword:keywords
+ '(ess-r--find-fl-keyword . ess-keyword-face)
+ "Font lock keyword for `ess-R-keywords'.")
+
+(defvar ess-R-fl-keyword:assign-ops
+ '(eval . (cons (regexp-opt ess-R-assign-ops) 'ess-assignment-face))
+ "Font-lock assign operators.
+See `ess-R-assign-ops' for the ops.")
+
+(defvar ess-R-fl-keyword:constants
+ '(eval . (cons (regexp-opt ess-R-constants 'words) 'ess-constant-face))
+ "Font-lock constants keyword.
+See `ess-R-constants' for the list of constants.")
+
+(defvar ess-R-fl-keyword:F&T
+ '("\\b[FT]\\b" . ess-constant-face)
+ "Highlight T and F in addition to TRUE and FALSE in R.")
+
+(defvar ess-R-fl-keyword:%op% nil
+ "Highlight %op% operators.")
+
+(defcustom ess-R-font-lock-keywords
+ '((ess-R-fl-keyword:keywords . t)
+ (ess-R-fl-keyword:constants . t)
+ (ess-R-fl-keyword:modifiers . t)
+ (ess-R-fl-keyword:fun-defs . t)
+ (ess-R-fl-keyword:assign-ops . t)
+ (ess-R-fl-keyword:%op% . t)
+ (ess-fl-keyword:fun-calls)
+ (ess-fl-keyword:numbers)
+ (ess-fl-keyword:operators)
+ (ess-fl-keyword:delimiters)
+ (ess-fl-keyword:=)
+ (ess-R-fl-keyword:F&T))
+ "An alist of available font-lock keywords for the R mode.
+The key of each cons cell is a name of the keyword. The value
+should be t or nil to indicate if the keyword is active or not."
+ :group 'ess-R
+ :group 'ess-faces
+ :type '(repeat (cons symbol boolean)))
+
+(defvar ess-S-fl-keyword:prompt
+ (cons (concat "^" inferior-S-prompt) 'comint-highlight-prompt)
+ "Highlight prompts missed by comint.")
+
+(defvar ess-fl-keyword:matrix-labels
+ ;; also matches subsetting
+ (cons "\\[,?[1-9][0-9]*,?\\]" 'ess-matrix-face)
+ "Matrix and vector numeric labels.")
+
+(defvar ess-R-fl-keyword:messages
+ (cons (regexp-opt ess-R-message-prefixes 'enc-paren)
+ 'font-lock-warning-face)
+ "Inferior-ess problems or errors.")
+
+(defvaralias 'inferior-R-font-lock-keywords 'inferior-ess-r-font-lock-keywords)
+(defcustom inferior-ess-r-font-lock-keywords
+ '((ess-S-fl-keyword:prompt . t)
+ (ess-R-fl-keyword:keywords . t)
+ (ess-R-fl-keyword:constants . t)
+ (ess-R-fl-keyword:modifiers . t)
+ (ess-R-fl-keyword:messages . t)
+ (ess-R-fl-keyword:fun-defs . t)
+ (ess-R-fl-keyword:assign-ops . t)
+ (ess-fl-keyword:matrix-labels . t)
+ (ess-fl-keyword:fun-calls)
+ (ess-fl-keyword:numbers)
+ (ess-fl-keyword:operators)
+ (ess-fl-keyword:delimiters)
+ (ess-fl-keyword:=)
+ (ess-R-fl-keyword:F&T))
+ "Font-lock patterns used in `inferior-ess-r-mode' buffers.
+The key of each cons cell is a name of the keyword. The value
+should be t or nil to indicate if the keyword is active or not."
+ :group 'ess-R
+ :group 'ess-faces
+ :type '(repeat (cons symbol boolean)))
+
+(defvar ess-S-fl-keyword:messages
+ (cons (regexp-opt ess-S-message-prefixes 'enc-paren)
+ 'font-lock-warning-face)
+ "Inferior-ess problems or errors.")
+
+(defcustom inferior-S-font-lock-keywords
+ '((ess-S-fl-keyword:prompt . t)
+ (ess-S-fl-keyword:messages . t)
+ (ess-S-fl-keyword:modifiers . t)
+ (ess-S-fl-keyword:fun-defs . t)
+ (ess-S-fl-keyword:keywords . t)
+ (ess-S-fl-keyword:assign-ops . t)
+ (ess-S-fl-keyword:constants . t)
+ (ess-fl-keyword:fun-calls)
+ (ess-fl-keyword:numbers)
+ (ess-fl-keyword:operators)
+ (ess-fl-keyword:delimiters)
+ (ess-fl-keyword:=))
+ "Font-lock patterns used in inferior-S-mode buffers.
+The key of each cons cell is a name of the keyword. The value
+should be t or nil to indicate if the keyword is active by
+default."
+ :group 'ess-S
+ :group 'ess-faces
+ :type '(repeat (cons symbol boolean)))
+
+\f
+;;;*;;; ess-help variables
+
+;; This will never need to be loaded independently of any of the other modules,
+;; but they can all call it so we may as well put it here.
+
+(defcustom ess-help-pop-to-buffer t
+ "If non-nil ess-help buffers are given focus during the display.
+If non-nil, `ess-display-help' uses `pop-to-buffer' to display
+help, otherwise it uses `display-buffer', which does not select
+the help window."
+ :group 'ess-help
+ :type 'boolean)
+
+(defcustom ess-help-own-frame nil
+ "Controls whether ESS help buffers should start in a different frame.
+
+Possible values are:
+ nil: Display help in current frame.
+ \\='one: All help buffers are shown in one dedicated frame.
+ t: Each help buffer gets its own frame.
+
+If this is non-nil,`ess-help-reuse-window' is ignored. The
+parameters of the own frame are stored in
+`ess-help-frame-alist'."
+ :group 'ess-help
+ :type '(choice (const :tag "Display in current frame" nil)
+ (const :tag "Display in one frame" one)
+ (const :tag "Always display in a new frame" t)))
+
+(defcustom ess-help-reuse-window t
+ "If t, ESS tries to display new help buffers in the existing help window.
+This variable is ignored if `ess-help-own-frame' is non-nil."
+ :type 'boolean
+ :group 'ess-help)
+
+(defcustom ess-help-frame-alist default-frame-alist
+ "Alist of frame parameters used to create help frames.
+This defaults to `default-frame-alist' and is used only when
+the variable `ess-help-own-frame' is non-nil."
+ :group 'ess-help
+ :type 'alist
+ :package-version '(ess . "18.10"))
+
+\f ; Faces
+;;;=====================================================
+
+(defconst comint-highlight-prompt 'comint-highlight-prompt)
+
+(defconst ess-function-call-face 'ess-function-call-face)
+(defface ess-function-call-face
+ '((default (:slant normal :inherit font-lock-function-name-face)))
+ "Font Lock face used to highlight function calls in ess buffers."
+ :group 'ess-faces)
+
+(defconst ess-numbers-face 'ess-numbers-face)
+(defface ess-numbers-face
+ '((default (:slant normal :inherit font-lock-type-face)))
+ "Font Lock face used to highlight numbers in `ess-mode' buffers."
+ :group 'ess-faces)
+
+(defconst ess-operator-face 'ess-operator-face)
+(defface ess-operator-face
+ '((default (:inherit font-lock-constant-face)))
+ "Font Lock face for operators."
+ :group 'ess-faces)
+
+(defconst ess-%op%-face 'ess-%op%-face)
+(defface ess-%op%-face
+ '((default (:inherit ess-operator-face)))
+ "Font Lock face used to highlight %op% operators in `ess-mode' buffers."
+ :group 'ess-faces)
+
+(defconst ess-assignment-face 'ess-assignment-face)
+(defface ess-assignment-face
+ '((default (:inherit font-lock-constant-face)))
+ "Font lock face used to highlight assignment operators."
+ :group 'ess-faces)
+
+(defconst ess-paren-face 'ess-paren-face)
+(defface ess-paren-face
+ '((default (:inherit font-lock-constant-face)))
+ "Font lock face used to highlight parentheses."
+ :group 'ess-faces)
+
+(defconst ess-operator-face 'ess-operator-face)
+(defface ess-operator-face
+ '((default (:inherit font-lock-constant-face)))
+ "Font lock face used to highlight operators."
+ :group 'ess-faces)
+
+(defconst ess-modifiers-face 'ess-modifiers-face)
+(defface ess-modifiers-face
+ '((default (:inherit font-lock-constant-face)))
+ "Font lock face used to highlight modifiers.
+In `R-mode', for example, this includes \"library,\" \"attach,\"
+and others. See `ess-R-modifiers'."
+ :group 'ess-faces)
+
+(defconst ess-constant-face 'ess-constant-face)
+(defface ess-constant-face
+ '((default (:inherit font-lock-type-face)))
+ "Font lock face used to highlight constants.
+In `ess-r-mode', for example, this includes TRUE, FALSE, Inf and
+others. See `ess-R-constants'."
+ :group 'ess-faces)
+
+(defconst ess-matrix-face 'ess-matrix-face)
+(defface ess-matrix-face
+ '((default (:inherit font-lock-constant-face)))
+ "Font lock face used to highlight row/column labels in matrices."
+ :group 'ess-faces)
+
+(defconst ess-keyword-face 'ess-keyword-face)
+(defface ess-keyword-face
+ '((default (:inherit font-lock-keyword-face)))
+ "Font lock face used to highlight reserved keywords.
+In `ess-r-mode', for example, this includes \"while,\" \"if/else\",
+\"function,\" and others. See `ess-R-keywords'."
+ :group 'ess-faces)
+
+(defconst ess-r-control-flow-keyword-face 'ess-r-control-flow-keyword-face)
+(defface ess-r-control-flow-keyword-face
+ '((default (:inherit ess-keyword-face)))
+ "Font lock face used to highlight control flow keywords.
+In `R-mode', for example, this includes \"switch(),\"
+\"tryCatch()\", and \"stop(),\". See
+`ess-R-control-flow-keywords'. By default, these keywords are
+highlighted with the same face as `ess-R-keywords'"
+ :group 'ess-faces)
+
+(defcustom ess-help-kill-bogus-buffers t
+ "Non-nil means kill ESS help buffers immediately if they are \"bogus\"."
+ :group 'ess-help
+ :type 'boolean)
+
+(defvar ess-execute-screen-options-command nil
+ "Dialect specific command run by `ess-execute-screen-options'.")
+
+(defvar-local ess-funargs-command nil
+ "Dialect specific command to return a list of function arguments.
+See `ess-function-arguments' and .ess_funargs command in R and
+S+ for details of the format that should be returned.")
+
+\f ; System variables
+;;;=====================================================
+;;; Users note: You will rarely have to change these
+;;; variables.
+
+;;*;; Variables relating to ess-help-mode
+
+;;-- ess-help-S-.. and ess-help-R-.. : in ess-s-lang.el (are used in ess-inf).
+
+(defvar-local ess-help-sec-keys-alist nil
+ "Alist of (key . string) pairs for use in section searching.")
+
+(defvar-local ess-help-sec-regex nil
+ "Reg(ular) Ex(pression) of section headers in help file.")
+
+\f ; julia-mode
+(define-obsolete-variable-alias 'inferior-julia-program-name
+ 'inferior-julia-program "ESS 18.10")
+(defcustom inferior-julia-program (or (executable-find "julia-basic")
+ "julia")
+ "Executable for Julia.
+Should be an absolute path to the julia executable."
+ :group 'ess-Julia
+ :type '(choice (string) (file)))
+
+;; FIXME
+(defvar-local ess-mode-completion-syntax-table nil "Completion and help syntax table for `ess-mode'.")
+
+\f ; Buffer local customization stuff
+
+(defcustom ess-error-buffer-name "*ESS-errors*"
+ "Name of buffer to keep process error messages in.
+Created for each process."
+ :group 'ess-proc
+ :type 'string)
+
+(defvar ess-error-regexp-alist nil
+ "List of symbols which are looked up in `compilation-error-regexp-alist-alist'.")
+
+(defcustom ess-write-to-dribble t
+ "Non-nil means write to `ess-dribble-buffer'.
+See also `ess-verbose'."
+ :group 'ess-proc
+ :type 'boolean
+ :package-version '(ess . "18.10"))
+
+(defcustom ess-verbose nil
+ "Non-nil means write more information to `ess-dribble-buffer' than usual."
+ :group 'ess-proc
+ :type 'boolean)
+
+(defvar ess-dribble-buffer "*ESS*"
+ "Buffer or name of buffer for printing debugging information.")
+
+(defvar-local ess-local-customize-alist nil
+ "Buffer local settings for proper behavior.
+Used to store the values for passing on to newly created buffers.")
+
+(defvar ess-mode-editing-alist nil
+ "Variable settings for `ess-mode'.")
+
+(defvar-local ess-transcript-minor-mode nil
+ "Non-nil if using `ess-transcript-mode' as a minor mode of some other mode.")
+
+(defvar-local ess-listing-minor-mode nil
+ "Non-nil if using `ess-listing-minor-mode'.")
+
+(defvar ess-STERM nil
+ "Placeholder for dialect-specific STERM.")
+
+(make-obsolete-variable 'ess-S-loop-timeout "It is ignored." "ESS 18.10")
+(make-obsolete-variable 'ess-mode-load-hook "It is ignored." "ESS 18.10")
+(make-obsolete-variable 'ess-speedbar-use-p "It is ignored." "ESS 18.10")
+(make-obsolete-variable 'ess-synchronize-evals "It is ignored." "ESS 18.10")
+(make-obsolete-variable 'ess-eval-visibly-at-end "It is ignored." "ESS 18.10")
+(make-obsolete-variable 'ess-font-lock-mode 'global-font-lock-mode "ESS 18.10")
+(provide 'ess-custom)
+
+;;; ess-custom.el ends here
--- /dev/null
+;; ess-gretl.el --- ESS gretl mode and inferior interaction -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2012-2022 Free Software Foundation, Inc.
+;; Author: Ahmadou Dicko, Spinu Vitalie and Allin Cottrell
+;; Maintainer: ESS Core Team <ESS-coreNOSPAMr-project.org>
+;; 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
+;; <http://www.gnu.org/licenses/>
+
+;;; 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
--- /dev/null
+;;; ess-help.el --- Support for viewing ESS help files -*- lexical-binding: t; -*-
+
+;; Copyright (C) 1989-2022 Free Software Foundation, Inc.
+
+;; Author: David Smith <dsmithNOSPAMstats.adelaide.edu.au>
+;; Created: 7 Jan 1994
+;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
+
+;; 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
+;; <http://www.gnu.org/licenses/>
+
+;;; Commentary:
+
+;; Code for dealing with ESS help files. See README.<LANGUAGE> where
+;; <LANGUAGE> is one of `S', `SAS', `Stata' or `XLispStat'.
+
+;;; Code:
+
+\f ; 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).")
+
+\f ; 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 <TEACH> 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))
+
+\f
+;;*;; 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))))
+
+\f
+;;*;; 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 "_\b" 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)))
+
+\f
+;; 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
--- /dev/null
+;;; ess-inf.el --- Support for running S as an inferior Emacs process -*- lexical-binding: t; -*-
+
+;; Copyright (C) 1989-2022 Free Software Foundation, Inc.
+
+;; Author: David Smith <dsmithNOSPAMstats.adelaide.edu.au>
+;; Created: 7 Jan 1994
+;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
+
+;; 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
+;; <http://www.gnu.org/licenses/>
+
+;;; 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)))))
+
+\f ;;*;; 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-<lang>-objects-command
+and then made buffer local."); and the *-<lang>-* 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 ()
+ "\1e\1eESSR::ERROR \\(\"\\)")
+
+(defun ess--delimiter-error-end-re ()
+ "\\(\"\\)\1e\1e")
+
+(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)))
+ (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-<ESSlang>-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
+ (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)))
+
+\f
+;;; 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)))))
+
+\f
+;;*;; 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))
+
+\f
+;;*;; 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.")
+
+\f
+;;*;; 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)))
+
+\f
+;;;*;;; 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")
+
+\f
+;;;*;;; 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))
+
+\f ; 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))
+
+
+\f
+;;*;; 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)))))
+
+\f
+;;;*;;; 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))))))
+
+\f
+;;;*;;; 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")))))
+
+\f
+;;;*;;; 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)))))))
+
+\f
+;;*;; 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))))
+
+\f
+;;; 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 ",")))))
+
+\f ; 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)))))
+
+\f
+;;*;; 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 \f 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 "^\f" 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)))
+
+\f
+;;*;; 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
--- /dev/null
+;;; 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 <ESS-coreNOSPAMr-project.org>
+
+;; 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
+;; <http://www.gnu.org/licenses/>
+
+;;; 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 "\\<d\\(bern\\|beta\\|bin\\|cat\\|chisq\\|"
+ "dexp\\|dirch\\|exp\\|\\(gen[.]\\)?gamma\\|hyper\\|"
+ "interval\\|lnorm\\|logis\\|mnorm\\|mt\\|multi\\|"
+ "negbin\\|norm\\(mix\\)?\\|par\\|pois\\|sum\\|t\\|"
+ "unif\\|weib\\|wish\\)[ \t\n]*(")
+ font-lock-constant-face)
+
+ (cons (concat "\\<\\(abs\\|cos\\|dim\\|\\(i\\)?cloglog\\|equals\\|"
+ "exp\\|for\\|inprod\\|interp[.]line\\|inverse\\|length\\|"
+ "\\(i\\)?logit\\|logdet\\|logfact\\|loggam\\|max\\|mean\\|"
+ "mexp\\|min\\|phi\\|pow\\|probit\\|prod\\|rank\\|round\\|"
+ "sd\\|sin\\|sort\\|sqrt\\|step\\|sum\\|t\\|trunc\\|T\\)[ \t\n]*(")
+ font-lock-function-name-face)
+
+ ;; .jmd files
+ (cons (concat "\\<\\(adapt\\|cd\\|clear\\|coda\\|data\\|dir\\|"
+ "exit\\|in\\(itialize\\)?\\|load\\|model\\|monitors\\|parameters\\|"
+ "pwd\\|run\\|s\\(amplers\\|ystem\\)\\|to\\|update\\)[ \t\n]")
+ font-lock-keyword-face)
+
+ (cons "\\<\\(compile\\|monitor\\)[, \t\n]"
+ font-lock-keyword-face)
+
+ (cons "[, \t\n]\\(by\\|chain\\|nchains\\|stem\\|thin\\|type\\)[ \t\n]*("
+ font-lock-function-name-face)
+ )
+ "ESS[JAGS]: Font lock keywords."
+ )
+
+(defun ess-jags-switch-to-suffix (suffix &optional jags-chains jags-monitor jags-thin
+ jags-burnin jags-update)
+ "ESS[JAGS]: Switch to file with suffix."
+ (find-file (concat ess-bugs-file-dir ess-bugs-file-root suffix))
+
+ (if (equal 0 (buffer-size)) (progn
+ (if (equal ".jag" suffix) (progn
+ (insert "var ;\n")
+ (insert "model {\n")
+ (insert " for (i in 1:N) {\n \n")
+ (insert " }\n")
+ (insert "}\n")
+ (insert "#Local Variables" ":\n")
+ (insert "#ess-jags-chains:1\n")
+ (insert "#ess-jags-monitor:(\"\")\n")
+ (insert "#ess-jags-thin:1\n")
+ (insert "#ess-jags-burnin:10000\n")
+ (insert "#ess-jags-update:10000\n")
+ (insert "#End:\n")
+ ))
+
+ (if (equal ".jmd" suffix) (let
+ ((ess-jags-temp-chains "") (ess-jags-temp-monitor "") (ess-jags-temp-chain ""))
+
+ (if jags-chains (setq ess-jags-chains jags-chains))
+ (if jags-monitor (setq ess-jags-monitor jags-monitor))
+ (if jags-thin (setq ess-jags-thin jags-thin))
+
+ (setq ess-jags-temp-chains
+ (concat "compile, nchains(" (format "%d" ess-jags-chains) ")\n"))
+
+ (setq jags-chains ess-jags-chains)
+
+ (while (< 0 jags-chains)
+ (setq ess-jags-temp-chains
+ (concat ess-jags-temp-chains
+ "parameters ## \"" ess-bugs-file-root
+ ".##" (format "%d" jags-chains) "\", chain("
+ (format "%d" jags-chains) ")\n"))
+ (setq jags-chains (- jags-chains 1)))
+
+ (setq ess-jags-temp-monitor "")
+
+ (while (and (listp ess-jags-monitor) (consp ess-jags-monitor))
+ (if (not (string-equal "" (car ess-jags-monitor)))
+ (setq ess-jags-temp-monitor
+ (concat ess-jags-temp-monitor "monitor "
+ (car ess-jags-monitor) ", thin(" (format "%d" ess-jags-thin) ")\n")))
+ (setq ess-jags-monitor (cdr ess-jags-monitor)))
+
+ (insert "model in \"" ess-bugs-file-root ".jag\"\n")
+ (insert "data in \"" ess-bugs-file-root ".jdt\"\n")
+ (insert (ess-replace-in-string ess-jags-temp-chains "##" "in"))
+ (insert "initialize\n")
+ ;(insert "update " (format "%d" (* jags-thin jags-burnin)) "\n")
+ (insert "update " (format "%d" jags-burnin) "\n")
+ (insert ess-jags-temp-monitor)
+ (insert "update " (format "%d" (* jags-thin jags-update)) "\n")
+ (insert (ess-replace-in-string
+ (ess-replace-in-string ess-jags-temp-chains
+ "compile, nchains([0-9]+)" "#") "##" "to"))
+ (insert "coda "
+ ;(if ess-microsoft-p (if (w32-shell-dos-semantics) "*" "\\*") "\\*")
+ "*, stem(\"" ess-bugs-file-root "\")\n")
+
+ (if ess-jags-system (progn
+ (insert "system rm -f " ess-bugs-file-root ".ind\n")
+ (insert "system ln -s " ess-bugs-file-root "index.txt " ess-bugs-file-root ".ind\n")
+
+ (setq jags-chains ess-jags-chains)
+
+ (while (< 0 jags-chains)
+ (setq ess-jags-temp-chain (format "%d" jags-chains))
+
+ ;.txt not recognized by BOA and impractical to over-ride
+ (insert "system rm -f " ess-bugs-file-root ess-jags-temp-chain ".out\n")
+ (insert "system ln -s " ess-bugs-file-root "chain" ess-jags-temp-chain ".txt "
+ ess-bugs-file-root ess-jags-temp-chain ".out\n")
+ (setq jags-chains (- jags-chains 1)))))
+
+ (insert "exit\n")
+ (insert "Local Variables" ":\n")
+ (insert "ess-jags-chains:" (format "%d" ess-jags-chains) "\n")
+ (insert "ess-jags-command:\"jags\"\n")
+ (insert "End:\n")
+ ))
+ ))
+ )
+
+(defun ess-jags-na-jmd (jags-command)
+ "ESS[JAGS]: Perform the Next-Action for .jmd."
+ ;(ess-save-and-set-local-variables)
+ (if (equal 0 (buffer-size)) (ess-jags-switch-to-suffix ".jmd")
+ ;else
+ (shell)
+ (ess-sleep)
+
+ (if (when (fboundp 'w32-shell-dos-semantics)
+ (w32-shell-dos-semantics))
+ (if (string-equal ":" (substring ess-bugs-file 1 2))
+ (progn
+ (insert (substring ess-bugs-file 0 2))
+ (comint-send-input)
+ )
+ )
+ )
+
+ (insert "cd \"" ess-bugs-file-dir "\"")
+ (comint-send-input)
+
+ ; (let ((ess-jags-temp-chains ""))
+ ;
+ ; (while (< 0 jags-chains)
+ ; (setq ess-jags-temp-chains
+ ; (concat (format "%d " jags-chains) ess-jags-temp-chains))
+ ; (setq jags-chains (- jags-chains 1)))
+
+ (insert ess-bugs-batch-pre-command " " jags-command " "
+ ess-bugs-file-root ".jmd "
+
+ (if (or (equal shell-file-name "/bin/csh")
+ (equal shell-file-name "/bin/tcsh")
+ (equal shell-file-name "/bin/zsh")
+ (equal shell-file-name "/bin/bash"))
+ (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
--- /dev/null
+;; 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
+;; <http://www.gnu.org/licenses/>
+
+;;; 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))))
+
+\f
+;;; 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=\"\\([^>]+\\)\">\\([^<]+\\)</a" nil t)
+ (push (propertize (match-string 2)
+ :manual (concat url (match-string 1)))
+ out))
+ (kill-buffer)
+ (nreverse out))))
+
+(defvar ess-julia--manual-topics nil)
+(cl-defmethod ess--manual-lookup-override (&context (ess-dialect "julia"))
+ "Look up topics at https://docs.julialang.org/en/latest/manual/."
+ (let* ((pages (or ess-julia--manual-topics
+ (setq ess-julia--manual-topics
+ (ess-julia--retrieve-topics
+ "https://docs.julialang.org/en/latest/"))))
+ (page (ess-completing-read "Lookup:" pages nil t)))
+ (browse-url (get-text-property 1 :manual page))))
+
+(defun ess-julia-input-sender (proc string)
+ "Function to send PROC STRING submitted by user.
+See `comint-input-sender'."
+ (save-current-buffer
+ (let* ((help-?-regexp "^ *\\(?:\\(?1: *?\\? *\\)\\(?2:.+\\)\\)")
+ (help-?-match (string-match help-?-regexp string)))
+ (cond (help-?-match
+ (ess-display-help-on-object (match-string 2 string))
+ (process-send-string proc "\n"))
+ (t ;; normal command
+ (inferior-ess-input-sender proc string))))))
+
+(cl-defmethod ess-installed-packages (&context (ess-dialect "julia"))
+ "Return list of installed julia packages."
+ ;; FIXME: This doesn't work if the user hasn't done "using Pkg" yet
+ (ess-get-words-from-vector "keys(Pkg.installed())\n"))
+
+(cl-defmethod ess-load-library--override (pack &context (ess-dialect "julia"))
+ (ess-eval-linewise (format "using %s\n" pack)))
+
+\f
+;;; COMPLETION
+(defun ess-julia-latexsub-completion ()
+ "Complete latex input in format required by `completion-at-point-functions'."
+ (if (julia-latexsub) ; julia-latexsub returns nil if it performed a completion, the point otherwise
+ nil
+ (lambda () t) ;; bypass other completion methods
+ ))
+
+(defun ess-julia-object-completion ()
+ "Return completions in format required by `completion-at-point-functions'."
+ (let ((proc (ess-get-next-available-process ess-dialect t))
+ (beg (ess-symbol-start)))
+ (if proc
+ (when beg
+ (let* ((prefix (buffer-substring-no-properties beg (point)))
+ (obj (and (string-match "\\(.*\\)\\..*$" prefix)
+ (match-string 1 prefix)))
+ (beg (if obj
+ (+ beg 1 (length obj))
+ beg)))
+ (list beg (point)
+ (nreverse (mapcar #'car (ess-julia--get-objects proc obj)))
+ :exclusive 'no)))
+ (when (string-match "complet" (symbol-name last-command))
+ (message "No ESS process of dialect %s started" ess-dialect)
+ nil))))
+
+(defun ess-julia-objects (prefix &optional proc)
+ "Given PREFIX get all cached objects from PROC."
+ (when prefix
+ (let ((proc (or proc (ess-get-next-available-process nil t))))
+ (if (string-match "\\(.*\\)\\..*$" prefix)
+ (let ((module (match-string 1 prefix)))
+ (mapcar (lambda (el) (concat module "." (car el)))
+ (ess-julia--get-objects proc module)))
+ (ess-julia--get-objects proc)))))
+
+(defun ess-julia--get-objects (&optional proc obj)
+ "Return all available objects.
+Local caching might be used. If MODULE is given, return only
+objects from that MODULE."
+ (setq proc (or proc (ess-get-process)))
+ (when (stringp proc)
+ (setq proc (get-process proc)))
+ (when (process-live-p proc)
+ (let ((objects (process-get proc 'objects)))
+ (if (process-get proc 'busy)
+ (if obj
+ (assoc obj objects)
+ (process-get proc 'objects))
+ (if obj
+ (or (cdr (assoc obj objects))
+ ;; don't cache composite objects and datatypes
+ (ess-julia--get-components proc obj))
+ ;; this segment is entered when user completion at top level is
+ ;; requested, either Tab or AC. Hence Main is always updated.
+ (let ((modules (ess-get-words-from-vector
+ "ESS.main_modules()\n" nil nil proc))
+ (loc (process-get proc 'last-objects-cache))
+ (lev (process-get proc 'last-eval)))
+ (prog1
+ (apply #'nconc
+ (mapcar
+ (lambda (mod)
+ ;; we are caching all modules, and reinit Main every
+ ;; time user enters commands
+ (copy-sequence
+ (or (and (or (not (equal mod "Main"))
+ (ignore-errors (time-less-p lev loc)))
+ (cdr (assoc mod objects)))
+ (ess-julia--get-components proc mod t))))
+ modules))
+ (process-put proc 'last-objects-cache (current-time)))))))))
+
+(defun ess-julia--get-components (proc obj &optional cache?)
+ (with-current-buffer (ess--foreground-command (format "ESS.components(%s)\n" obj)
+ nil nil nil nil proc)
+ (goto-char (point-min))
+ (let (list)
+ (while (re-search-forward
+ "^\\([^ \t\n]+\\) +\\([^ \t\n]+\\)$" nil t)
+ (push (cons (match-string 1) (match-string 2)) list))
+ (when cache?
+ (let ((objects (process-get proc 'objects)))
+ (push (cons obj list) objects)
+ (process-put proc 'objects objects)))
+ list)))
+
+(defun ess-julia-get-object-help-string (sym)
+ "Help string for ac."
+ (let ((proc (ess-get-next-available-process nil t)))
+ (if (null proc)
+ "No free ESS process found"
+ (let ((buf (get-buffer-create " *ess-command-output*")))
+ (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))))))
+
+(defvar ac-source-ess-julia-objects
+ '((prefix . ess-symbol-start)
+ (requires . 2)
+ (candidates . ess-ac-julia-objects)
+ (document . ess-julia-get-object-help-string))
+ "Auto-completion source for julia objects.")
+
+(defun ess-ac-julia-objects ()
+ (require 'auto-complete)
+ (ess-julia-objects ac-prefix))
+
+(declare-function company-begin-backend "company.el")
+
+(defun company-ess-julia-objects (command &optional arg &rest _ignored)
+ (interactive (list 'interactive))
+ (cl-case command
+ (interactive (company-begin-backend 'company-ess-julia-objects))
+ (prefix (unless (company-in-string-or-comment)
+ (let ((start (ess-symbol-start)))
+ (when start (buffer-substring-no-properties start (point))))))
+ (candidates (let ((proc (ess-get-next-available-process)))
+ (when proc
+ (all-completions arg (mapcar (lambda (x) (or (car-safe x) x))
+ (ess-julia-objects arg proc))))))
+ (doc-buffer (company-doc-buffer (ess-julia-get-object-help-string arg)))))
+
+\f
+;;; ERRORS
+(defvar ess-julia-error-regexp-alist '(ess-julia-in ess-julia-at ess-julia-while-load)
+ "List of symbols which are looked up in `compilation-error-regexp-alist-alist'.")
+
+(add-to-list 'compilation-error-regexp-alist-alist
+ '(ess-julia-in "^\\s-*in [^ \t\n]* \\(at \\(.*\\):\\([0-9]+\\)\\)" 2 3 nil 2 1))
+(add-to-list 'compilation-error-regexp-alist-alist
+ '(ess-julia-at "^\\S-+\\s-+\\(at \\(.*\\):\\([0-9]+\\)\\)" 2 3 nil 2 1))
+(add-to-list 'compilation-error-regexp-alist-alist
+ '(ess-julia-while-load "^\\s-*\\(while loading\\s-\\(.*\\), in .* on line +\\([0-9]+\\)\\)" 2 3 nil 2 1))
+
+\f
+;;; ELDOC
+(defun ess-julia-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. Honors `eldoc-echo-area-use-multiline-p'."
+ (when (and (ess-can-eval-in-background)
+ (ess-process-live-p)
+ (not (ess-process-get 'busy)))
+ (let ((funname (or (and ess-eldoc-show-on-symbol ;; aggressive completion
+ (symbol-name (ess-symbol-at-point)))
+ (car (ess--fn-name-start))))
+ (multiline (eq t eldoc-echo-area-use-multiline-p)))
+ (when funname
+ (let* ((args (copy-sequence (nth 2 (ess-function-arguments funname))))
+ (W (- (window-width (minibuffer-window)) (+ 4 (length funname))))
+ (doc (concat (propertize funname 'face font-lock-function-name-face) ": ")))
+ (when args
+ (setq args (sort args (lambda (s1 s2)
+ (< (length s1) (length s2)))))
+ (setq doc (concat doc (pop args)))
+ (while (and args (or multiline (< (+ (length doc) (length (car args))) W)))
+ (setq doc (concat doc " " (pop args))))
+ (when (and args (< (length doc) W))
+ (setq doc (concat doc " {--}")))
+ doc))))))
+
+\f
+;;; CORE
+(defvar ess-julia-customize-alist
+ '((inferior-ess-primary-prompt . "\\w*> ")
+ (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=<file>. 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
--- /dev/null
+;;; ess-mode.el -- Emacs Speaks Statistics root mode. -*- lexical-binding: t; -*-
+
+;; Copyright (C) 1994-2022 Free Software Foundation, Inc.
+;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
+
+;; 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
+;; <http://www.gnu.org/licenses/>
+
+;;; 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-<up>") #'ess-eval-buffer-from-beg-to-here)
+ (define-key map (kbd "C-c C-<down>") #'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 <tabs> 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"))
+
+\f
+;;; 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))))
+
+\f
+;;; 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))
+
+\f
+;;; 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))))
+
+\f
+;;; 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
--- /dev/null
+(define-package "ess" "20230419.1527" "Emacs Speaks Statistics"
+ '((emacs "25.1"))
+ :commit "5c4ae91cefa5c56fd13b204a9a996825af836a67" :authors
+ '(("David Smith" . "dsmithNOSPAMstats.adelaide.edu.au")
+ ("A.J. Rossini" . "blindglobeNOSPAMgmail.com")
+ ("Richard M. Heiberger" . "rmh@temple.edu")
+ ("Kurt Hornik" . "Kurt.HornikNOSPAMR-project.org")
+ ("Martin Maechler" . "maechlerNOSPAMstat.math.ethz.ch")
+ ("Rodney A. Sparapani" . "rsparapaNOSPAMmcw.edu")
+ ("Stephen Eglen" . "stephenNOSPAMgnu.org")
+ ("Sebastian P. Luque" . "spluqueNOSPAMgmail.com")
+ ("Henning Redestig" . "henning.redNOSPAMgooglemail.com")
+ ("Vitalie Spinu" . "spinuvitNOSPAMgmail.com")
+ ("Lionel Henry" . "lionel.hryNOSPAMgmail.com")
+ ("J. Alexander Branham" . "alex.branhamNOSPAMgmail.com"))
+ :maintainers
+ '(("ESS Core Team" . "ESS-coreNOSPAMr-project.org"))
+ :maintainer
+ '("ESS Core Team" . "ESS-coreNOSPAMr-project.org")
+ :url "https://ess.r-project.org/")
+;; Local Variables:
+;; no-byte-compile: t
+;; End:
--- /dev/null
+;;; ess-r-completion.el --- R completion -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2015-2022 Free Software Foundation, Inc.
+;; Author: Vitalie Spinu
+;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
+
+;; 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
+;; <http://www.gnu.org/licenses/>
+
+;;; 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)
+
+\f
+;;;*;;; 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))))
+
+\f
+;;;*;;; 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)))))
+
+\f
+;;;*;;; 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.")
+
+\f
+;;;*;;; 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)))))))
+
+\f
+;;;*;;; 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 "<pkg>")
+ (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 (_) " <pkg>"))))
+
+\f
+;;;*;;; 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
--- /dev/null
+;;; ess-r-flymake.el --- A ess-r Flymake backend -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2018-2022 Free Software Foundation, Inc.
+;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
+
+
+;; 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
+;; <http://www.gnu.org/licenses/>
+
+;;; 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 "<text>:"
+ ;; 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
--- /dev/null
+;;; 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 <ESS-coreNOSPAMr-project.org>
+
+;; 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
+;; <http://www.gnu.org/licenses/>
+
+;;; 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)
+
+
+\f
+;;*;; 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 "\ 4" #'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 "\ 2" #'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))
+
+\f
+;;;*;;; 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))))
+
+
+\f
+;;*;; 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"))
+
+\f
+;;*;; 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('\1e\1eESSR::ERROR \"', conditionMessage(cnd), '\"\1e\1e')
+ 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 \f
+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))
+
+\f
+;;*;; 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))))
+
+\f
+
+;;;*;;; 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))
+
+
+\f
+;;;*;;; 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)))
+
+\f
+
+;; 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
--- /dev/null
+;;; 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 <ESS-core@r-project.org>
+
+;; 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
+;; <http://www.gnu.org/licenses/>
+
+;;; 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.")
+
+\f
+;;;*;;; 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))))))
+
+\f
+;;;*;;; 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"))))
+
+\f
+;;;*;;; 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))))
+
+\f
+;;;*;;; 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: ")))))
+
+\f
+;;;*;;; 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)
+
+\f
+;;;*;;; 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)
+
+\f
+;;;*;;; 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")
+
+\f
+(provide 'ess-r-package)
+
+;;; ess-r-package.el ends here
--- /dev/null
+;;; ess-r-syntax.el --- Utils to work with R code -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2015-2022 Free Software Foundation, Inc.
+;; Author: Lionel Henry <lionel.hryNOSPAMgmail.com>
+;; Created: 12 Oct 2015
+;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
+
+;; 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
+;; <http://www.gnu.org/licenses/>
+
+;;; Commentary:
+
+;; API is not yet stable.
+
+;;; Code:
+
+(require 'ess-utils)
+(require 'regexp-opt)
+
+(eval-when-compile
+ (require 'cl-lib))
+
+\f
+;;*;; 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))))
+
+\f
+;;*;; 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)))
+
+\f
+;;*;; 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))))))
+
+\f
+;;;*;;; 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))))))
+
+\f
+;;;*;;; 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))))
+
+\f
+;;;*;;; 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))
+
+\f
+;;;*;;; 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)))))
+
+\f
+;;;*;;; 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)))))
+
+\f
+;;;*;;; 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
--- /dev/null
+;;; 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 <ESS-coreNOSPAMr-project.org>
+
+;; 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
+;; <http://www.gnu.org/licenses/>
+
+;;; 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
--- /dev/null
+;; ess-rd.el --- Support for editing R documentation (Rd) source -*- lexical-binding: t; -*-
+
+;; Copyright (C) 1997-2022 Free Software Foundation, Inc.
+;; Author: KH <Kurt.HornikNOSPAMci.tuwien.ac.at>
+;; Created: 25 July 1997
+;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
+
+;; 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
+;; <http://www.gnu.org/licenses/>
+
+;;; 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" "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 <R>/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-reference-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
--- /dev/null
+;;; 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 <stephenNOSPAManc.ed.ac.uk>
+;; Created: Thu 24 Oct 2002
+;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
+
+;; 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
+;; <http://www.gnu.org/licenses/>
+
+;;; 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
--- /dev/null
+;;; ess-roxy.el --- convenient editing of in-code roxygen documentation -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2009-2022 Free Software Foundation, Inc.
+;; Author: Henning Redestig <henning.red * go0glemail c-m>
+
+;; 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
+;; <http://www.gnu.org/licenses/>
+
+;;; 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.")
+
+\f
+;;*;; 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)))
+
+
+\f
+;;*;; 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)
+
+\f
+;;*;; 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)))
+
+\f
+;;*;; 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
--- /dev/null
+;;; 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 <rossiniNOSPAMbiostat.washington.edu>
+;; Created: 26 Aug 1997
+;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
+
+;; 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
+;; <http://www.gnu.org/licenses/>
+
+;;; 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))
+
+\f ; 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 <dialect>-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.")
+
+\f ; 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]\\)\\(<<?-\\)" "\\1 \\2" nil nil verbose)
+ (goto-char from)(ess-rep-regexp "<-\\([^ \t\n]\\)" "<- \\1" nil nil verbose)
+ ;; ensure space around "<" (not in "<-","<=","<<-") and ">" (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"))
+
+
+\f ;;; 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
--- /dev/null
+;;; 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-coreNOSPAMr-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
+;; <http://www.gnu.org/licenses/>
+
+;;; 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\\|\f\\|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
--- /dev/null
+;;; ess-sas-d.el --- SAS customization -*- lexical-binding: t; -*-
+
+;; Copyright (C) 1997-2022 Free Software Foundation, Inc.
+;; Author: Richard M. Heiberger <rmhNOSPAMtemple.edu>
+;; Created: 20 Aug 1997
+;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
+
+;; 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
+;; <http://www.gnu.org/licenses/>
+
+;;; 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))
+
+\f ; Provide package
+
+(provide 'ess-sas-d)
+
+;;; ess-sas-d.el ends here
--- /dev/null
+;;; 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 <ESS-coreNOSPAMr-project.org>
+
+;; 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
+;; <http://www.gnu.org/licenses/>
+
+;;; 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
+;;; cookNOSPAMbiostat.wisc.edu
+;;;
+;;; Acknowledgements:
+;;; Menu code for XEmacs/Lucid emacs and startup mods
+;;; contributed by arossiniNOSPAMbiostats.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 "\\<and(" font-lock-function-name-face)
+ (cons "\\<data=" font-lock-keyword-face)
+ (cons "\\<in:(" font-lock-function-name-face)
+ (cons "\\<index(" font-lock-function-name-face)
+ (cons "\\<input(" font-lock-function-name-face)
+ (cons "\\<libname(" font-lock-function-name-face)
+ (cons "\\<not(" font-lock-function-name-face)
+ (cons "\\<or(" font-lock-function-name-face)
+ (cons "\\<put(" font-lock-function-name-face)
+ (cons "\\<sum(" font-lock-function-name-face)
+
+ ; other idiosyncratic keywords
+ ;(cons "key=" font-lock-keyword-face)
+ ;(cons "/unique" font-lock-keyword-face)
+
+ ;; SAS execution blocks: DATA, %MACRO/%MEND, %DO/%END, etc.
+ (cons (regexp-opt '(
+ "data" "start" "return" ;"proc"
+ "%macro" "%mend"
+ "%do" "%to" "%by" "%end"
+ "%goto" "%go to"
+ "%if" "%then" "%else"
+ "%global" "%inc" "%include" "%input" "%local" "%let" "%put" "%sysexec"
+ ) 'words) font-lock-constant-face)
+
+ ;; SAS execution blocks that must be followed by a semi-colon
+ (cons (concat "\\<"
+ (regexp-opt
+ '(
+ "run;" "quit;" "endsas;" "finish;"
+ "cards;" "cards4;" "datalines;" "datalines4;" "lines;" "lines4;"
+ )))
+ font-lock-constant-face)
+
+ ;; SAS statements that must be followed by a semi-colon
+ (cons (concat "\\<"
+ (regexp-opt
+ '(
+ "end;" "list;" "lostcard;" "page;" "stop;" ;"return;"
+ )))
+ font-lock-keyword-face)
+
+ ;; SAS statements that must be followed by an equal sign
+ (cons (concat "\\<"
+ (regexp-opt
+ '(
+ "compress=" "in=" "out=" "sortedby="
+ )))
+ font-lock-keyword-face)
+
+;;; ;; SAS procedure names
+ (cons (concat "\\<proc[ ]+"
+ (regexp-opt '(
+ ;; SAS base and SAS/Graph
+ "append"
+ "calendar" "catalog" "chart" "cimport" "cport" "compare" "contents" "copy" "corr"
+ "datasets" "dbcstab" "display"
+ "explode" "export"
+ "fcmp" "format" "forms" "freq" "fsbrowse" "fsedit" "fsletter" "fslist" "fsview"
+ "ganno" "gchart" "gcontour" "gdevice" "geocode" "gfont" "gimport" "ginside"
+ "gkeymap" "gmap" "goptions" "gplot" "gprint" "gproject" "greduce" "gremove"
+ "greplay" "gslide" "gtestit" "g3d" "g3grid"
+ "iml" "import" "insight"
+ "mapimport" "means"
+ "options"
+ "plot" "pmenu" "print" "printto"
+ "rank" "registry" "report"
+ "setinit" "sgdesign" "sgmap"
+ "sgpanel" "sgplot" "sgrender" "sgscatter" "sort" "sql" "standard" "summary"
+ "tabulate" "template" "timeplot" "transpose" "trantab"
+ "univariate"
+
+ ;;SAS/Stat and SAS/ETS
+ "aceclus" "anova" "arima" "autoreg"
+ "bgenmod" "blifereg" "boxplot" "bphreg"
+ "calis" "cancorr" "candisc" "catmod" "citibase" "cluster" "computab" "corresp" "countreg"
+ "discrim" "distance"
+ "entropy" "expand"
+ "factor" "fastclus" "forecast"
+ "gam" "gee" "genmod" "glimmix" "glm" "glmmod" "glmpower" "glmselect"
+ "hpmixed"
+ "inbreed"
+ "kde" "krige2d"
+ "lattice" "lifereg" "lifetest" "loess" "logistic"
+ "mcmc" "mdc" "mds" "mi" "mianalyze" "mixed" "modeclus" "model" "mortgage" "multtest"
+ "nested" "nlin" "nlmixed" "npar1way"
+ "orthoreg"
+ "panel" "pdlreg" "phreg" "plan" "plm" "pls" "power" "princomp" "prinqual" "probit"
+ "qlim" "quantreg"
+ "reg" "risk" "robustreg" "rsreg"
+ "score" "seqdesign" "seqtest" "severity" "sim2d" "similarity" "simlin" "simnormal"
+ "spectra" "statespace" "stdize" "stepdisc"
+ "surveyfreq" "surveylogistic" "surveymeans" "surveyphreg" "surveyreg" "surveyselect" "syslin"
+ "tcalis" "timeid" "timeseries" "tphreg" "tpspline" "transreg" "tree" "ttest"
+ "ucm"
+ "varclus" "varcomp" "variogram" "varmax"
+ "x11" "x12"
+ ) 'words)) font-lock-constant-face)
+
+ ; (cons (concat
+ ; "\\<"
+ ; "do[ \t]*" (regexp-opt '("over" "until" "while") t) "?"
+ ; "\\>")
+ ; 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 "\\<call[ \t]+[a-z]+(" font-lock-function-name-face)
+
+ (cons (concat ;"\\<"
+ (regexp-opt
+ '(
+ "abs" "arcos" "arsin" "atan"
+ "betainv" "byte"
+ "call execute" "call label" "call module" "call modulei"
+ "call poke" "call ranbin" "call rancau" "call ranexp"
+ "call rangam" "call rannor" "call ranpoi" "call rantbl"
+ "call rantri" "call ranuni" "call rxchange" "call rxfree"
+ "call rxsubstr" "call set" "call streaminit" "call symput" "call system"
+ "cdf" "ceil" "cinv" "collate" "compress" "convx" "convxp" "cos" "cosh" "css" "cv"
+ "daccdb" "daccdbsl" "daccsl" "daccsyd" "dacctab"
+ "depdb" "depdbsl" "depsl" "depsyd" "deptab"
+ "date" "datejul" "datepart" "datetime" "day" "dhms" "dif" "digamma" "dim"
+ "erf" "erfc" "exp"
+ "finv" "fipname" "fipnamel" "fipstate" "floor" "fuzz"
+ "gaminv" "gamma"
+ "hbound" "hms" "hour"
+ "in" "index" "indexc" "input" "int" "intck" "intnx" "intrr" "irr"
+ "juldate"
+ "kurtosis"
+ "lag" "lbound" "left" "length" "lgamma" "log" "log10" "log2"
+ "logcdf" "logpdf" "logsdf"
+ "max" "mdy" "mean" "min" "minute" "mod" "month" "mort"
+ "n" "netpv" "nmiss" "normal" "npv"
+ "ordinal"
+ "pdf"
+ "probbeta" "probbnml" "probchi" "probf" "probgam" "probhypr" "probit" "probnegb" "probnorm" "probt"
+ "poisson" "put"
+ "qtr" "quantile"
+ "rand" "range" "rank" "repeat" "reverse" "right" "round" "rxmatch" "rxparse"
+ "ranbin" "rancau" "ranexp" "rangam" "rannor" "ranpoi" "rantbl" "rantri" "ranuni"
+ "saving" "scan" "sdf" "second" "sign" "sin" "sinh" "sqrt" "squantile"
+ "std" "stderr" "stfips" "stname" "stnamel" "substr" "sum" "symget"
+ "tan" "tanh" "time" "timepart" "tinv" "today" "translate" "trigamma" "trim" "trunc"
+ "uniform" "until" "upcase" "uss"
+ "var" "verify"
+ "weekday" "when" "while"
+ "year" "yyq"
+ "zipfips" "zipname" "zipnamel" "zipstate"
+
+;;; ;; SAS/IML functions
+ "all" "allcomb" "allperm" "any" "apply" "armasim"
+ "bin" "blankstr" "block" "branks" "bspline" "btran" "byte"
+ "char" "choose" "col" "colvec" "concat" "contents" "convexit" "corr" "corr2cov"
+ "countmiss" "countn" "countunique" "cov" "cov2corr" "covlag" "cshape" "cusum"
+ "cuprod" "cv" "cvexhull"
+ "datasets" "design" "designf" "det" "diag" "dimension" "distance" "do" "duration"
+ "echelon" "eigval" "eigvec" "expmatrix" "expandgrid"
+ "fft" "fftc" "forward" "froot" "full"
+ "gasetup" "geomean" "ginv"
+ "hadamard" "half" "hankel" "harmean" "hdir" "hermite" "homogen"
+ "i" "ifft" "ifftc" "importtablefromr" "insert" "inv" "invupdt" "isempty" "isskipped"
+ "j" "jroot"
+ "kurtosis"
+ "lambertw" "listgetallnames" "listgetitem" "listgetname" "listgetsubitem" "listindex"
+ "listlen" "loc" "logabsdet"
+ "mad" "magic" "mahalanobis" "moduleic" "modulein"
+ "name" "ncol" "nrow" "ndx2sub" "nleng" "norm" "num"
+ "opscal" "orpol"
+ "parentname" "palette" "polyroot" "prod" "product" "pv"
+ "quartile"
+ "rancomb" "randdirichlet" "randfun" "randmultinomial" "randmvt" "randnormal" "randwishart"
+ "ranperk" "ranperm" "ranktie" "rates" "ratio" "remove" "repeat" "root" "row"
+ "rowcat" "rowcatc" "rowvec" "rsubstr"
+ "sample" "setdif" "shape" "shapecol" "skewness" "solve" "sparse" "splinev" "spot"
+ "sqrsym" "sqrvech" "ssq" "standard" "storage" "sub2ndx" "sweep" "symsqr"
+ "t" "tablecreate" "tablecreatefromdataset" "tablegetvardata" "tablegetvarformat"
+ "tablegetvarindex" "tablegetvarinformat" "tablegetvarlabel" "tablegetvarname"
+ "tablegetvartype" "tableisexistingvar" "tableisvarnumeric" "tfhilbert" "tfpwv"
+ "tfstft" "tfwindow" "toeplitz" "trace" "trisolv" "type"
+ "union" "unique" "uniqueby"
+ "value" "vecdiag" "vech"
+ "xmult" "xsect"
+ "yield"
+
+;;; ;; SAS functions introduced in Technical Report P-222
+ "airy"
+ "band" "blshift" "brshift" "bnot" "bor" "bxor"
+ "cnonct" "compbl"
+ "dairy" "dequote"
+ "fnonct"
+ "ibessel" "indexw" "inputc" "inputn"
+ "jbessel"
+ "lowcase"
+ "putc" "putn"
+ "quote"
+ "resolve"
+ "soundex" "sysprod"
+ "tnonct" "tranwrd" "trimn"
+
+;;; ;; SCL functions that are known to work with SAS macro function %sysfunc
+ "attrc" "attrn"
+ "cexist" "close"
+ "dclose" "dnum" "dopen" "dread"
+ "exist"
+ "fclose" "fetchobs" "fileexist" "finfo" "fopen" "fput" "fwrite"
+ "getoption" "getvarc" "getvarn"
+ "libname" "libref"
+ "open" "optgetn" "optsetn"
+ "pathname"
+ "sysmsg"
+ "varfmt" "varlabel" "varnum" "vartype"
+ ) 'words) ;"\\>"
+ "("); "[ \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 "\\<call[ \t]+[a-z_][a-z_0-9]*[ \t]*("
+ font-lock-function-name-face)
+
+ (cons (concat
+ "\\<"
+ "\\(a\\(bs\\|r\\(cos\\|sin\\)\\|tan\\)\\|b\\(etainv\\|yte\\)"
+ "\\|c\\(eil\\|inv\\|o\\(llate\\|mpress\\|sh?\\)\\|ss\\|v\\)"
+ "\\|dacc\\(db\\(\\|sl\\)\\|s\\(l\\|yd\\)\\|tab\\)"
+ "\\|dep\\(db\\(\\|sl\\)\\|s\\(l\\|yd\\)\\|tab\\)"
+ "\\|d\\(a\\(te\\(\\|jul\\|part\\|time\\)\\|y\\)\\|hms\\|i\\(f[0-9]*\\|m\\|gamma\\)\\)"
+ "\\|e\\(rfc?\\|xp\\)"
+ "\\|f\\(i\\(nv\\|p\\(namel?\\|state\\)\\)\\|loor\\|uzz\\)\\|gam\\(inv\\|ma\\)"
+ "\\|h\\(bound\\|ms\\|our\\)\\|i\\(n\\(dexc?\\|put\\|t\\(\\|ck\\|nx\\|rr\\)\\)\\|rr\\)"
+ "\\|juldate\\|kurtosis\\|l\\(ag[0-9]*\\|bound\\|e\\(ft\\|ngth\\)\\|gamma\\|og\\(\\|10\\|2\\)\\)"
+ "\\|m\\(ax\\|dy\\|ean\\|in\\(\\|ute\\)\\|o\\(d\\|nth\\|rt\\)\\)"
+ "\\|n\\(\\|etpv\\|miss\\|o\\(rmal\\|t\\)\\|pv\\)"
+ "\\|prob\\([ft]\\|b\\(eta\\|nml\\)\\|chi\\|gam\\|hypr\\|it\\|n\\(egb\\|orm\\)\\)"
+ "\\|ordinal\\|p\\(oisson\\|ut\\)\\|qtr\\|r\\(e\\(peat\\|verse\\)\\|ight\\|ound\\)"
+ "\\|ran\\(bin\\|cau\\|exp\\|g\\(am\\|e\\)\\|k\\|nor\\|poi\\|t\\(bl\\|ri\\)\\|uni\\)"
+ "\\|s\\(aving\\|can\\|econd\\|i\\(gn\\|nh?\\)\\|qrt\\|t\\(d\\(\\|err\\)\\|fips\\|namel?\\)\\|u\\(bstr\\|m\\)\\|ymget\\)"
+ "\\|t\\(anh?\\|i\\(me\\(\\|part\\)\\|nv\\)\\|oday\\|r\\(anslate\\|i\\(gamma\\|m\\)\\|unc\\)\\)"
+ "\\|u\\(niform\\|pcase\\|ss\\)\\|v\\(ar\\|erify\\)"
+ "\\|weekday\\|y\\(ear\\|yq\\)\\|zip\\(fips\\|namel?\\|state\\)"
+
+;;; ;; SAS functions introduced in Technical Report P-222
+
+ "\\|airy\\|b\\(and\\|lshift\\|not\\|or\\|rshift\\|xor\\)"
+ "\\|c\\(nonct\\|ompbl\\)\\|d\\(airy\\|equote\\)\\|fnonct\\|tnonct"
+ "\\|i\\(bessel\\|n\\(dexw\\|put[cn]\\)\\)\\|jbessel\\|put[cn]"
+ "\\|lowcase\\|quote\\|resolve\\|s\\(oundex\\|ysprod\\)\\|tr\\(anwrd\\|imn\\)"
+
+;;; ;; IML functions that are not also Datastep functions
+ "\\|a\\(ll\\|ny\\|pply\\|rmasim\\)\\|b\\(lock\\|ranks\\|tran\\)"
+ "\\|c\\(har\\|hoose\\|on\\(cat\\|tents\\|vexit\\|vmod\\)\\|ovlag\\|shape\\|usum\\|vexhull\\)"
+ "\\|d\\(atasets\\|esignf?\\|et\\|iag\\|o\\|uration\\)"
+ "\\|e\\(chelon\\|igv\\(al\\|ec\\)\\)\\|f\\(ft\\|orward\\)\\|ginv"
+ "\\|h\\(alf\\|ankel\\|dir\\|ermite\\|omogen\\)"
+ "\\|i\\(\\|fft\\|nsert\\|nv\\(updt\\)?\\)\\|j\\(\\|root\\)\\|loc\\|mad"
+ "\\|n\\(ame\\|col\\|leng\\|row\\|um\\)\\|o\\(pscal\\|rpol\\)"
+ "\\|p\\(olyroot\\|roduct\\|v\\)\\|r\\(anktie\\|ates\\|atio\\|emove\\|eturn\\|oot\\|owcatc?\\)"
+ "\\|s\\(etdif\\|hape\\|olve\\|plinev\\|pot\\|qrsym\\|ssq\\|torage\\|weep\\|ymsqr\\)"
+ "\\|t\\(\\|eigv\\(al\\|ec\\)\\|oeplitz\\|race\\|risolv\\|ype\\)"
+ "\\|uni\\(on\\|que\\)\\|v\\(alue\\|ecdiag\\)\\|x\\(mult\\|sect\\)\\|yield"
+
+;;; ;; SCL functions that are known to work with SAS macro function %sysfunc
+
+ "\\|attr[cn]\\|c\\(exist\\|lose\\)\\|d\\(close\\|num\\|open\\|read\\)"
+ "\\|exist\\|f\\(close\\|etchobs\\|i\\(leexist\\|nfo\\)\\|open\\|put\\|write\\)"
+ "\\|get\\(option\\|var[cn]\\)\\|lib\\(name\\|ref\\)\\|op\\(en\\|t\\(getn\\|setn\\)\\)"
+ "\\|pathname\\|sysmsg\\|var\\(fmt\\|l\\(abel\\|en\\)\\|n\\(ame\\|um\\)\\|type\\)\\)"
+ "[ \t]*(") font-lock-function-name-face)
+ ))
+ "Font Lock regexs for SAS.")
+
+(defun beginning-of-sas-statement (arg &optional comstart)
+ "Move point to beginning of current sas statement."
+ (interactive "P")
+ (let ((pos (point))
+ )
+ (if (search-forward ";" nil 1) (forward-char -1))
+ (re-search-backward ";[ \n*/]*$" (point-min) 1 arg)
+ (skip-chars-forward sas-comment-chars)
+ (if comstart nil
+ (if (looking-at "\\*/")
+ (progn (forward-char 2)
+ (skip-chars-forward sas-comment-chars)))
+ (while (looking-at "/\\*")
+ (if (not (search-forward "*/" pos t 1)) ;;(;; (point-max) 1 1)
+ (forward-char 2))
+ (skip-chars-forward sas-white-chars)))))
+
+(defun sas-indent-line ()
+ "Indent function for SAS mode."
+ (interactive)
+ (let (indent prev-end
+ (pos (- (point-max) (point)))
+ (case-fold-search t)
+ (cur-ind (current-indentation))
+ (comment-col (sas-comment-start-col))) ;; 2/1/95 TDC
+ (save-excursion
+ (cond ((progn
+ (back-to-indentation)
+ (or (bobp)
+ (looking-at
+ "data[ ;]\\|proc[ ;]\\|run[ ;]\\|quit[ ;]\\|endsas[ ;]\\|g?options[ ;]\\|%macro[ ;]\\|%mend[ ;]")))
+ ;; Case where current statement is DATA, PROC, etc...
+ (setq prev-end (point))
+ (goto-char (point-min))
+ ;; Added 6/27/94
+ ;; May get fooled if %MACRO, %DO, etc embedded in comments
+ (setq indent
+ (+ (* (- (sas-how-many "^[ \t]*%macro\\|[ \t]+%do"
+ prev-end)
+ (sas-how-many "^[ \t]*%mend\\|%end" prev-end))
+ sas-indent-width) comment-col))) ;; 2/1/95 TDC
+ ;; Case where current line begins with sas-indent-ignore-comment
+ ;; added 6/27/94 to leave "* ;" comments alone.
+ ((progn
+ (back-to-indentation)
+ (and (not (looking-at "\\*/"))
+ (looking-at (concat sas-indent-ignore-comment "\\|/\\*"))))
+ (setq indent (current-indentation)))
+ ;; Case where current statement not DATA, PROC etc...
+ (t (beginning-of-line 1)
+ (skip-chars-backward sas-white-chars)
+ (if (bobp) nil
+ (backward-char 1))
+ (cond
+ ((looking-at ";") ; modified 1/31/95
+ (setq indent (sas-next-statement-indentation)))
+ ((save-excursion;; added 4/28/94 to properly check
+ (if (bobp) () (backward-char 1));; for end of comment
+ (setq prev-end (point))
+ (looking-at "\\*/"));; improved 1/31/95
+ (save-excursion
+ (search-backward "*/"
+ (point-min) 1 1); comment start is first /*
+ (search-forward "/*"
+ prev-end 1 1) ; after previous */
+ (backward-char 2) ; 2/1/95 TDC
+ (skip-chars-backward sas-white-chars)
+ (setq indent
+ (if (bobp) 0
+ (if (looking-at ";")
+ (sas-next-statement-indentation)
+ ;;(+ (current-indentation) sas-indent-width)
+ (current-indentation))))))
+
+ ;; added 6/27/94 to leave "* ;" comments alone
+ ((save-excursion
+ (progn
+ (beginning-of-sas-statement 1 t)
+ (and (not (looking-at "\\*/"))
+ (looking-at sas-indent-ignore-comment))))
+ (setq indent cur-ind))
+ ((progn
+ (beginning-of-sas-statement 1)
+ (bobp));; added 4/13/94
+ (setq indent sas-indent-width));; so the first line works
+ ((save-excursion
+ (beginning-of-sas-statement 2)
+ (looking-at "cards4?;\\|datalines4?;\\|lines4?;"))
+ (setq indent (current-indentation))) ; So cards keep indentation.
+ (t
+ (if (progn
+ (save-excursion
+ (beginning-of-line 1)
+ (skip-chars-backward sas-white-chars)
+ (if (bobp) nil (backward-char 1))
+ (or (looking-at ";")
+ (bobp) (backward-char 1) (looking-at "\\*/"))))
+ (setq indent (+ (current-indentation) sas-indent-width))
+ (setq indent (current-indentation))))))))
+ (save-excursion
+ (let (beg end)
+ (back-to-indentation)
+ (setq end (point))
+ (beginning-of-line 1)
+ (setq beg (point))
+ (delete-region beg end)
+ (indent-to indent)))
+ (if (> (- (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 ;
+"))))
+
+\f
+;; 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
+\f
+;; 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
--- /dev/null
+;;; ess-site.el --- user customization of ESS -*- lexical-binding: t; -*-
+
+;; Copyright (C) 1993-2020 Free Software Foundation, Inc.
+;; Author: David Smith <D.M.SmithNOSPAMlancaster.ac.uk>
+;; Created: 12 Nov 1993
+;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
+
+;; 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
+;; <http://www.gnu.org/licenses/>
+
+;;; 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
--- /dev/null
+;;; 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 <rossiniNOSPAMu.washington.edu>
+;; Created: 2001/02/06
+;; Maintainer: ESS Core Team <ESS-coreNOSPAMr-project.org>
+
+;; 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
+;; <http://www.gnu.org/licenses/>
+
+;;; 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")
+
+
+
+\f ; Provide package
+
+(provide 'ess-sp6-d)
+
+;;; ess-sp6-d.el ends here
--- /dev/null
+;;; 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 <ESS-coreNOSPAMr-project.org>
+
+;; 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
+;; <http://www.gnu.org/licenses/>
+
+;;; 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
--- /dev/null
+;; 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
+;; <http://www.gnu.org/licenses/>
+
+;;; 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)
+
+
+\f
+;;; MPI
+
+;; http://jkorpela.fi/chars/c0.html
+;; https://en.wikipedia.org/wiki/ANSI_escape_code#Escape_sequences
+(defvar ess-mpi-message-start-delimiter "\e_")
+(defvar ess-mpi-message-field-separator "\1e")
+(defvar ess-mpi-message-end-delimiter "\e\\")
+
+(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 \eTYPE\1eFIELD...\1d 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
--- /dev/null
+;;; ess-trns.el --- Support for manipulating S transcript files -*- lexical-binding: t; -*-
+
+;; Copyright (C) 1989-2020 Free Software Foundation, Inc.
+;; Author: David Smith <dsmithNOSPAMstats.adelaide.edu.au>
+;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
+
+;; 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
+;; <http://www.gnu.org/licenses/>
+
+;;; Commentary:
+
+;; Code for dealing with ESS transcripts.
+
+;;; Code:
+
+\f ; Requires and autoloads
+
+(require 'ess-mode)
+(require 'ess-inf)
+(require 'comint)
+
+(declare-function ess-display-help-on-object "ess-help" (object &optional command))
+
+\f ; 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
--- /dev/null
+;;; ess-utils.el --- General Emacs utility functions used by ESS -*- lexical-binding: t; -*-
+
+;; Copyright (C) 1998-2022 Free Software Foundation, Inc.
+;; Author: Martin Maechler <maechlerNOSPAMstat.math.ethz.ch>
+;; Created: 9 Sept 1998
+;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
+
+;; 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
+;; <http://www.gnu.org/licenses/>
+
+;;; 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")
+
+\f
+;;*;; 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))))
+
+\f
+;;*;; 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))
+
+\f
+;;*;; 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")))))
+
+\f
+;;*;; 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))))))
+
+\f
+;;*;; 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)
+
+\f
+;;*;; 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] \\<ess-mode-map>\\[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!")))))
+
+\f
+;;*;; 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 <iversonNOSPAMbiostat.wisc.edu>
+
+(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")
+
+\f
+;;*;; 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)))
+
+\f
+;;*;; 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))
+
+\f
+;;*;; 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
--- /dev/null
+;;; ess.el --- Emacs Speaks Statistics -*- lexical-binding: t; -*-
+
+;; Copyright (C) 1997-2022 Free Software Foundation, Inc.
+
+;; Author: David Smith <dsmithNOSPAMstats.adelaide.edu.au>
+;; A.J. Rossini <blindglobeNOSPAMgmail.com>
+;; Richard M. Heiberger <rmhNOSPAMtemple.edu>
+;; Kurt Hornik <Kurt.HornikNOSPAMR-project.org>
+;; Martin Maechler <maechlerNOSPAMstat.math.ethz.ch>
+;; Rodney A. Sparapani <rsparapaNOSPAMmcw.edu>
+;; Stephen Eglen <stephenNOSPAMgnu.org>
+;; Sebastian P. Luque <spluqueNOSPAMgmail.com>
+;; Henning Redestig <henning.redNOSPAMgooglemail.com>
+;; Vitalie Spinu <spinuvitNOSPAMgmail.com>
+;; Lionel Henry <lionel.hryNOSPAMgmail.com>
+;; J. Alexander Branham <alex.branhamNOSPAMgmail.com>
+;;
+;; Maintainer: ESS Core Team <ESS-coreNOSPAMr-project.org>
+;; Created: 7 Jan 1994
+;; Version: 18.10.3snapshot
+;; 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
+;; <http://www.gnu.org/licenses/>
+
+;;; 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)
+
+\f
+;; 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(<from source>) 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 "<unknown>"))
+ (concat ess-version " [" ess-revision "]")))
+
+\f
+;;; 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-bugsNOSPAMr-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))))))))
+
+
+\f
+;;; 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'.")
+
+\f
+;;; 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
--- /dev/null
+This is ess.info, produced by makeinfo version 6.7 from ess.texi.
+
+INFO-DIR-SECTION Emacs
+START-INFO-DIR-ENTRY
+* ESS: (ess). Emacs Speaks Statistics (R/S/S+, SAS, BUGS/JAGS and Stata).
+END-INFO-DIR-ENTRY
+
+ESS -- Emacs Speaks Statistics
+******************************
+
+\1f
+File: ess.info, Node: Top, Next: Introduction, Up: (dir)
+
+ESS: Emacs Speaks Statistics
+****************************
+
+ESS version 18.10.3snapshot
+
+ 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.
+
+ 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.
+
+ 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.
+
+* 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::
+
+\1f
+File: ess.info, Node: Introduction, Next: Installation, Prev: Top, Up: Top
+
+1 Introduction to ESS
+*********************
+
+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, _Emacs_ refers to _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
+'ESS[dialect]', where 'dialect' can take values such as 'R', 'SAS', or
+'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 ('iESS'), and are shown in the modeline by 'iESS
+[dialect]'.
+
+ Currently, the documentation contains many references to ''R'' where
+actually any supported (statistics) language is meant, i.e., 'R' could
+also mean 'S' or 'SAS.'
+
+ 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.
+
+ No special knowledge of Emacs is necessary when using R interactively
+under ESS.
+
+ 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
+
+\1f
+File: ess.info, Node: Features, Next: New features, Up: Introduction
+
+1.1 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 <https://www.gnu.org/philosophy/free-sw.html>.
+
+* Menu:
+
+* Current Features::
+
+\1f
+File: ess.info, Node: Current Features, Up: Features
+
+1.1.1 Features Overview
+-----------------------
+
+ * Languages Supported:
+ * S family (R, S, and S+ AKA S-PLUS)
+ * SAS
+ * BUGS/JAGS
+ * Stata
+ * Julia
+ * Editing source code (S family, SAS, BUGS/JAGS, Stata, Julia)
+ * Syntactic indentation and highlighting of source code
+ * Partial evaluation of code
+ * Loading and error-checking of code
+ * Source code revision maintenance
+ * Batch execution (SAS, BUGS/JAGS)
+ * Use of imenu to provide links to appropriate functions
+ * Interacting with the process (S family, SAS, Stata, Julia)
+ * Command-line editing
+ * Searchable Command history
+ * Command-line completion of S family object names and file
+ names
+ * Quick access to object lists and search lists
+ * Transcript recording
+ * Interface to the help system
+ * Transcript manipulation (S family, Stata)
+ * Recording and saving transcript files
+ * Manipulating and editing saved transcripts
+ * Re-evaluating commands from transcript files
+ * Interaction with Help Pages and other Documentation (R)
+ * Fast Navigation
+ * Sending Examples to running ESS process.
+ * Fast Transfer to Further Help Pages
+ * Help File Editing (R)
+ * Syntactic indentation and highlighting of source code.
+ * Sending Examples to running ESS process.
+ * Previewing
+
+ For source code buffers, ESS offers several features:
+
+ * Support for multiple indentation styles R code *Note Indenting::.
+
+ * Facilities for loading and error-checking source files, including a
+ keystroke to jump straight to the position of an error in a source
+ file. *Note Error Checking::.
+
+ * Source code revision maintenance, which allows you to keep historic
+ versions of R source files. *Note Source Files::.
+
+ * Facilities for evaluating R code such as portions of source files,
+ or line-by-line evaluation of files (useful for debugging). *Note
+ Evaluating code::.
+
+ 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:
+
+ * Command-line editing for fixing mistakes in commands before they
+ are entered. *Note Command-line editing::.
+
+ * Searchable command history for recalling previously-submitted
+ commands. *Note Command History::.
+
+ * Command-line completion of both object and file names for quick
+ entry. *Note Completion::.
+
+ * Hot-keys for quick entry of commonly-used commands in 'R' such as
+ 'objects()', and 'search()'. *Note Hot keys::.
+
+ * Transcript recording for a complete record of all the actions in an
+ R session. *Note Transcript::.
+
+ * Interface to the help system, with a specialized mode for viewing R
+ help files. *Note Help::.
+
+ * 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. *Note Edit
+ buffer::.
+
+ Finally, ESS provides features for re-submitting commands from saved
+transcript files, including:
+
+ * Evaluation of previously entered commands, stripping away
+ unnecessary prompts. *Note Transcript resubmit::.
+
+\1f
+File: ess.info, Node: New features, Next: Credits, Prev: Features, Up: Introduction
+
+1.2 New features in ESS
+=======================
+
+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
+ <language>-mode-hook and <language>-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 <https://github.com/polymode/poly-R/>,
+ <https://polymode.github.io/>, or markdown-mode with edit-indirect
+ <https://jblevins.org/projects/markdown-mode>.
+
+ * 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" <ess-config-here>)' 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
+
+\1f
+File: ess.info, Node: Credits, Next: Manual, Prev: New features, Up: Introduction
+
+1.3 Authors of and contributors to ESS
+======================================
+
+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.
+
+ * The multiple process code, and the idea for
+ 'ess-eval-line-and-next-line' are by Rod Ball.
+
+ * Thanks to Doug Bates for many useful suggestions.
+
+ * Thanks to Martin Maechler for reporting and fixing bugs, providing
+ many useful comments and suggestions, and for maintaining the ESS
+ mailing lists.
+
+ * Thanks to Frank Ritter for updates, particularly the menu code, and
+ invaluable comments on the manual.
+
+ * Thanks to Ken'ichi Shibayama for his excellent indenting code, and
+ many comments and suggestions.
+
+ * Thanks to Aki Vehtari for adding interactive BUGS support.
+
+ * Thanks to Brendan Halpin for bug-fixes and updates to Stata-mode.
+
+ * Last, but definitely not least, thanks to the many ESS users and
+ contributors to the ESS mailing lists.
+
+ _ESS_ is being developed and currently maintained by
+
+ * A.J. Rossini (mailto:blindglobeNOSPAMgmail.com)
+ * Richard M. Heiberger (mailto:rmhNOSPAMtemple.edu)
+ * Kurt Hornik (mailto:Kurt.HornikNOSPAMR-project.org)
+ * Martin Maechler (mailto:maechlerNOSPAMstat.math.ethz.ch)
+ * Rodney A. Sparapani (mailto:rsparapaNOSPAMmcw.edu)
+ * Stephen Eglen (mailto:stephenNOSPAMgnu.org)
+ * Sebastian P. Luque (mailto:spluqueNOSPAMgmail.com)
+ * Henning Redestig (mailto:henning.redNOSPAMgooglemail.com)
+ * Vitalie Spinu (mailto:spinuvitNOSPAMgmail.com)
+ * Lionel Henry (mailto:lionel.hryNOSPAMgmail.com)
+ * J. Alexander Branham (mailto:alex.branhamNOSPAMgmail.com)
+
+\1f
+File: ess.info, Node: Manual, Prev: Credits, Up: Introduction
+
+1.4 How to read this manual
+===========================
+
+If you need to install ESS, read *note 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 'C-h t'.
+
+ In this manual we use the standard notation used by Emacs for
+describing the keystrokes used to invoke certain commands. 'C-<chr>'
+means hold the CONTROL key while typing the character <chr>. 'M-<chr>'
+means hold the META key (usually ALT) down while typing <chr>. If there
+is no META, EDIT or ALT key, instead press and release the ESC key and
+then type <chr>.
+
+ All ESS commands can be invoked by typing '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 'M-x R' can accept an optional 'prefix'
+argument. To specify the prefix argument, you would type 'C-u' before
+giving the command. For example, if you type '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 'C-h f'. For example, if you type 'C-h f
+ess-eval-region', documentation for that command will appear in a
+separate *Help* buffer. Second, '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
+'M-x customize-group RET ess RET' to get started. *note 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.
+
+\1f
+File: ess.info, Node: Installation, Next: Interactive ESS, Prev: Introduction, Up: Top
+
+2 Installing ESS on your system
+*******************************
+
+ESS 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.
+
+ 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 *note Activating and Loading ESS:: for more details.
+
+* Menu:
+
+* Installing from a third-party repository::
+* Installing from source::
+* Activating and Loading ESS::
+* Check Installation::
+
+\1f
+File: ess.info, Node: Installing from a third-party repository, Next: Installing from source
+
+2.1 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 MELPA's website (https://melpa.org/).
+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 *note Activating and Loading ESS::.
+Depending on install method, this may be taken care of automatically.
+
+\1f
+File: ess.info, Node: Installing from source, Next: Activating and Loading ESS, Prev: Installing from a third-party repository
+
+2.2 Installing from source
+==========================
+
+Stable versions of ESS are available at the ESS web page
+(https://ess.r-project.org) as a .tgz file or .zip file. ESS releases
+are GPG-signed, you should check the signature by downloading the
+accompanying '.sig' file and doing:
+
+ gpg --verify ess-18.10.tgz.sig
+
+ Alternatively, you may download the git repository. ESS is currently
+hosted on GitHub: <https://github.com/emacs-ess/ESS>. 'git clone
+https://github.com/emacs-ess/ESS.git' will download it to a new
+directory 'ESS' in the current working directory.
+
+ We will refer to the location of the ESS source files as
+'/path/to/ESS/' hereafter.
+
+ After installing, users should make sure they activate or load ESS in
+each Emacs session, see *note Activating and Loading ESS::
+
+ Optionally, compile Elisp files, build the documentation, and the
+autoloads:
+ cd /path/to/ESS/
+ make
+ 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 'make install'. You might need
+administrative privileges:
+
+ make install
+
+ The files are installed into '/usr/share/emacs' directory. For this
+step to run correctly on macOS, you will need to adjust the 'PREFIX'
+path in 'Makeconf'. The necessary code and instructions are commented
+in that file.
+
+\1f
+File: ess.info, Node: Activating and Loading ESS, Next: Check Installation, Prev: Installing from source
+
+2.3 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 *note Check Installation::
+
+ Otherwise, you may need to add the path to ESS to 'load-path' with:
+
+ (add-to-list 'load-path "/path/to/ESS/lisp")
+
+ 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 'make'):
+
+ (load "ess-autoloads")
+
+ To require ESS on startup, you can either put
+
+ (require 'ess-site)
+
+ or
+
+ (require 'ess-r-mode)
+
+ In your configuration file, depending on whether you want all ESS
+features or only R related features.
+
+\1f
+File: ess.info, Node: Check Installation, Prev: Activating and Loading ESS
+
+2.4 Check Installation
+======================
+
+Restart Emacs and check that ESS was loaded from a correct location with
+'M-x ess-version'.
+
+\1f
+File: ess.info, Node: Interactive ESS, Next: Entering commands, Prev: Installation, Up: Top
+
+3 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::
+
+\1f
+File: ess.info, Node: Starting up, Next: Multiple ESS processes, Up: Interactive ESS
+
+3.1 Starting an ESS process
+===========================
+
+To start an inferior R session on GNU/Linux, macOS, or Windows using the
+Cygwin bash shell, simply type 'M-x R RET'. To start an R session on
+Windows when you use the MSDOS/powershell shell, simply type 'M-x
+S+6-msdos RET'. R will then (by default) ask the question
+
+ R starting data directory?
+
+Enter the name of the directory you wish to have as the working
+directory (that is, the directory you wish to have 'getwd()' return if
+using R).
+
+ You will then be popped into a buffer named '*R*' which will be used
+for interacting with the ESS process, and you can start entering
+commands.
+
+\1f
+File: ess.info, Node: Multiple ESS processes, Next: ESS processes on Remote Computers, Prev: Starting up, Up: Interactive ESS
+
+3.2 Running more than one ESS process
+=====================================
+
+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
+(process 1) is simply named 'R'. If you call 'M-x R' again without
+killing the first R process, ESS will start a second R process with the
+name 'R:2'. To have the first buffer named 'R:1', customize the option
+'ess-plain-first-buffername'. With a prefix argument, 'C-u M-x R'
+allows for the specification of command line options.
+
+ -- User Option: ess-plain-first-buffername
+ If non-'nil', name the first iESS process [R]. Otherwise, name it
+ [R:1].
+
+ You can switch to any active ESS process with the command '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.
+
+\1f
+File: ess.info, Node: ESS processes on Remote Computers, Next: Customizing startup, Prev: Multiple ESS processes, Up: Interactive ESS
+
+3.3 ESS processes on Remote Computers
+=====================================
+
+3.3.1 ESS and TRAMP
+-------------------
+
+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 *Note (tramp)Top::.
+
+ Start an ssh session using TRAMP with '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 ('R', 'Julia', 'stata' etc) as you would
+usually do on local machine: 'M-x R'.
+
+ Alternatively you can start your process normally ('M-x R'). When
+asked for starting directory, simply type '/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
+'.ssh/' folder and add an account. For example if you use amazon EC2,
+it might look like following:
+
+ Host amazon
+ Hostname ec2-54-215-203-181.us-west-1.compute.amazonaws.com
+ User ubuntu
+ IdentityFile ~/.ssh/my_amazon_key.pem
+ ForwardX11 yes
+
+ With this configuration '/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
+
+3.3.2 ESS-remote
+----------------
+
+TRAMP is the recommended way of starting a remote session. The other
+way to start a remote ESS connection is through 'ess-remote'.
+
+ 1. Start a new shell, telnet or ssh buffer and connect to the remote
+ computer (e.g. use, 'M-x shell', 'M-x telnet' or 'M-x ssh'; ssh.el
+ is available at
+ <https://www.splode.com/~friedman/software/emacs-lisp/src/ssh.el>).
+
+ 2. Start the ESS process on the remote machine, for example with one
+ of the commands 'R', 'Splus', or 'sas -stdio'.
+
+ 3. Start '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 ('C-c C-n' and its relatives) now work
+ with the R language processes. For SAS you need to use a different
+ command 'C-c i' (that is a regular 'i', not a 'C-i') to send lines
+ from your 'myfile.sas' to the remote SAS process. 'C-c i' sends
+ lines over invisibly. 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.
+
+ 4. Graphics (interactive) on the remote machine. If you run X11
+ (*Note X11::, X Windows) on both the local and remote machines then
+ you should be able to display the graphs locally by setting the
+ 'DISPLAY' environment variable appropriately. Windows users can
+ download 'xfree86' from cygwin.
+
+ 5. 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 '.gif' and '.jpg' files. Otherwise, a
+ graphics file viewer will be needed. Ghostscript/ghostview may be
+ downloaded to display '.ps' and '.eps' files. Viewers for GIF and
+ JPEG are usually included with operating systems. *Note
+ ESS(SAS)--Function keys for batch processing::, for more
+ information on using the F12 key for displaying graphics files with
+ SAS.
+
+ Should you or a colleague inadvertently start a statistical process
+in an ordinary '*shell*' buffer, the 'ess-remote' command can be used to
+convert it to an ESS buffer and allow you to use the ESS commands with
+it.
+
+\1f
+File: ess.info, Node: Customizing startup, Next: Controlling buffer display, Prev: ESS processes on Remote Computers, Up: Interactive ESS
+
+3.4 Changing the startup actions
+================================
+
+If you do not wish ESS to prompt for a starting directory when starting
+a new process, set the variable 'ess-ask-for-ess-directory' to 'nil'.
+In this case, the starting directory will be set using one of the
+following methods:
+
+ 1. If the variable 'ess-directory-function' stores the name of a
+ function, the value returned by this function is used. The default
+ for this variable is nil.
+
+ 2. Otherwise, if the variable 'ess-directory' stores the name of a
+ directory (ending in a slash), this value is used. The default for
+ this variable is nil.
+
+ 3. Otherwise, the working directory of the current buffer is used.
+
+ If 'ess-ask-for-ess-directory' has a non-'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,
+'ess-directory' is an ideal variable to set in 'ess-pre-run-hook'.
+
+ You may also customize 'ess-post-run-hook' and the dialect-specific
+'ess-*-post-run-hook' variables. For example, you may want to use
+'ess-load-file' to load a file when ESS starts R:
+
+ (add-hook 'ess-r-post-run-hook (lambda () (ess-load-file "foo.R")))
+
+ If you like to keep a record of your R actions, set the variable
+'ess-ask-about-transfile' to 't', and you will be asked for a filename
+for the transcript before the ESS process starts.
+
+ -- User Option: ess-ask-about-transfile
+ If non-'nil', ask for a file name in which to save the session
+ transcript.
+
+ 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 '.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 --
+*note Saving transcripts::.)
+
+ Once these questions are answered (if they are asked at all) the
+inferior process itself is started. If you need to pass any arguments
+to this program, they may be specified in the variable
+'inferior-S_PROGRAM_NAME-args'. For example, if 'inferior-ess-program'
+is '"R"' then the variable to set is 'inferior-R-args'. It is not
+normally necessary to pass arguments to the iESS program; in particular
+do not pass the '-e' option to 'Splus', since ESS provides its own
+command history mechanism.
+
+ ESS can set the width option of inferior processes automatically when
+the window configuration changes. To do so, set '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 'ess-auto-width-visible' to a
+non-nil value.
+
+\1f
+File: ess.info, Node: Controlling buffer display, Prev: Customizing startup, Up: Interactive ESS
+
+3.5 Controlling buffer display
+==============================
+
+Users can control how buffers are displayed by customizing
+'display-buffer-alist', *Note (emacs)Window Choice::. 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; '*R Dired*' would match '*R' if it
+came before in the alist.
+
+ (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))))
+
+ 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
+'reusable-frames', see *Note (elisp)Buffer Display Action Alists::.
+
+ (setq display-buffer-alist
+ '(("^\\*R"
+ (display-buffer-reuse-window display-buffer-pop-up-frame)
+ (reusable-frames . 0))))
+
+ 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. *Note
+(elisp)Dedicated Windows::. For example, this prevents help buffers
+from being displayed in the window showing the inferior R process.
+
+ (setq display-buffer-alist
+ '(("^\\*R"
+ nil
+ (dedicated . t))))
+
+ 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:
+
+ (setq display-buffer-alist
+ '(("^\\*R" . ((display-buffer-same-window) (inhibit-same-window . nil)))
+ ("\\.R$" . ((display-buffer-same-window) (inhibit-same-window . nil)))))
+
+\1f
+File: ess.info, Node: Entering commands, Next: Evaluating code, Prev: Interactive ESS, Up: Top
+
+4 Interacting with the ESS process
+**********************************
+
+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 _inferior_ buffer,
+which has an active 'inferior-ess-mode'. The features of inferior R
+mode are similar to those provided by the standard Emacs shell mode
+(*note (emacs)Shell Mode::). 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
+
+\1f
+File: ess.info, Node: Command-line editing, Next: Transcript, Up: Entering commands
+
+4.1 Entering commands and fixing mistakes
+=========================================
+
+Sending a command to the ESS process is as simple as typing it in and
+pressing the <RETURN> key:
+
+ -- Command: inferior-ess-send-input
+ 'RET' Send the command on the current line to the ESS process.
+
+ If you make a typing error before pressing 'RET' all the usual Emacs
+editing commands are available to correct it (*note Basic:
+(emacs)Basic.). Once the command has been corrected you can press
+<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:
+
+'C-c C-w'
+ 'backward-kill-word' Deletes the previous word (such as an object
+ name) on the command line.
+
+'C-c C-u'
+ '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.
+
+'C-a'
+ 'comint-bol' Move to the beginning of the line, and then skip
+ forwards past the prompt, if any.
+
+ *Note (emacs)Shell Mode::, for other commands relevant to entering
+input.
+
+\1f
+File: ess.info, Node: Transcript, Next: Command History, Prev: Command-line editing, Up: Entering commands
+
+4.2 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 move back up
+through the buffer, to look at the output from previous commands for
+example.
+
+ Within the process buffer, a paragraph is defined as the prompt, the
+command after the prompt, and the output from the command. Thus 'M-{'
+and 'M-}' move you backwards and forwards, respectively, through
+commands in the transcript. A particularly useful command is 'M-h'
+('mark-paragraph') which will allow you to mark a command and its entire
+output (for deletion, perhaps). For more information about paragraph
+commands, *note Paragraphs: (emacs)Paragraphs.
+
+ 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 ('^L') character.
+Thus pages in the ESS process buffer correspond to ESS sessions. Thus,
+for example, you may use 'C-x [' and 'C-x ]' to move backward and
+forwards through ESS sessions in a single ESS process buffer. For more
+information about page commands, *note Pages: (emacs)Pages.
+
+* 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
+
+\1f
+File: ess.info, Node: Last command, Next: Process buffer motion, Up: Transcript
+
+4.2.1 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:
+
+ '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 'comint-scroll-to-bottom-on-input' to 't' or ''this'. If the
+first part of the output is still not visible, use 'C-c C-r'
+('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 'C-c C-o' ('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.
+
+\1f
+File: ess.info, Node: Process buffer motion, Next: Transcript resubmit, Prev: Last command, Up: Transcript
+
+4.2.2 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:
+
+'C-c C-p'
+ 'comint-previous-prompt' Moves point to the preceding prompt in the
+ process buffer.
+
+'C-c C-n'
+ 'comint-next-prompt' Moves point to the next prompt in the process
+ buffer.
+
+Note that these two commands are analogous to 'C-p' and 'C-n' but apply
+to command lines rather than text lines. And just like 'C-p' and 'C-n',
+passing a prefix argument to these commands means to move to the ARG'th
+next (or previous) command. (These commands are also discussed in *note
+Shell History Copying: (emacs)Shell History Copying.)
+
+ 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 (*note Syntax of Regular Expression:
+(emacs)Regexps.), and then moves to the next (previous) command matching
+the pattern.
+
+'comint-backward-matching-input regexp arg'
+'comint-forward-matching-input regexp arg'
+ Search backward (forward) through the transcript buffer for the
+ ARG'th previous (next) command matching REGEXP. ARG is the prefix
+ argument; REGEXP is prompted for in the minibuffer.
+
+\1f
+File: ess.info, Node: Transcript resubmit, Next: Saving transcripts, Prev: Process buffer motion, Up: Transcript
+
+4.2.3 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 _output_, an error is
+signaled). Note all commands involve the <RETURN> key.
+
+'RET'
+ 'inferior-ess-send-input' *Note Command-line editing::.
+
+'C-c RET'
+ '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.
+
+ When the cursor is not after the current prompt, the <RETURN> key has
+a slightly different behavior than usual. Pressing '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 '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 '+' instead of '>') -- 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 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 *note
+Command History::.
+
+\1f
+File: ess.info, Node: Saving transcripts, Prev: Transcript resubmit, Up: Transcript
+
+4.2.4 Keeping a record of your R session
+----------------------------------------
+
+To keep a record of your R session in a disk file, use the Emacs command
+'C-x C-w' ('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 '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 'ess-ask-about-transfile' to
+'t'; *Note Customizing startup::. For R files, naming transcript files
+'*.Rout' puts them in a special mode (ESS transcript mode -- *note
+Transcript Mode::) for editing transcript files which is automatically
+selected for files with this suffix.
+
+ R transcripts can get very large, so some judicious editing is
+appropriate if you are saving it in a file. Use '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
+'M-h C-w'. Also, remember that '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 'ess-transcript-clean-region' to strip output from a
+transcript, leaving only source code suitable for inclusion in files
+'source()'-able from R. *note Transcript Mode: Clean.
+
+\1f
+File: ess.info, Node: Command History, Next: History expansion, Prev: Transcript, Up: Entering commands
+
+4.3 Command History
+===================
+
+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 'comint-input-ring-size' in
+'inferior-ess-mode-hook'.) The simplest history commands simply select
+the next and previous commands in the input history:
+
+'M-p'
+ 'comint-previous-input' Select the previous command in the input
+ history.
+
+'M-n'
+ 'comint-next-input' Select the next command in the input history.
+
+For example, pressing '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 '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 (*note Syntax of Regular
+Expression: (emacs)Regexps.), to search for a particular variable name
+for example, these commands are also available:
+
+'M-r'
+ 'comint-history-isearch-backward-regexp' Prompt for a regular
+ expression, and search backwards through the input history for a
+ command matching the expression.
+
+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:
+
+'C-c M-r'
+ 'comint-previous-matching-input-from-input' Select the previous
+ command in the history which matches the string typed so far.
+
+'C-c M-s'
+ 'comint-next-matching-input-from-input' Select the next command in
+ the history which matches the string typed so far.
+
+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 'attach()' command,
+you may only need to type 'att' and then 'C-c M-r' and 'RET'.
+
+ *Note Shell History Ring: (emacs)Shell Ring, for a more detailed
+discussion of the history mechanism, and do experiment with the 'In/Out'
+menu to explore the possibilities.
+
+ Many ESS users like to have even easier access to these, and
+recommend adding something like
+ (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)
+ ))
+ to your Emacs configuration file, where the last two settings are
+typically desirable for the situation where you work with a script (for
+example, 'code.R') and send code chunks to the process buffer (e.g.
+'*R*'). Note however that these settings influence all 'comint'-using
+Emacs modes, not just the ESS ones, and for that reason, these
+customization cannot be part of 'ESS' itself.
+
+* Menu:
+
+* Saving History::
+
+\1f
+File: ess.info, Node: Saving History, Up: Command History
+
+4.3.1 Saving the command history
+--------------------------------
+
+The 'ess-history-file' variable, which is 't' by default, together with
+'ess-history-directory', governs if and where the command history is
+saved and restored between sessions. By default,
+'ess-history-directory' is '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:
+
+ (setq ess-history-file nil)
+
+or if you prefer only one global command history file:
+
+ (setq ess-history-directory "~/.R/")
+
+in your Emacs configuration file.
+
+\1f
+File: ess.info, Node: History expansion, Next: Hot keys, Prev: Command History, Up: Entering commands
+
+4.4 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 'csh'. History references are introduced by a '!' or '^' character
+and have meanings as follows:
+
+'!!'
+ The immediately previous command
+
+'!-N'
+ The Nth previous command
+
+'!text'
+ The last command beginning with the string 'text'
+
+'!?text'
+ The last command containing the string 'text'
+
+ In addition, you may follow the reference with a "word designator" to
+select particular "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 'comint-delimiter-argument-list' to a list of
+characters that are allowed to separate words and themselves form
+words.) Words are numbered beginning with zero. The word designator
+usually begins with a ':' (colon) character; however it may be omitted
+if the word reference begins with a '^', '$', '*' or '-'. If the word
+is to be selected from the previous command, the second '!' character
+can be omitted from the event specification. For instance, '!!:1' and
+'!:1' both refer to the first word of the previous command, while '!!$'
+and '!$' both refer to the last word in the previous command. The
+format of word designators is as follows:
+
+'0'
+ The zeroth word (i.e. the first one on the command line)
+
+'N'
+ The Nth word, where N is a number
+
+'^'
+ The first word (i.e. the second one on the command line)
+
+'$'
+ The last word
+
+'X-Y'
+ A range of words; '-Y' abbreviates '0-Y'
+
+'*'
+ All the words except the zeroth word, or nothing if the command had
+ just one word (the zeroth)
+
+'X*'
+ Abbreviates X-$
+
+'X-'
+ Like 'X*', but omitting the last word
+
+ In addition, you may surround the entire reference except for the
+first '!' 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
+'^old^new^' means "the last command, but with the first occurrence of
+the string 'old' replaced with the string 'new'" (the last '^' is
+optional). Similarly, '^old^' means "the last command, with the first
+occurrence of the string 'old' deleted" (again, the last '^' is
+optional).
+
+ To convert a history reference as described above to an input
+suitable for R, you need to "expand" the history reference, using the
+<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 'SPC TAB'. This will convert the history
+reference into an R command from the history, which you can then edit or
+press <RET> to execute.
+
+ For example, to execute the last command that referenced the variable
+'data', type '!?data SPC TAB RET'.
+
+\1f
+File: ess.info, Node: Hot keys, Next: Statistical Process running in ESS?, Prev: History expansion, Up: Entering commands
+
+4.5 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 'objects()' or '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:
+
+ -- User Option: ess-execute-in-process-buffer
+ If non-'nil', means that these commands will produce their output
+ in the process buffer instead.
+
+ In any case, passing a prefix argument to the commands (with 'C-u')
+will reverse the meaning of '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:
+
+ -- Command: ess-execute-objects POSN
+ 'C-c C-x' Sends the 'objects()' command to the ESS process. A
+ prefix argument specifies the position on the search list (use a
+ negative argument to toggle '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 POSN gets the objects
+ for that position, as well as toggling
+ 'ess-execute-in-process-buffer'.
+
+ -- Command: ess-execute-search INVERT
+ 'C-c C-s' Sends the 'inferior-ess-search-list-command' command to
+ the 'ess-language' process; 'search()' in R. Prefix INVERT toggles
+ 'ess-execute-in-process-buffer'.
+
+ '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; *note
+Keyboard Macros: (emacs)Keyboard Macros.
+
+ The following hot keys do not use '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:
+
+ -- Command: ess-load-file FILENAME
+ 'C-c M-l' Prompts for a file (FILENAME) to load into the ESS
+ process using 'source()'. If there is an error during loading, you
+ can jump to the error in the file with the following function.
+
+ -- Command: ess-parse-errors ARG RESET
+ Visits next '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 ARG specifies
+ how many error messages to move; negative means move back to
+ previous error messages. Just 'C-u' as a prefix means reparse the
+ error message buffer and start at the first error. The RESET
+ argument specifies restarting from the beginning.
+
+ *Note Error Checking::, for more details.
+
+ -- Command: ess-display-help-on-object OBJECT COMMAND
+ 'C-c C-v' Pops up a help buffer for an R object or function. If
+ COMMAND is supplied, it is used instead of
+ 'inferior-ess-help-command'. See *note Help:: for more details.
+
+ -- Command: ess-quit
+ 'C-c C-q' Issue an exiting command to the inferior process,
+ additionally also running '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 '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.
+
+\1f
+File: ess.info, Node: Statistical Process running in ESS?, Next: Emacsclient, Prev: Hot keys, Up: Entering commands
+
+4.6 Is the Statistical Process running under ESS?
+=================================================
+
+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 'options(STERM="iESS")' for R language processes running in
+an inferior 'iESS[S]' or 'iESS[R]' buffer.
+
+ ESS sets '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 'ddeESS[S]' buffer.
+
+ Other values of 'options()$STERM' that we recommend are:
+
+ * 'length': Fixed length xterm or telnet window.
+ * 'scrollable': Unlimited length xterm or telnet window.
+ * 'server': S-Plus Stat Server.
+ * 'BATCH': BATCH.
+ * 'Rgui': R GUI.
+ * 'Commands': S-Plus GUI without DDE interface to ESS.
+
+ Additional values may be recommended in the future as new interaction
+protocols are created. Unlike the values 'iESS' and 'ddeESS', ESS can't
+set these other values since the R language program is not under the
+control of ESS.
+
+\1f
+File: ess.info, Node: Emacsclient, Next: Other, Prev: Statistical Process running in ESS?, Up: Entering commands
+
+4.7 Using emacsclient
+=====================
+
+When starting R or S under Unix, ESS sets
+'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 'iterator', typing
+'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 'edit()' rather than
+'fix()' means that the function is not updated. Finally, the R function
+'page(x)' will also show a text representation of the object 'x' in a
+temporary Emacs buffer.
+
+\1f
+File: ess.info, Node: Other, Prev: Emacsclient, Up: Entering commands
+
+4.8 Other commands provided by inferior-ESS
+===========================================
+
+The following commands are also available in the process buffer:
+
+ -- Command: comint-interrupt-subjob
+ 'C-c C-c' Sends a Control-C signal to the iESS process. This has
+ the effect of aborting the current command.
+
+ -- Command: ess-switch-to-inferior-or-script-buffer TOGGLE-EOB
+ '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 'C-z' switch between the script and
+ process buffers.
+
+ If TOGGLE-EOB is given, the value of
+ 'ess-switch-to-end-of-proc-buffer' is toggled.
+
+ -- User Option: ess-switch-to-end-of-proc-buffer
+ If non-'nil', 'ess-switch-to-inferior-or-script-buffer' goes to end
+ of process buffer.
+
+ Other commands available in iESS modes are discussed in *note
+(emacs)Shell Mode::.
+
+\1f
+File: ess.info, Node: Evaluating code, Next: Transcript Mode, Prev: Entering commands, Up: Top
+
+5 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 '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:
+
+ -- User Option: ess-eval-visibly
+ Non-'nil' means 'ess-eval-*' commands display commands and output
+ in the process buffer. A value of 't' blocks Emacs while R is
+ busy. A value of 'nowait' does not block Emacs but printing may be
+ slightly off.
+
+ Passing a prefix ('C-u') (in Elisp terms, the argument VIS) to any of
+the following commands, however, reverses the meaning of
+'ess-eval-visibly' for that command only -- for example 'C-u C-c C-j'
+evaluates the current line without showing the input in the iESS buffer.
+The default value of 'ess-eval-visibly' ('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 'ess-eval-visibly' to ''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:
+
+ -- Command: ess-eval-region-or-line-and-step VIS
+ 'C-<RET>' Sends the highlighted region or current line and step to
+ next line of code.
+
+ -- Command: ess-eval-region-or-function-or-paragraph VIS
+ 'C-M-x' Sends the current selected region or function or paragraph.
+
+ -- Command: ess-eval-region-or-function-or-paragraph-and-step VIS
+ 'C-c C-c' Like 'ess-eval-region-or-function-or-paragraph' but steps
+ to next line of code.
+
+ Other, not so often used, evaluation commands are:
+
+ -- Command: ess-eval-line VIS
+ 'C-c C-j' Sends the current line to the ESS process.
+
+ -- Command: ess-eval-line-and-go VIS
+ 'C-c M-j' Like 'ess-eval-line' but additionally switches point to
+ the ESS process.
+
+ -- Command: ess-eval-function VIS NO-ERROR
+ 'C-c C-f' Sends the function containing point to the ESS process.
+
+ -- Command: ess-eval-function-and-go VIS
+ 'C-c M-f' Like 'ess-eval-function' but additionally switches point
+ to the ESS process.
+
+ -- Command: ess-eval-region START END TOGGLE MESSAGE
+ 'C-c C-r' Sends the current region to the ESS process.
+
+ -- Command: ess-eval-region-and-go START END VIS
+ 'C-c M-r' Like 'ess-eval-region' but additionally switches point to
+ the ESS process.
+
+ -- Command: ess-eval-buffer VIS
+ 'C-c C-b' Sends the current buffer to the ESS process.
+
+ -- Command: ess-eval-buffer-and-go VIS
+ 'C-c M-b' Like 'ess-eval-buffer' but additionally switches point to
+ the ESS process.
+
+ All the above '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 'C-c C-l' to
+update the function's value. In particular, '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 'comint-move-point-for-output' to ''others' or 't'.
+
+\1f
+File: ess.info, Node: Transcript Mode, Next: Editing objects, Prev: Evaluating code, Up: Top
+
+6 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 "transcript file", which should normally have the suffix '.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 '.Rout' into Emacs, it is placed
+in R Transcript Mode. Transcript Mode is similar to inferior R mode
+(*note Entering commands::): paragraphs are defined as a command and its
+output, and you can move though commands either with the paragraph
+commands or with 'C-c C-p' and 'C-c C-n'.
+
+* Menu:
+
+* Resubmit:: Resubmitting commands from the transcript file
+* Clean:: Cleaning transcript files
+
+\1f
+File: ess.info, Node: Resubmit, Next: Clean, Up: Transcript Mode
+
+6.1 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:
+
+ -- Command: ess-transcript-send-command
+ 'M-RET' Sends the current command line to the ESS process, and
+ execute it.
+
+ -- Command: ess-transcript-copy-command
+ 'C-c RET' Copy the current command to the ESS process, and switch
+ to it (ready to edit the copied command).
+
+ -- Command: ess-transcript-send-command-and-move
+ '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.
+
+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.
+
+\1f
+File: ess.info, Node: Clean, Prev: Resubmit, Up: Transcript Mode
+
+6.2 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:
+
+ -- Command: ess-transcript-clean-region BEG END EVEN-IF-READ-ONLY
+ 'C-c C-w' Strip the transcript in the region (given by BEG and
+ END), leaving only commands. Deletes any lines not beginning with
+ a prompt, and then removes the prompt from those lines that remain.
+ Prefix argument EVEN-IF-READ-ONLY means to clean even if the buffer
+ is read-only. Don't forget to remove any erroneous commands first!
+
+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 (*note Evaluating code::) using the code evaluation commands
+from R mode, also available in R Transcript Mode.
+
+\1f
+File: ess.info, Node: Editing objects, Next: Help, Prev: Transcript Mode, Up: Top
+
+7 Editing objects and 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
+
+\1f
+File: ess.info, Node: Edit buffer, Next: Loading, Up: Editing objects
+
+7.1 Creating or modifying R objects
+===================================
+
+To edit an object, type
+
+ -- Command: ess-dump-object-into-edit-buffer OBJECT
+ 'C-c C-e C-d' Edit an object in its own edit buffer.
+
+ from within the iESS process buffer ('*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 'TAB' key),
+or you may enter the name of a new object. 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
+'ess-function-template' is non-'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 'ess-dump-object-into-edit-buffer' is placed in the '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.
+
+ Note: when you dump a file with '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 (*note 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
+'dump()' command issued. 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 'ess-dump-object-into-edit-buffer' by typing 'C-u C-c
+C-e C-d'.
+
+\1f
+File: ess.info, Node: Loading, Next: Error Checking, Prev: Edit buffer, Up: Editing objects
+
+7.2 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 'source' function.
+You have already seen how to create source files using '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
+'ess-load-file' ('C-c M-l'). *note Hot keys::.
+
+After typing '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 '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 '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.
+
+\1f
+File: ess.info, Node: Error Checking, Next: Indenting, Prev: Loading, Up: Editing objects
+
+7.3 Detecting errors in source files
+====================================
+
+If any errors occur when loading a file with '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 'C-c `'
+('ess-parse-errors'). You will be returned to the offending file
+(loading it into a buffer if necessary) with point at the line S
+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 '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 _is_ a syntax error)
+by passing a prefix argument to 'ess-parse-errors' with 'C-u C-c `'.
+
+\1f
+File: ess.info, Node: Indenting, Next: Other edit buffer commands, Prev: Error Checking, Up: Editing objects
+
+7.4 Indenting and formatting R code
+===================================
+
+ESS provides a sophisticated mechanism for indenting R source code.
+Compound statements (delimited by '{' and '}') 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, 'if' statements,
+calls to '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.
+
+ Comments are also handled specially by ESS, using an idea borrowed
+from the Emacs-Lisp indentation style. By default, comments beginning
+with '###' are aligned to the beginning of the line. Comments beginning
+with '##' are aligned to the current level of indentation for the block
+containing the comment. Finally, comments beginning with '#' are
+aligned to a column on the right (the 40th column by default, but this
+value is controlled by the variable '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 '(setq ess-indent-with-fancy-comments nil)' to your '.emacs' file.
+
+ ESS also supports roxygen2 entries which is R documentation
+maintained in the source code as comments *Note roxygen2::.
+
+ The indentation commands provided by ESS are:
+
+ -- Command: ess-indent-or-complete
+ '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
+ 'tab-always-indent' is ''complete'. See also
+ 'ess-first-tab-never-complete'.
+
+ -- User Option: ess-first-tab-never-complete
+ If non-'nil', 'TAB' never tries to complete in ess-mode. The
+ default ''symbol' does not try to complete if the next char is a
+ valid symbol constituent. There are more options, see the help
+ ('C-h v').
+
+ -- Command: ess-indent-exp
+ 'TAB' Indents each line in the R (compound) expression which
+ follows point. Very useful for beautifying your R code.
+
+ -- Command: ess-electric-brace
+ '{' '}' The braces automatically indent to the correct position
+ when typed.
+
+ The following Emacs command are also helpful:
+
+'RET'
+'LFD'
+ 'newline-and-indent' Insert a newline, and indent the next line.
+ (Note that most keyboards nowadays do not have a <LINEFEED> key,
+ but <RET> and 'C-j' are equivalent.)
+
+'M-;'
+ 'indent-dwim' Call the comment command you want (Do What I Mean).
+
+* Menu:
+
+* Styles:: Changing styles for indentation and alignment
+
+\1f
+File: ess.info, Node: Styles, Up: Indenting
+
+7.4.1 Changing styles for code indentation and alignment
+--------------------------------------------------------
+
+The combined value of twelve variables (4 of three groups
+'ess-indent-*', 'ess-offset-*' and 'ess-align-*') that control
+indentation are collectively termed a style. ESS provides several
+styles covering the common styles of indentation: 'DEFAULT', 'OWN',
+'GNU', 'BSD', 'K&R', 'C++', 'RRR', 'RRR+', 'Rstudio', 'Rstudio-', and
+'CLB'. The variable 'ess-style-alist' lists the value of each
+indentation variable per style (and its documentation contains more).
+
+ -- Command: ess-set-style
+ 'C-c C-e C-s' (or 'C-c C-e s') sets the formatting style in this
+ buffer to be one of the predefined styles, see above. The
+ 'DEFAULT' style uses the default values for the indenting
+ variables; The 'OWN' style allows you to use your own private
+ values of the indentation variable, see below.
+
+ -- User Option: ess-style
+ The style to use. See the variable 'ess-style-alist' for how these
+ groups (DEFAULT, OWN, GNU, RRR, ...) map onto different settings
+ for variables. You can set this in your Emacs configuration file:
+
+ (setq ess-style 'C++)
+
+ -- 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 'ess-own-style-list'. The default
+ style in use is controlled by 'ess-style'.
+
+ The styles 'DEFAULT' and 'OWN' are initially identical. If you wish
+to edit some of the default values, set 'ess-style' to ''OWN' and change
+'ess-own-style-list'. *Note 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:
+
+ (defun myindent-ess-hook ()
+ (setq ess-indent-level 4))
+ (add-hook 'ess-mode-hook 'myindent-ess-hook)
+
+ In the rare case that you'd like to add an entire new indentation
+style of your own, copy the definition of 'ess-own-style-list' to a new
+variable and ensure that the last line of the ':set' declaration calls
+'ess-add-style' with a unique name for your style (e.g. ''MINE').
+Finally, add '(setq ess-style 'MINE)' to use your new style.
+
+\1f
+File: ess.info, Node: Other edit buffer commands, Next: Source Files, Prev: Indenting, Up: Editing objects
+
+7.5 Commands for motion, completion and more
+============================================
+
+A number of commands are provided to move across function definitions in
+the edit buffer:
+
+ -- Command: ess-goto-beginning-of-function-or-para
+ 'ESC C-a' aka 'C-M-a' If inside a function go to the beginning of
+ it, otherwise go to the beginning of paragraph.
+
+ -- Command: ess-goto-end-of-function-or-para
+ 'ESC C-e' aka 'C-M-e' Move point to the end of the function
+ containing point.
+
+ -- Command: ess-mark-function
+ 'ESC C-h' aka 'C-M-h' Place point at the beginning of the R
+ function containing point, and mark at the end.
+
+Don't forget the usual Emacs commands for moving over balanced
+expressions and parentheses: *Note Lists and Sexps: (Emacs)Lists.
+
+ Completion is provided in the edit buffer in a similar fashion to the
+process buffer: <TAB> first indents, and if there is nothing to indent,
+completes the object or file name; 'M-?' lists file completions. See
+*Note Completion::, for more.
+
+ Finally, 'C-c C-z' ('ess-switch-to-inferior-or-script-buffer')
+returns you to the 'iESS' process buffer, if done from a script buffer,
+placing point at the end of the buffer. If this is done from the '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 'C-c
+C-v', edit another function with 'C-c C-e C-d' and of course 'C-c C-l'
+can be used to load a source file into R.
+
+\1f
+File: ess.info, Node: Source Files, Next: Source Directories, Prev: Other edit buffer commands, Up: Editing objects
+
+7.6 Maintaining R source files
+==============================
+
+Every edit buffer in ESS is associated with a "dump file" on disk. Dump
+files are created whenever you type 'C-c C-e C-d'
+('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.
+
+ -- User Option: ess-delete-dump-files
+ If non-'nil', dump files created with C-c C-e C-d are deleted
+ immediately after they are created by the ess-process.
+
+ 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 _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 'dump'
+function; it doesn't apply to source files which already exist. The
+default value is 't'.
+
+ -- User Option: ess-keep-dump-files
+ 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 behaviour of
+ 'ess-load-file'. Dump files are never deleted if an error occurs
+ during the load.
+
+ After an object has been successfully (without error) loaded back
+into R with '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.
+
+ If the value of 'ess-keep-dump-files' is '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 --
+*note Single or Numbered Backups: (emacs)Backup Names, you can keep a
+historic record of function definitions. Another possibility is to
+maintain the files with a version-control system such as git *Note
+Version Control: (emacs)Version Control. As long as a dump file exists
+in the appropriate place for a particular object, editing that object
+with '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 _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 'ess-keep-dump-files' is nil, the dump file is always
+silently deleted after a successful load with 'C-c C-l'. While this is
+useful for files that were created with '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
+'ess-keep-dump-files' is buffer-local, you can make sure particular
+files are not deleted by setting it to 't' in the Local Variables
+section of the file *Note Local Variables in Files: (emacs)File
+Variables.
+
+ A safer option is to set 'ess-keep-dump-files' to '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 'C-c C-e C-d', but not any other files, setting
+'ess-keep-dump-files' to 'check' (the default value) will silently
+delete dump files created with '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 'C-c C-l', the dump file is _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.
+
+ Dump buffers are always autosaved, regardless of the value of
+'ess-keep-dump-files'.
+
+\1f
+File: ess.info, Node: Source Directories, Prev: Source Files, Up: Editing objects
+
+7.7 Names and locations of dump files
+=====================================
+
+Every dump file should be given a unique file name, usually the dumped
+object name with some additions.
+
+ -- User Option: ess-dump-filename-template
+ Template for filenames of dumped objects. '%s' is replaced by the
+ object name.
+
+By default, dump file names are the user name, followed by '.' and the
+object and ending with '.R'. Thus if user 'joe' dumps the object
+'myfun' the dump file will have name 'joe.myfun.R'. The username part
+is included to avoid clashes when dumping into a publicly-writable
+directory, such as '/tmp'; you may wish to remove this part if you are
+dumping into a directory owned by you.
+
+ You may also specify the directory in which dump files are written:
+
+ -- User Option: ess-source-directory
+ Directory name (ending in a slash) where R dump files are to be
+ written.
+
+ By default, dump files are always written to '/tmp', which is fine
+when 'ess-keep-dump-files' is 'nil'. If you are keeping dump files,
+then you will probably want to keep them somewhere in your home
+directory, say '~/R-source'. This could be achieved by including the
+following line in your Emacs configuration file:
+ (setq ess-source-directory (expand-file-name "~/R-source/"))
+
+ 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 '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 'Src' of the
+directory the ESS process was run in.
+
+ (setq ess-source-directory
+ (lambda ()
+ (concat ess-directory "Src/")))
+
+('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:
+ (setq ess-source-directory
+ (lambda ()
+ (file-name-as-directory
+ (expand-file-name (concat
+ (car ess-search-list)
+ "/.Src")))))
+
+ 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.
+
+\1f
+File: ess.info, Node: Help, Next: Completion, Prev: Editing objects, Up: Top
+
+8 Reading 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 'C-c C-v' ('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 '*help(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:
+
+'?'
+ 'ess-describe-help-mode' Pops up a help buffer with a list of the
+ commands available in R help mode.
+
+'h'
+ 'ess-display-help-on-object' Pop up a help buffer for a different
+ object.
+
+ Paging commands:
+
+'DEL'
+ 'scroll-down-command' Move one screen backwards through the help
+ file.
+
+'SPC'
+ 'scroll-up-command' Move one screen forwards through the help file.
+
+'>'
+'<'
+ 'end/beginning-of-buffer' Move to the end or beginning of the help
+ file, respectively.
+
+ Section-based motion commands:
+
+'n'
+'p'
+ 'ess-skip-to-previous-section' and '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.
+
+ In addition, the '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 's ?' to get the current list of active key bindings.
+
+'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:
+
+'?'
+ Pops up a help buffer with a list of the defined section motion
+ keys.
+
+ Evaluation:
+
+'l'
+ '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.
+
+'r'
+ 'ess-eval-region' Send the contents of the current region to the
+ ESS process. Useful for running examples in help files.
+
+ Quit commands:
+
+'q'
+ 'ess-help-quit' Return to previously selected buffer, and bury the
+ help buffer.
+
+'k'
+ 'kill-buffer' Return to previously selected buffer, and kills the
+ help buffer.
+
+'x'
+ 'ess-kill-buffer-and-go' Return to the ESS process, killing this
+ help buffer.
+
+ Miscellaneous:
+
+'i'
+ 'ess-display-index' Prompt for a package and display it's help
+ index.
+
+'v'
+ 'ess-display-vignettes' Display all available vignettes.
+
+'w'
+ 'ess-display-help-in-browser' Display current help page with the
+ web browser.
+
+'/'
+ 'isearch-forward' Same as 'C-s'.
+
+ In addition, all of the ESS commands available in the edit buffers
+are also available in R help mode (*note Edit buffer::). Of course, the
+usual (non-editing) Emacs commands are available, and for convenience
+the digits and <-> 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 'C-u') to 'ess-display-help-on-object'.
+
+ Help buffers are marked as temporary buffers in ESS, and are deleted
+when 'ess-quit' or '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 'ess-help-own-frame'.
+
+ Help buffers are displayed by calling the function
+'ess-display-help'. You can customize where these buffers are displayed
+by adding an entry in 'display-buffer-alist'; for examples, see *Note
+(ess)Controlling buffer display::. Or by customizing the options
+'ess-help-own-frame', 'ess-help-frame-alist', and
+'ess-display-buffer-reuse-frame'.
+
+\1f
+File: ess.info, Node: Completion, Next: Developing with ESS, Prev: Help, Up: Top
+
+9 Completion
+************
+
+* Menu:
+
+* Object names::
+* Function arguments::
+* Minibuffer completion::
+* Company::
+* Icicles::
+
+\1f
+File: ess.info, Node: Object names, Next: Function arguments, Up: Completion
+
+9.1 Completion of object names
+==============================
+
+The <TAB> key is for completion. The value of the variable
+'ess-first-tab-never-complete' controls when completion is allowed to
+occur. In 'ess-mode' <TAB> first tries to indent, and if there is
+nothing to indent, complete the object name instead.
+
+'TAB'
+ 'comint-dynamic-complete' Complete the R object name or filename
+ before point.
+
+ When the cursor is just after a partially-completed object name,
+pressing <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 'search()' command along with
+the component objects of attached data frames
+
+ For example, consider three functions 'binomplot()', 'binom.test()'
+and 'binomial()'. Typing 'bin TAB' will insert the characters 'om',
+completing the longest prefix ('binom') which distinguishes these three
+commands. Pressing 'TAB' once more provides a list of the three
+commands which have this prefix, allowing you to add more characters
+(say, '.') which specify the function you desire. After entering more
+characters pressing '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 'M-?'.
+
+ -- Command: ess-complete-object-name
+ 'M-?' List all possible completions of the object name at point.
+
+ ESS also provides completion over the components of named lists and
+environments (after '$'), S4 classes slots (after @), package and
+namespace objects (after :: and :::).
+
+ Completion is also provided over file names, which is particularly
+useful when using R functions such as 'get()' or '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 <TAB> key has a third use: it
+expands history references. *Note 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 *know* is there), the command 'M-x ess-resynch'
+forces the _entire_ cache to be refreshed, which should fix the problem.
+
+\1f
+File: ess.info, Node: Function arguments, Next: Minibuffer completion, Prev: Object names, Up: Completion
+
+9.2 Completion of function arguments
+====================================
+
+When inside a function call (i.e. following ''(''), 'TAB' completion
+also provides function arguments. If function is a generic, completion
+will provide all the arguments of 'S3' methods known to 'R'.
+
+ 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
+'?rc.options' at the prompt. For example, to have the equals sign for
+function arguments contain spaces on both sides (e.g. 'lm(for)'
+suggests 'formula = ' rather than 'formula='), you can adjust
+'funarg.suffix':
+
+ utils::rc.options(funarg.suffix = " = ")
+
+ A related functionality is *Note ESS ElDoc::, which displays function
+arguments in the echo area whenever the point is inside a function call.
+
+\1f
+File: ess.info, Node: Minibuffer completion, Next: Company, Prev: Function arguments, Up: Completion
+
+9.3 Minibuffer completion
+=========================
+
+ESS uses 'IDO' mechanism (part of default Emacs) for minibuffer
+completion if the 'ido' package is available and the value of
+'ess-use-ido' it 't' (the default). The completion command
+'ess-completing-read' falls back on classic 'completion-read' interface
+if this feature is not available for whatever reason.
+
+\1f
+File: ess.info, Node: Company, Next: Icicles, Prev: Minibuffer completion, Up: Completion
+
+9.4 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 'ess-use-company' to 'nil'. You can set it to
+''script-only' to only activate company in R scripts.
+
+\1f
+File: ess.info, Node: Icicles, Prev: Company, Up: Completion
+
+9.5 Icicles
+===========
+
+Another option for comprehensively handling completion in Emacs is via
+Icicles (<https://www.emacswiki.org/emacs/Icicles>). It allows users to
+have completions shown temporarily in the standard '*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 'customize-group Icicles', for more details on
+installation and customization options.
+
+ Once installed, Icicles can be activated by evaluating):
+
+ (require 'icicles)
+ (icy-mode 1)
+
+ Icicles can be toggled by typing 'M-x icy'.
+
+ When Icicles is on, 'TAB' offers completion, provided the conditions
+determined by 'ess-first-tab-never-complete' allow it. Typing 'M-TAB'
+will attempt completion regardless. Typing 'M-?' in 'ESS' or 'iESS'
+modes brings up the relevant completion candidates from which to choose.
+Minibuffer input filters the available candidates. Use 'TAB' for prefix
+completion or 'S-TAB' for substring or regexp completion. Use 'S-SPC'
+to match an additional pattern (repeatable). You can cycle among the
+matching candidates, choosing with 'RET' or 'mouse-2'.
+
+\1f
+File: ess.info, Node: Developing with ESS, Next: Extras, Prev: Completion, Up: Top
+
+10 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
+
+\1f
+File: ess.info, Node: ESS tracebug, Next: Editing documentation, Up: Developing with ESS
+
+10.1 ESS tracebug
+=================
+
+* Menu:
+
+* Getting started with tracebug:: Quick tutorial
+
+ESS '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.
+
+ 'ess-tracebug' is on by default. You can toggle it on and off with
+'M-x' 'ess-tracebug'. To disable startup activation of 'ess-tracebug'
+set 'ess-use-tracebug' to nil.
+
+ Tracebug functionality can be found on 'ess-dev-map', bound to 'C-c
+C-t'. Additionally, when subprocess is in a debugging state
+'ess-debug-minor-mode' is active and the following additional shortcuts
+are available:
+
+* 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'
+
+
+ These are all the tracebug commands defined in 'ess-dev-map' ('C-c
+C-t ?' to show this table):
+
+
+* 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'
+
+
+ To configure how electric watch window splits the display see
+'ess-watch-width-threshold' and 'ess-watch-height-threshold' variables.
+
+ _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")
+
+\1f
+File: ess.info, Node: Getting started with tracebug, Up: ESS tracebug
+
+10.1.1 Getting started with tracebug
+------------------------------------
+
+Consider a buffer with the following function:
+
+test <- function(x){
+ mean(x),
+}
+
+ Evaluating the function (e.g. 'C-c C-c') results in an error about
+an unexpected comma. You can use 'next-error' (bound by default to 'C-x
+`', 'M-g n', and '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 'mean' and
+set the breakpoint using 'C-c C-t b' ('ess-bp-set') and reevaluate the
+function. Jump to the inferior buffer (possibly using 'C-c C-z') and
+evaluate 'test(1:10)'. An interactive debug process starts, stopping at
+the breakpoint we just specified. Here you can debug your function
+(what is 'x' at this point?). Use 'M-N' to continue.
+
+ Let's replace our test function with one slightly more complicated:
+
+test <- function(x){
+ x <- x + 1
+ y <- mean(x)
+ x <- ifelse(x > 5, x, x - 100)
+ list(x, y)
+}
+
+ Try setting multiple breakpoints. You can unset a breakpoint by
+killing it with 'C-c C-t k'. You can set conditional breakpoints too.
+Try setting one by placing point on the line 'x <- x + 1' and doing 'C-c
+C-t B'. ESS will ask for the condition. Let's set it to
+'!is.numeric(x)'. After re-evaluating 'test', try calling 'test(1:100)'
+and 'test('foo')'.
+
+ You can remove all breakpoints with 'C-c C-t K'.
+
+ You can flag a function for debugging (similar to calling
+'debug(test)' at R's prompt) by doing 'C-c C-t d'. Try this yourself by
+putting point over 'test' and doing 'C-c C-t d'.
+
+ If an error occurs, you can get the complete call stack by doing 'C-c
+`' or 'C-c C-t `' ('ess-show-traceback').
+
+ Tracebug also offers a watch window where you can watch values of
+objects. Open it with 'C-c C-t w' ('ess-watch'). Initially you aren't
+watching anything. Add something with 'a' (e.g. 'a test'). The watch
+window displays what the object is at any given time and automatically
+updates. Quit the watch window with 'q'.
+
+\1f
+File: ess.info, Node: Editing documentation, Next: Namespaced Evaluation, Prev: ESS tracebug, Up: Developing with ESS
+
+10.2 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
+
+\1f
+File: ess.info, Node: R documentation files, Next: roxygen2, Up: Editing documentation
+
+10.2.1 Editing R documentation (Rd) files
+-----------------------------------------
+
+R objects are documented in files written in the "R documentation"
+("Rd"), a simple markup language closely resembling (La)TeX, which can
+be processed into a variety of formats, including LaTeX, 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 '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.
+
+'C-h m'
+ Describe the features of Rd mode.
+
+'LFD'
+'RET'
+ Reindent the current line, insert a newline and indent the new line
+ ('reindent-then-newline-and-indent'). An abbrev before point is
+ expanded if 'abbrev-mode' is non-'nil'.
+
+'TAB'
+ Indent current line based on its contents and on previous lines.
+ ('indent-according-to-mode').
+
+'C-c C-e'
+ Insert a "skeleton" with Rd markup for at least all mandatory
+ entries in Rd files ('Rd-mode-insert-skeleton'). Note that many
+ users might prefer to use the R function '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).
+
+'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 ('Rd-font'). 'C-c C-f' is only a prefix;
+ see e.g. '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 'C-c
+ C-f'.
+
+'C-c C-j'
+ Insert a suitably indented '\item{' on the next line
+ ('Rd-mode-insert-item').
+
+'C-c C-p'
+ Preview a plain text version ("help file", *note Help::) generated
+ from the Rd file ('Rd-preview-help').
+
+ 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,
+'C-c C-v' provides access to on-line help, and '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 'C-h
+m' for all available commands.
+
+ Rd mode also provides access to abbreviations for most of the Rd
+markup commands. Type '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.
+
+ -- User Option: Rd-mode-hook
+ Hook to be run when Rd mode is entered.
+
+ -- User Option: Rd-indent-level
+ The indentation of Rd code with respect to containing blocks.
+ Default is 2.
+
+ -- User Option: Rd-to-help-command
+ The shell command used for converting Rd source to help text.
+ Default is 'R CMD Rd2txt'.
+
+ To automatically turn on the abbrev and font-lock features of Rd
+mode, add the following lines to one of your Emacs startup files:
+
+ (add-hook 'Rd-mode-hook
+ (lambda ()
+ (abbrev-mode 1)
+ (font-lock-mode 1)))
+
+\1f
+File: ess.info, Node: roxygen2, Prev: R documentation files, Up: Editing documentation
+
+10.2.2 Editing roxygen2 documentation
+-------------------------------------
+
+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 'NAMESPACE' files.
+See the roxygen2 documentation found via <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:
+
+ ##' 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")
+ The entry is immediately preceding the object to document and all
+lines start with the roxygen2 prefix string, in this case '##''. 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 'ess-roxy.el' which is loaded
+by default in ESS. The following special Emacs commands are provided.
+
+ -- Command: ess-roxy-update-entry
+ '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 'ess-roxy-fill-param-p' is non-nil.
+
+ -- Command: ess-roxy-toggle-roxy-region BEG END
+ 'C-c C-o C-c' Toggle the presence of the leading roxygen2 string on
+ all lines in the marked region (between BEG and END. Convenient
+ for transferring text to roxygen2 entries and to evaluate example
+ fields.
+
+ -- Command: ess-roxy-preview-Rd NAME-FILE
+ '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 NAME-FILE,
+ i.e. '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.
+
+ -- Command: ess-roxy-preview-HTML VISIT-INSTEAD-OF-OPEN
+ '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 VISIT-INSTEAD-OF-OPEN, i.e. 'C-u C-c C-e
+ C-t', visit the generated HTML file instead. Requires the roxygen2
+ and tools packages to be installed.
+
+ -- Command: ess-roxy-previous-entry
+ 'C-c C-o p' Go to start of the roxygen2 entry above point.
+
+ -- Command: ess-roxy-next-entry
+ 'C-c C-o n' Go to end of the roxygen2 entry above point.
+
+ -- Command: ess-roxy-hide-all
+ '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.
+
+ ESS also advises the following standard editing functions in order to
+make roxygen2 editing more intuitive:
+
+'TAB'
+ 'ess-R-complete-object-name' Complete roxygen2 tag at point. E.g.
+ doing 'TAB' when the point is at the end of '@par' completes to
+ '@param'.
+
+'M-h'
+ '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.
+
+'TAB'
+ 'ess-indent-command' If hide-show support is enabled, fold away the
+ visibility of the roxygen2 entry at point.
+
+'M-q'
+ 'fill-paragraph' Fill the roxygen2 field at point.
+
+'C-a'
+ '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.
+
+'RET'
+ 'newline-and-indent' Insert a new line and the roxygen2 prefix
+ string.
+
+\1f
+File: ess.info, Node: Namespaced Evaluation, Prev: Editing documentation, Up: Developing with ESS
+
+10.3 Namespaced Evaluation
+==========================
+
+In non package files evaluation commands, *Note Evaluating code::, send
+portions of the current buffer environment ('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
+<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 'GlobalEnv' from inside a
+package. In such cases 'C-c C-t C-s' is your friend.
+
+ -- Command: ess-r-set-evaluation-env ARG
+ 'C-c C-t C-s' Set or unset the current evaluation environment (a
+ package).
+
+\1f
+File: ess.info, Node: Extras, Next: ESS for R, Prev: Developing with ESS, Up: Top
+
+11 Other ESS features and tools
+*******************************
+
+ESS has a few extra features, which didn't fit anywhere else.
+* 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
+
+\1f
+File: ess.info, Node: ESS ElDoc, Next: ESS Flymake, Up: Extras
+
+11.1 ElDoc
+==========
+
+In 'ElDoc' mode, the echo area displays function's arguments at point.
+ElDoc is active by default in 'ess-mode' and 'inferior-ess-mode'
+buffers. To activate it only in 'ess-mode' buffers, place the following
+into your init file:
+
+ (setq ess-use-eldoc 'script-only)
+
+ -- User Option: ess-use-eldoc
+ If 't', activate eldoc in ess-mode and inferior-ess-mode buffers.
+ If ''script-only' activate in ess-mode buffers only. Set
+ 'ess-use-eldoc' to 'nil' to stop using 'ElDoc' altogether.
+
+ -- User Option: ess-eldoc-show-on-symbol
+ This variable controls whether the help is shown only inside
+ function calls. If set to 't', '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 ''(''.
+
+ -- User Option: ess-eldoc-abbreviation-style
+ The variable determines how the doc string should be abbreviated to
+ fit into minibuffer. Posible values are 'nil', 'mild', 'normal',
+ 'strong' and 'aggressive'. Please see the documentation of the
+ variable for more details. The default filter is 'normal'.
+
+ Ess-eldoc also honors the value of 'eldoc-echo-area-use-multiline-p',
+which if set to 'nil', will cause the truncation of doc string
+indifferent of the value of 'ess-eldoc-abbreviation-style'. This way
+you can combine different filter levels with the truncation.
+
+\1f
+File: ess.info, Node: ESS Flymake, Next: Handy commands, Prev: ESS ElDoc, Up: Extras
+
+11.2 Flymake
+============
+
+The minor mode '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 'ess-use-flymake' to
+'nil'. In order to use it, you may need to install the 'lintr' R
+package, available from CRAN.
+
+ -- User Option: ess-use-flymake
+ When non-nil, use flymake. If ''process', only use flymake when
+ the buffer has an inferior process running.
+
+ -- 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 'lintr::with_defaults'. See the
+ help page for 'lintr::default_linters' for information on available
+ linters and their defaults.
+
+ -- User Option: ess-r-flymake-lintr-cache
+ When 't' (the default), lintr uses a cache. Change to 'nil' to
+ disable lintr's caching mechanism.
+
+\1f
+File: ess.info, Node: Handy commands, Next: Highlighting, Prev: ESS Flymake, Up: Extras
+
+11.3 Handy commands
+===================
+
+ -- Command: ess-handy-commands
+ Request and execute a command from 'ess-handy-commands' list.
+
+ -- User Option: ess-handy-commands
+ An alist of custom ESS commands available for call by
+ 'ess-handy-commands' and 'ess-smart-comma' function.
+
+ Currently contains:
+
+ 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.
+
+\1f
+File: ess.info, Node: Highlighting, Next: Parens, Prev: Handy commands, Up: Extras
+
+11.4 Syntactic highlighting of buffers
+======================================
+
+ESS provides Font-Lock (*note Using Multiple Typefaces: (emacs)Faces.)
+patterns for inferior R Mode, S Mode, and R Transcript Mode buffers.
+
+ The font-lock patterns are defined by the following variables, which
+you may modify if desired:
+
+ -- User Option: inferior-R-font-lock-keywords
+ Font-lock patterns for inferior *R* processes. (There is a
+ corresponding '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 'NA' and
+ 'TRUE'.
+
+ -- User Option: ess-R-font-lock-keywords
+ Font-lock patterns for ESS R programming mode. (There is a
+ corresponding 'ess-S-font-lock-keywords' for S buffers.) The
+ default value highlights function names, literals, assignments,
+ source functions and reserved words.
+
+\1f
+File: ess.info, Node: Parens, Next: Graphics, Prev: Highlighting, Up: Extras
+
+11.5 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:
+
+ (show-paren-mode)
+
+\1f
+File: ess.info, Node: Graphics, Next: Imenu, Prev: Parens, Up: Extras
+
+11.6 Using graphics with ESS
+============================
+
+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
+
+\1f
+File: ess.info, Node: printer, Next: X11, Up: Graphics
+
+11.6.1 Using ESS with the 'printer()' driver
+--------------------------------------------
+
+This is the simplest (and least desirable) method of using graphics
+within ESS. S's '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
+ printer(width=79)
+ (the '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 'show()' command is
+issued, which displays the current figure.
+
+\1f
+File: ess.info, Node: X11, Next: winjava, Prev: printer, Up: Graphics
+
+11.6.2 Using ESS with windowing devices
+---------------------------------------
+
+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.
+
+\1f
+File: ess.info, Node: winjava, Prev: X11, Up: Graphics
+
+11.6.3 Java Graphics Device
+---------------------------
+
+S+6.1 and newer on Windows contains a java library that supports
+graphics. Send the commands:
+
+ library(winjava)
+ java.graph()
+
+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.)
+
+\1f
+File: ess.info, Node: Imenu, Next: Toolbar, Prev: Graphics, Up: Extras
+
+11.7 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 'imenu-generic-expression'. This value is set
+by various ESS variables such as 'ess-imenu-S-generic-expression'.
+
+\1f
+File: ess.info, Node: Toolbar, Next: Xref, Prev: Imenu, Up: Extras
+
+11.8 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. *Note Customization::, for
+ways to change the toolbar.
+
+\1f
+File: ess.info, Node: Xref, Next: Rdired, Prev: Toolbar, Up: Extras
+
+11.9 Xref
+=========
+
+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 *Note
+(emacs)Xref::.
+
+\1f
+File: ess.info, Node: Rdired, Next: Package listing, Prev: Xref, Up: Extras
+
+11.10 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 'M-x R' and then store a few variables, such
+as:
+
+ s <- sin(seq(from=0, to=8*pi, length=100))
+ x <- c(1, 4, 9)
+ y <- rnorm(20)
+ z <- TRUE
+
+ Then use 'M-x ess-rdired' to create a buffer listing the objects in
+your current environment and display it in a new window:
+ mode length
+ s numeric 100
+ x numeric 3
+ y numeric 20
+ z logical 1
+
+ Type 'C-h m' or '?' 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).
+
+\1f
+File: ess.info, Node: Package listing, Next: Org, Prev: Rdired, Up: Extras
+
+11.11 Package listing
+=====================
+
+ESS[R] provides several commands to list and manage packages and objects
+under the 'C-c C-.' keymap:
+
+ -- Command: ess-r-package-list-local-packages
+ 'C-c C-. l' List all packages in all available libraries.
+
+ -- Command: ess-r-package-list-available-packages
+ 'C-c C-. r' List available packages from repositories listed by
+ 'getOptions(``repos'')' in the current R session.
+
+ -- Command: ess-r-package-update-packages LIB REPOS
+ 'C-c C-. u' Update packages in a particular library LIB and
+ repository REPOS.
+
+ -- Command: ess-rutils-rm-all
+ 'C-c C-. m' Remove all R objects.
+
+ -- Command: ess-rutils-load-workspace
+ 'C-c C-. w' Load a workspace file into R.
+
+ -- Command: ess-rutils-save-workspace
+ 'C-c C-. s' Save a workspace file.
+
+ -- Command: ess-change-directory
+ 'C-c C-. d' Change the working directory for the current R session.
+
+ -- Command: ess-rutils-html-docs
+ 'C-c C-. H' Use 'browse-url' to navigate R html documentation.
+
+ Functions for listing objects and packages ('ess-rutils-local-pkgs',
+'ess-rutils-repos-pkgs', and 'ess-rutils-objs') show results in a
+separate buffer and window, in 'ess-rutils-mode', providing useful key
+bindings in this mode (type '?' in this buffer for a description).
+
+\1f
+File: ess.info, Node: Org, Next: Sweave and AUCTeX, Prev: Package listing, Up: Extras
+
+11.12 Interaction with Org mode
+===============================
+
+Org-mode (<https://orgmode.org>) now supports reproducible research and
+literate programming in many languages (including R) - see chapter 15 of
+the Org manual
+(<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.)
+
+\1f
+File: ess.info, Node: Sweave and AUCTeX, Prev: Org, Up: Extras
+
+11.13 Support for Sweave in ESS and AUCTeX
+==========================================
+
+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 <https://github.com/polymode/poly-R/>,
+<https://polymode.github.io/>, or markdown-mode with edit-indirect
+<https://jblevins.org/projects/markdown-mode>.
+
+ ESS provides support for writing and processing Sweave
+(<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:
+
+ -- Command: ess-swv-weave CHOOSE
+ 'M-n s' Run Sweave on the current .Rnw file. If CHOOSE is
+ non-'nil', offer a menu of available weavers.
+
+ -- Command: ess-swv-latex
+ 'M-n l' Run LaTeX after Sweave'ing.
+
+ -- Command: ess-swv-PS
+ 'M-n p' Generate and display a postscript file after LaTeX'ing.
+
+ -- Command: ess-swv-PDF PDFLATEX-CMD
+ 'M-n P' Generate and display a PDF file after LaTeX'ing. Optional
+ argument PDFLATEX-CMD is the command to use, which by default, is
+ the command used to generate the PDF file is the first element of
+ 'ess-swv-pdflatex-commands'.
+
+ -- User Option: ess-swv-pdflatex-commands
+ Commands used by 'ess-swv-PDF' to run a version of pdflatex; the
+ first entry is the default command.
+
+ Sweave'ing with 'ess-swv-weave' starts an inferior-ESS process, if
+one is not available. Other commands are available from the 'Sweaving,
+Tangling, ...' submenu of the Noweb menu.
+
+ AUCTeX (<https://www.gnu.org/software/auctex>) users may prefer to
+set the variable '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 '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 'C-c C-c Sweave RET' without an inferior-ESS process.
+Similarly, LaTeX'ing can be done by 'C-c C-c LaTeXSweave RET'. In both
+cases, the process can be monitored with 'C-c C-l'
+('TeX-recenter-output-buffer'). Open the viewer with 'C-c C-v'
+('TeX-view'), as usual in AUCTeX.
+
+\1f
+File: ess.info, Node: ESS for R, Next: ESS for SAS, Prev: Extras, Up: Top
+
+12 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::
+
+\1f
+File: ess.info, Node: ESS(R)--Editing files, Next: iESS(R)--Inferior ESS processes, Up: ESS for R
+
+12.1 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 '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.
+
+\1f
+File: ess.info, Node: iESS(R)--Inferior ESS processes, Next: Philosophies for using ESS(R), Prev: ESS(R)--Editing files, Up: ESS for R
+
+12.2 iESS[R]-Inferior ESS processes
+===================================
+
+To start up iESS mode for R, use:
+ M-x R
+ M-x S+3
+ M-x S4
+ M-x S+5
+ M-x S+6
+
+(for R, S-PLUS 3.x, S4, S+5, S+6 or S+7, respectively. This assumes
+that you have access to each).
+
+ 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
+'inferior-R-args'.
+
+ Note that R has some extremely useful command line arguments. For
+example, '--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
+'exec-path' for R binaries. If ESS cannot find your R binaries, on Unix
+you can change the Unix environment variable 'PATH', as this variable is
+used to set 'exec-path'.
+
+ R on GNU/Linux systems and other Unix-like systems (macOS): If you
+have "R-3.6.3" on your 'exec-path', it can be started using 'M-x
+R-3.6.3'. By default, ESS will find versions of R beginning "R-1",
+"R-2", ..., "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 'ess-r-runners-prefixes'. To see which functions
+have been created for starting different versions of R, type '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 'exec-path', it
+can be started using 'M-x rw1081'. By default, ESS will find versions
+of R located in directories parallel to the version of R in your 'PATH'.
+If your versions of R are called other names, you will need to change
+the variable 'ess-rterm-versions'. To see which functions have been
+created for starting different versions of R, type '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 '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 'R --version' to determine which is newest.)
+
+\1f
+File: ess.info, Node: Philosophies for using ESS(R), Next: Example ESS usage, Prev: iESS(R)--Inferior ESS processes, Up: ESS for R
+
+12.3 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:
+ (setq ess-keep-dump-files nil)
+ (setq ess-delete-dump-files t)
+ (setq ess-mode-silently-save nil)
+
+\1f
+File: ess.info, Node: Example ESS usage, Prev: Philosophies for using ESS(R), Up: ESS for R
+
+12.4 Example ESS usage
+======================
+
+Comments as to what should be happening are prefixed by "##".
+
+ ### 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.
+
+
+\1f
+File: ess.info, Node: ESS for SAS, Next: ESS for BUGS, Prev: ESS for R, Up: Top
+
+13 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::
+ESS[SAS] was designed for use with SAS. It is descended from emacs
+macros developed by John Sall for editing SAS programs and '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.
+
+\1f
+File: ess.info, Node: ESS(SAS)--Design philosophy, Next: ESS(SAS)--Editing files, Up: ESS for SAS
+
+13.1 ESS[SAS]-Design philosophy
+===============================
+
+ESS[SAS] was designed to aid the user in writing and maintaining SAS
+programs, such as 'FOO.sas'. Both interactive and batch submission of
+SAS programs is supported.
+
+ ESS[SAS] was written with two primary goals.
+ 1. 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.
+ 2. 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.
+
+\1f
+File: ess.info, Node: ESS(SAS)--Editing files, Next: ESS(SAS)--TAB key, Prev: ESS(SAS)--Design philosophy, Up: ESS for SAS
+
+13.2 ESS[SAS]-Editing files
+===========================
+
+ESS[SAS] is the mode for editing SAS language files. This mode handles:
+
+ * proper indenting, generated by both <TAB> and <RET>.
+ * color and font choices based on syntax.
+ * 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.
+ * capability of killing the batch SAS process through the '*shell*'
+ buffer or allow the SAS process to keep on running after you exit
+ emacs.
+ * single keypress navigation of '.sas', '.log' and '.lst' files
+ ('.log' and '.lst' files are refreshed with each keypress).
+ * ability to send the contents of an entire buffer, a highlighted
+ region, or a single line to an interactive SAS process.
+ * ability to switch between processes which would be the target of
+ the buffer (for the above).
+
+ ESS[SAS] is automatically turned on when editing a file with a '.sas'
+suffix (or other extension, if specified via '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 'M-x SAS' (*Note
+iESS(SAS)--Interactive SAS processes::.)
+
+ At this writing, the indenting and syntax highlighting are generally
+correct. Known issues: for multiple line '*' or '%*' comments, only the
+first line is highlighted; for '.log' files, only the first line of a
+'NOTE:', 'WARNING:' or 'ERROR:' message is highlighted; unmatched
+single/double quotes in 'CARDS' data lines are *NOT* ignored; in an
+iterative 'DO' statement, 'TO' and 'BY' are not highlighted.
+
+\1f
+File: ess.info, Node: ESS(SAS)--TAB key, Next: ESS(SAS)--Batch SAS processes, Prev: ESS(SAS)--Editing files, Up: ESS for SAS
+
+13.3 ESS[SAS]-<TAB> key
+=======================
+
+Two options. The <TAB> key is bound by default to 'sas-indent-line'.
+This function is used to syntactically indent SAS code so 'PROC' and
+'RUN' are in the left margin, other statements are indented
+'sas-indent-width' spaces from the margin, continuation lines are
+indented '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
+'require'/'load':
+ (setq ess-sas-edit-keys-toggle nil)
+
+ ESS provides an alternate behavior for <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, 'C-<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 'require'/'load':
+ (setq ess-sas-edit-keys-toggle t)
+ Under the alternate behavior, <TAB> is bound to 'M-x tab-to-tab-stop'
+and the stops are defined by 'ess-sas-tab-stop-list'.
+
+\1f
+File: ess.info, Node: ESS(SAS)--Batch SAS processes, Next: ESS(SAS)--Function keys for batch processing, Prev: ESS(SAS)--TAB key, Up: ESS for SAS
+
+13.4 ESS[SAS]-Batch SAS processes
+=================================
+
+Submission of a SAS batch job is dependent on your environment.
+'ess-sas-submit-method' is determined by your operating system and your
+shell. It defaults to ''sh' unless you are running Windows or Mac
+Classic. Under Windows, it will default to ''sh' if you are using a
+UNIX-imitating shell; otherwise ''ms-dos' for an MS-DOS shell. On
+macOS, it will default to ''sh', but under Mac Classic, it defaults to
+''apple-script'. You will also set this to ''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 'ess-sas-shell-buffer-remote-init' is a Local
+Variable that defaults to '"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 'ssh-agent'/'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 'ess-kermit-prefix' character prepended (the default is
+'"#"'). Execute the command '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 '*shell*' buffer, then note
+that the Kermit escape sequence is 'C-q C-\ c' rather than '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
+'ess-kermit-command'.
+
+ The command used by the 'SUBMIT' function key (<F3> or <F8>) to
+submit a batch SAS job, whether local or remote, is
+'ess-sas-submit-command' which defaults to 'sas-program'. 'sas-program'
+is '"invoke SAS using program file"' for Mac Classic and '"sas"'
+otherwise. However, you may have to alter '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:
+ endsas;
+ Local variables:
+ ess-sas-submit-command: "sas8"
+ End:
+
+ The command line is also made of 'ess-sas-submit-pre-command',
+'ess-sas-submit-post-command' and 'ess-sas-submit-command-options' (the
+last of which is also buffer-local). Here are some examples for your
+'~/.emacs' or '~/.emacs.d/init.el' file (you may also use
+'M-x customize-variable'):
+ ;'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")
+
+ 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
+'~/.emacs' or '~/.emacs.d/init.el' file by:
+ (setq ess-sleep-for 0.2)
+
+ For example, '(setq ess-sas-global-unix-keys t)' keys shown, '(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
+'C-x C-f foo.sas'. 'FOO.sas' will be in ESS[SAS] mode. Edit as
+appropriate, then save and submit the batch SAS job.
+ <F3> (<F8>)
+ The job runs in the '*shell*' buffer while you continue to edit
+'FOO.sas'. If 'ess-sas-submit-method' is ''sh', then the message buffer
+will display the shell notification when the job is complete. The ''sh'
+setting also allows you to terminate the SAS batch job before it is
+finished.
+ <F8> (<F3>)
+ Terminating a SAS batch in the '*shell*' buffer.
+ kill PID
+ You may want to visit the '.log' (whether the job is still running or
+it is finished) and check for error messages. The '.log' will be
+refreshed and you will be placed in it's buffer. You will be taken to
+the first error message, if any.
+ <F5> (<F6>)
+ Goto the next error message, if any.
+ <F5> (<F6>)
+ Now, 'refresh' the '.lst' and go to it's buffer.
+ <F6> (<F7>)
+ If you wish to make changes, go to the '.sas' file with.
+ <F4> (<F5>)
+ Make your editing changes and submit again.
+ <F3> (<F8>)
+
+\1f
+File: ess.info, Node: ESS(SAS)--Function keys for batch processing, Next: iESS(SAS)--Interactive SAS processes, Prev: ESS(SAS)--Batch SAS processes, Up: ESS for SAS
+
+13.5 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
+(GECS) which do not allow function keys to be bound so that they are
+available to the user.
+
+ Options 2-5. Since 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).
+
+ a. SAS Display Manager has different function key definitions for UNIX
+ (2, 4) and Windows (3, 5); ESS[SAS] can use either.
+ b. 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
+ 'auto-mode-alist'.
+
+ The distinction between local and global is subtle. If you want the
+ESS[SAS] definitions to work when you are in the '*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.
+
+ a. For a site installation or an individual, place *ONLY ONE* of the
+ following lines in your initialization file prior to a
+ 'require'/'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:
+ ;;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)
+
+ The names '-unix-' and '-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.
+
+ b. If your site installation has configured the keys contrary to your
+ liking, then you must call the appropriate function.
+ (load "ess-site") ;; local-unix-keys
+ (ess-sas-global-pc-keys)
+
+ 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).
+
+UNIX PC Nickname
+<F2> <F2> 'refresh'
+ revert the current buffer with the file of the same name if the file is
+ newer than the buffer
+<F3> <F8> 'SUBMIT'
+ save the current '.sas' file (which is either the '.sas' file in the
+ current buffer or the '.sas' file associated with the '.lst' or '.log'
+ file in the current buffer) and submit the file as a batch SAS job
+<F4> <F5> 'PROGRAM'
+ switch buffer to '.sas' file
+<F5> <F6> 'LOG'
+ switch buffer to '.log' file, 'refresh' and goto next error message, if
+ any
+<F6> <F7> 'OUTPUT'
+ switch buffer to '.lst' file and 'refresh'
+<F7> <F4> 'filetype-1'
+ switch buffer to 'filetype-1' (defaults to '.txt') file and 'refresh'
+<F8> <F3> 'shell'
+ switch buffer to '*shell*'
+<F9> <F9> 'VIEWTABLE'
+ open an interactive 'PROC FSEDIT' session on the SAS dataset near point
+<F10> <F10> toggle-log
+ toggle ESS[SAS] for '.log' files; useful for certain debugging situations
+<F11> <F11> 'filetype-2'
+ switch buffer to 'filetype-2' (defaults to '.dat') file and 'refresh'
+<F12> <F12> viewgraph
+ open a 'GSASFILE' near point for viewing either in emacs or with an
+ external viewer
+'C-<F1>' 'C-<F1>' rtf-portrait
+ create an MS RTF portrait file from the current buffer with a file
+ extension of '.rtf'
+'C-<F2>' 'C-<F2>' rtf-landscape
+ create an MS RTF landscape file from the current buffer with a file
+ extension of '.rtf'
+'C-<F3>' 'C-<F8>' submit-region
+ write region to 'ess-temp.sas' and submit
+'C-<F5>' 'C-<F6>' append-to-log
+ append 'ess-temp.log' to the current '.log' file
+'C-<F6>' 'C-<F7>' append-to-output
+ append 'ess-temp.lst' to the current '.lst' file
+'C-<F9>' 'C-<F9>' 'INSIGHT'
+ open an interactive 'PROC INSIGHT' session on the SAS dataset near point
+'C-<F10>''C-<F10>'toggle-listing
+ toggle ESS[SAS] for '.lst' files; useful for toggling read-only
+
+ 'SUBMIT', 'PROGRAM', 'LOG' and '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.
+
+ 'shell' switches you to the '*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 '*shell*') with the
+buffer-local variable '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 'ess-sas-submit-method'.
+
+ <F2> performs the 'refresh' operation on the current buffer.
+'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 'LOG', 'OUTPUT', 'filetype-1' or <F11> are pressed.
+
+ 'filetype-1' switches you to a file with the same file name as your
+'.sas' file, but with a different extension ('.txt' by default) and
+performs 'refresh'. You can over-ride the default extension; for
+example in your '~/.emacs' or '~/.emacs.d/init.el' file:
+ (setq ess-sas-suffix-1 "csv") ; for example
+
+ <F9> will prompt you for the name of a permanent SAS dataset near
+point to be opened for viewing by 'PROC FSEDIT'. You can control the
+SAS batch command-line with 'ess-sas-data-view-submit-options'. For
+controlling the SAS batch commands, you have the global variables
+'ess-sas-data-view-libname' and 'ess-sas-data-view-fsview-command' as
+well as the buffer-local variable 'ess-sas-data-view-fsview-statement'.
+If you have your SAS 'LIBNAME' defined in '~/autoexec.sas', then the
+defaults for these variables should be sufficient.
+
+ Similarly, 'C-<F9>' will prompt you for the name of a permanent SAS
+dataset near point to be opened for viewing by 'PROC INSIGHT'. You can
+control the SAS batch command-line with
+'ess-sas-data-view-submit-options'. For controlling the SAS batch
+commands, you have the global variables 'ess-sas-data-view-libname' and
+'ess-sas-data-view-insight-command' as well as the buffer-local variable
+'ess-sas-data-view-insight-statement'.
+
+ <F10> toggles ESS[SAS] mode for '.log' files which is off by default
+(technically, it is 'SAS-log-mode', but it looks the same). The syntax
+highlighting can be helpful in certain debugging situations, but large
+'.log' files may take a long time to highlight.
+
+ <F11> is the same as 'filetype-1' except it is '.dat' by default.
+
+ <F12> will prompt you for the name of a 'GSASFILE' near the point in
+'.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 '.gif' and '.jpg' files internally. You
+may need to change the following variables for your own situation.
+'ess-sas-graph-view-suffix-regexp' is a regular expression of supported
+file types defined via file name extensions.
+'ess-sas-graph-view-viewer-default' is the default external viewer for
+your platform. '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.
+ (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
+
+ 'C-<F2>' produces US landscape by default, however, it can produce A4
+landscape (first line for "global" key mapping, second for "local"):
+ (global-set-key [(control f2)] 'ess-sas-rtf-a4-landscape)
+ (define-key sas-mode-local-map [(control f2)] 'ess-sas-rtf-a4-landscape)
+
+\1f
+File: ess.info, Node: iESS(SAS)--Interactive SAS processes, Next: iESS(SAS)--Common problems, Prev: ESS(SAS)--Function keys for batch processing, Up: ESS for SAS
+
+13.6 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 '"-stdio -linesize 80 -noovp
+-nosyntaxcheck"' (the default of 'inferior-SAS-args').
+
+ '-stdio'
+ required to make the redirection of stdio work
+ '-linesize 80'
+ keeps output lines from folding on standard terminals
+ '-noovp'
+ prevents error messages from printing 3 times
+ '-nosyntaxcheck'
+ permits recovery after syntax errors
+
+ To start up iESS[SAS] mode, use:
+ M-x SAS
+
+ The '*SAS:1.log*' buffer in 'ESStr' mode corresponds to the file
+'FOO.log' in SAS batch usage and to the 'SAS: LOG' window in the SAS
+Display Manager. All commands submitted to SAS, informative messages,
+warnings, and errors appear here.
+
+ The '*SAS:1.lst*' buffer in 'ESSlst' mode corresponds to the file
+'FOO.lst' in SAS batch usage and to the 'SAS: OUTPUT' window in the SAS
+Display Manager. All printed output appears in this window.
+
+ The '*SAS:1*' buffer exists solely as a communications buffer. The
+user should never use this buffer directly. Files are edited in the
+'FOO.sas' buffer. The 'C-c C-r' key in ESS[SAS] is the functional
+equivalent of bringing a file into the 'SAS: PROGRAM EDITOR' window
+followed by 'SUBMIT'.
+
+ For example, open the file you want to work with.
+ C-x C-f foo.sas
+ 'FOO.sas' will be in ESS[SAS] mode. Edit as appropriate, and then
+start up SAS with the cursor in the 'FOO.sas' buffer.
+ M-x SAS
+ Four buffers will appear on screen:
+Buffer Mode Description
+'FOO.sas' 'ESS[SAS]' your source file
+'*SAS:1*' 'iESS[SAS:1]' iESS communication buffer
+'*SAS:1.log*' 'Shell ESStr SAS log information
+ []'
+'*SAS:1.lst*' 'Shell ESSlst SAS listing information
+ []'
+ 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 'FOO.sas'. Enter the sequence 'C-c C-w'. The cursor
+will normally be in buffer 'FOO.sas'. If not, put it there and
+'C-x b 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
+'DATA' or 'PROC' and end with 'RUN;'), '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
+'FOO.sas' buffer and resubmit with another 'C-c C-r'.
+
+ At the end of the session you may save the log and listing buffers
+with the usual 'C-x C-s' commands. You will be prompted for a file
+name. Typically, the names 'FOO.log' and '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 'C-x C-q'.
+
+ At the end of the session, the input file '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 '*SAS:1*' buffer is strictly for ESS use. The user should never
+need to read it or write to it. Refer to the '.lst' and '.log' buffers
+for monitoring output!
+
+ Troubleshooting: *Note iESS(SAS)--Common problems::.
+
+\1f
+File: ess.info, Node: iESS(SAS)--Common problems, Next: ESS(SAS)--Graphics, Prev: iESS(SAS)--Interactive SAS processes, Up: ESS for SAS
+
+13.7 iESS[SAS]-Common problems
+==============================
+
+ 1. iESS[SAS] does not work on Windows. In order to run SAS inside an
+ emacs buffer, it is necessary to start SAS with the '-stdio'
+ option. SAS does not support the '-stdio' option on Windows.
+ 2. If 'M-x SAS' gives errors upon startup, check the following:
+ * you are running Windows: see 1.
+ * 'ess-sas-sh-command' (from the ESS 'etc' directory) needs to
+ be executable; too check, type 'M-x dired'; if not, fix it as
+ follows, type 'M-:', then at the minibuffer prompt 'Eval:',
+ type '(set-file-modes "ess-sas-sh-command" 493)'.
+ * 'sas' isn't in your executable path; to verify, type 'M-:' and
+ at the minibuffer prompt 'Eval:', type '(executable-find
+ "sas")'
+ 3. 'M-x SAS' starts SAS Display Manager. Probably, the command 'sas'
+ on your system calls a shell script. In that case you will need to
+ locate the real 'sas' executable and link to it. You can execute
+ the UNIX command:
+ find / -name sas -print
+ Now place a soft link to the real 'sas' executable in your '~/bin'
+ directory, with for example
+ cd ~/bin
+ ln -s /usr/local/sas9/sas sas
+ Check your 'PATH' environment variable to confirm that '~/bin'
+appears before the directory in which the 'sas' shell script appears.
+
+\1f
+File: ess.info, Node: ESS(SAS)--Graphics, Next: ESS(SAS)--Windows, Prev: iESS(SAS)--Common problems, Up: ESS for SAS
+
+13.8 ESS[SAS]-Graphics
+======================
+
+Output from a SAS/GRAPH '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 <F12>, then include the following (either in 'FOO.sas' or in
+'~/autoexec.sas'):
+ filename gsasfile 'graphics.ps';
+ goptions device=ps gsfname=gsasfile gsfmode=append;
+ '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:
+ proc plot;
+ plot a*b / vpos=25;
+ run;
+
+\1f
+File: ess.info, Node: ESS(SAS)--Windows, Prev: ESS(SAS)--Graphics, Up: ESS for SAS
+
+13.9 ESS[SAS]-Windows
+=====================
+
+ * iESS[SAS] does not work on Windows. *Note iESS(SAS)--Common
+ problems::.
+
+ * ESS[SAS] mode for editing SAS language files works very well.
+ *Note ESS(SAS)--Editing files::.
+
+ * There are two execution options for SAS on Windows. You can use
+ batch. *Note 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.
+
+\1f
+File: ess.info, Node: ESS for BUGS, Next: ESS for JAGS, Prev: ESS for SAS, Up: Top
+
+14 ESS for BUGS
+***************
+
+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.
+
+14.1 ESS[BUGS]-Model files
+==========================
+
+Model files with the '.bug' extension are edited in ESS[BUGS] mode.
+Three keys are bound for your use in ESS[BUGS], 'F2', 'C-c C-c' and '='.
+'F2' performs the same action as it does in ESS[SAS], *Note
+ESS(SAS)--Function keys for batch processing::. 'C-c C-c' performs the
+function '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.
+'=' inserts the set operator, '<-'.
+
+14.2 ESS[BUGS]-Command files
+============================
+
+Files ending in '.bmd' are used for BUGS command files. When you have
+finished editing your model file and press 'C-c C-c', a command file is
+created if one does not already exist. When you are finished editing
+your command file, pressing 'C-c C-c' again will submit your command
+file as a batch job.
+
+14.3 ESS[BUGS]-Log files
+========================
+
+The '.bog' extension is used for BUGS log files. The command line
+generated by ESS creates the '.bog' transcript file.
+
+\1f
+File: ess.info, Node: ESS for JAGS, Next: Mailing lists/bug reports, Prev: ESS for BUGS, Up: Top
+
+15 ESS for JAGS
+***************
+
+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.
+
+15.1 ESS[JAGS]-Model files
+==========================
+
+Files with the '.jag' extension are edited in ESS[JAGS] mode. Three
+keys are bound for your use in ESS[JAGS], 'F2', 'C-c C-c' and '='. 'F2'
+performs the same action as it does in ESS[SAS], *Note
+ESS(SAS)--Function keys for batch processing::. 'C-c C-c' performs the
+function '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.
+'=' inserts the set operator, '<-'.
+
+ The first press of 'C-c C-c' will set up a template, including some
+necessary file-local variables in an empty buffer. These variables are
+'ess-jags-chains', 'ess-jags-monitor', 'ess-jags-thin',
+'ess-jags-burnin' and 'ess-jags-update'; they appear in the 'Local
+Variables' section. When you are finished editing your model file,
+pressing 'C-c C-c' will perform the necessary actions to build your
+command file for you.
+
+ The 'ess-jags-chains' variable is the number of chains that you want
+to initialize and sample from; defaults to 1. The 'ess-jags-monitor'
+variable is a list of variables that you want monitored: encase each
+variable in double quotes. When you press '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
+'ess-jags-thin' variable is the thinning parameter. By default, the
+thinning parameter is set to 1, i.e. no thinning. The
+'ess-jags-burnin' variable is the number of initial samples to discard.
+By default, the burnin parameter is set to 10000. The 'ess-jags-update'
+variable is the number of post-burnin samples to keep. By default, the
+update parameter is set to 10000. Both 'ess-jags-burnin' and
+'ess-jags-update' are multiplied by 'ess-jags-thin' since JAGS does not
+do it automatically.
+
+15.2 ESS[JAGS]-Command files
+============================
+
+Files ending in '.jmd' are for JAGS command files. For your '.jmd'
+file, there is only one variable, 'ess-jags-command', in the 'Local
+Variables' section. When you have finished editing your model file and
+press 'C-c C-c', a command file is created if one does not already
+exist. When you are finished editing your command file, pressing 'C-c
+C-c' again will submit your command file as a batch job. The
+'ess-jags-command' variable allows you to specify a different JAGS
+program to use to run your model; defaults to "jags".
+
+15.3 ESS[JAGS]-Log files
+========================
+
+The '.jog' extension is used for JAGS log files. You may find 'F2'
+useful to refresh the '.jog' if the batch process over-writes or appends
+it.
+
+\1f
+File: ess.info, Node: Mailing lists/bug reports, Next: Customization, Prev: ESS for JAGS, Up: Top
+
+16 Bugs and Bug Reporting, Mailing Lists
+****************************************
+
+* Menu:
+
+* Bugs::
+* Reporting Bugs::
+* Mailing Lists::
+* Help with Emacs::
+
+\1f
+File: ess.info, Node: Bugs, Next: Reporting Bugs, Up: Mailing lists/bug reports
+
+16.1 Bugs
+=========
+
+ * Commands like '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.
+
+ * The '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 _windows_ with 'window-point' at the right
+ place.
+
+ * It's possible to clear the modification flag (say, by saving the
+ buffer) with the edit buffer not having been loaded into S.
+
+ * Backup files can sometimes be left behind, even when
+ 'ess-keep-dump-files' is 'nil'.
+
+ * Passing an incomplete S expression to 'ess-execute' causes ESS to
+ hang.
+
+ * 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).
+
+ * Multi-line commands could be handled better by the command history
+ mechanism.
+
+ * Changes to the continuation prompt in R (e.g. '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 'inferior-ess-secondary-prompt' in
+ 'R-customize-alist'.
+
+\1f
+File: ess.info, Node: Reporting Bugs, Next: Mailing Lists, Prev: Bugs, Up: Mailing lists/bug reports
+
+16.2 Reporting Bugs
+===================
+
+Please send bug reports, suggestions etc. to <ESS-bugsNOSPAMr-project.org>,
+or post them on our github issue tracker
+(https://github.com/emacs-ess/ESS/issues)
+
+ The easiest way to do this is within Emacs by typing
+
+ '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.
+
+\1f
+File: ess.info, Node: Mailing Lists, Next: Help with Emacs, Prev: Reporting Bugs, Up: Mailing lists/bug reports
+
+16.3 Mailing Lists
+==================
+
+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 <ess-help-requestNOSPAMr-project.org>; contributions
+to the list may be mailed to <ess-helpNOSPAMr-project.org>. Rest assured,
+this is a fairly low-volume mailing list.
+
+ The purposes of the mailing list include
+
+ * helping users of ESS to get along with it.
+ * discussing aspects of using ESS.
+ * suggestions for improvements.
+ * announcements of new releases of ESS.
+ * posting small patches to ESS.
+
+\1f
+File: ess.info, Node: Help with Emacs, Prev: Mailing Lists, Up: Mailing lists/bug reports
+
+16.4 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 'M-x view-emacs-faq') and EmacsWiki
+(<https://www.emacswiki.org>). Please consult them before asking on the
+mailing list about issues that are not specific to ESS.
+
+\1f
+File: ess.info, Node: Customization, Next: Indices, Prev: Mailing lists/bug reports, Up: Top
+
+Appendix A Customizing ESS
+**************************
+
+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 '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.
+
+\1f
+File: ess.info, Node: Indices, Prev: Customization, Up: Top
+
+Indices
+*******
+
+* Menu:
+
+* Key index::
+* Function and program index::
+* Variable index::
+* Concept index::
+
+\1f
+File: ess.info, Node: Key index, Next: Function and program index, Up: Indices
+
+Key index
+=========
+
+\0\b[index\0\b]
+* Menu:
+
+* ,: Handy commands. (line 6)
+* {: Indenting. (line 53)
+* }: Indenting. (line 53)
+* C-c C-. d: Package listing. (line 30)
+* C-c C-. H: Package listing. (line 33)
+* C-c C-. l: Package listing. (line 10)
+* C-c C-. m: Package listing. (line 21)
+* C-c C-. r: Package listing. (line 13)
+* C-c C-. s: Package listing. (line 27)
+* C-c C-. u: Package listing. (line 17)
+* C-c C-. w: Package listing. (line 24)
+* C-c C-b: Evaluating code. (line 68)
+* C-c C-c: Other. (line 9)
+* C-c C-c <1>: Evaluating code. (line 41)
+* C-c C-e C-d: Edit buffer. (line 9)
+* C-c C-e C-s: Styles. (line 15)
+* C-c C-e s: Styles. (line 15)
+* C-c C-f: Evaluating code. (line 54)
+* C-c C-j: Evaluating code. (line 47)
+* C-c C-o C-c: roxygen2. (line 45)
+* C-c C-o C-h: roxygen2. (line 72)
+* C-c C-o C-o: roxygen2. (line 37)
+* C-c C-o C-r: roxygen2. (line 51)
+* C-c C-o C-t: roxygen2. (line 59)
+* C-c C-o n: roxygen2. (line 69)
+* C-c C-o p: roxygen2. (line 66)
+* C-c C-q: Hot keys. (line 71)
+* C-C C-r: Evaluating code. (line 61)
+* C-c C-s: Hot keys. (line 34)
+* C-c C-t C-s: Namespaced Evaluation.
+ (line 36)
+* C-c C-v: Hot keys. (line 66)
+* C-c C-w: Clean. (line 11)
+* C-c C-x: Hot keys. (line 24)
+* C-c C-z: Other. (line 13)
+* C-c M-b: Evaluating code. (line 71)
+* C-c M-f: Evaluating code. (line 57)
+* C-c M-j: Evaluating code. (line 50)
+* C-c M-l: Hot keys. (line 50)
+* C-c M-r: Evaluating code. (line 64)
+* C-c RET: Resubmit. (line 14)
+* C-c `: Error Checking. (line 9)
+* C-j: Indenting. (line 60)
+* C-M-a: Other edit buffer commands.
+ (line 10)
+* C-M-e: Other edit buffer commands.
+ (line 14)
+* C-M-h: Other edit buffer commands.
+ (line 18)
+* C-M-q: Indenting. (line 49)
+* C-M-x: Evaluating code. (line 38)
+* C-RET: Evaluating code. (line 34)
+* ESC C-a: Other edit buffer commands.
+ (line 10)
+* ESC C-e: Other edit buffer commands.
+ (line 14)
+* ESC C-h: Other edit buffer commands.
+ (line 18)
+* ESC C-q: Indenting. (line 49)
+* M-;: Indenting. (line 65)
+* M-?: Object names. (line 33)
+* M-C-q: Indenting. (line 49)
+* M-n l: Sweave and AUCTeX. (line 24)
+* M-n P: Sweave and AUCTeX. (line 30)
+* M-n s: Sweave and AUCTeX. (line 20)
+* M-RET: Resubmit. (line 10)
+* RET: Command-line editing. (line 10)
+* RET <1>: Resubmit. (line 18)
+* TAB: Indenting. (line 35)
+
+\1f
+File: ess.info, Node: Function and program index, Next: Variable index, Prev: Key index, Up: Indices
+
+Function and program index
+==========================
+
+\0\b[index\0\b]
+* Menu:
+
+* backward-kill-word: Command-line editing.
+ (line 22)
+* comint-backward-matching-input: Process buffer motion.
+ (line 31)
+* comint-bol: Command-line editing.
+ (line 31)
+* comint-copy-old-input: Transcript resubmit. (line 16)
+* comint-delete-output: Last command. (line 24)
+* comint-dynamic-complete: Object names. (line 12)
+* comint-forward-matching-input: Process buffer motion.
+ (line 32)
+* comint-history-isearch-backward-regexp: Command History. (line 32)
+* comint-interrupt-subjob: Other. (line 8)
+* comint-kill-input: Command-line editing.
+ (line 26)
+* comint-next-input: Command History. (line 18)
+* comint-next-matching-input-from-input: Command History. (line 45)
+* comint-next-prompt: Process buffer motion.
+ (line 15)
+* comint-previous-input: Command History. (line 14)
+* comint-previous-matching-input-from-input: Command History. (line 41)
+* comint-previous-prompt: Process buffer motion.
+ (line 11)
+* comint-show-output: Last command. (line 20)
+* dump(): Edit buffer. (line 35)
+* ess-change-directory: Package listing. (line 29)
+* ess-cleanup: Hot keys. (line 71)
+* ess-cleanup <1>: Help. (line 170)
+* ess-complete-object-name: Object names. (line 32)
+* ess-describe-help-mode: Help. (line 21)
+* ess-display-help-on-object: Hot keys. (line 65)
+* ess-display-help-on-object <1>: Help. (line 8)
+* ess-display-help-on-object <2>: Help. (line 25)
+* ess-dump-object-into-edit-buffer: Edit buffer. (line 8)
+* ess-electric-brace: Indenting. (line 52)
+* ess-eval-buffer: Evaluating code. (line 67)
+* ess-eval-buffer-and-go: Evaluating code. (line 70)
+* ess-eval-function: Evaluating code. (line 53)
+* ess-eval-function-and-go: Evaluating code. (line 56)
+* ess-eval-line: Evaluating code. (line 46)
+* ess-eval-line-and-go: Evaluating code. (line 49)
+* ess-eval-line-and-step: Help. (line 106)
+* ess-eval-region: Evaluating code. (line 60)
+* ess-eval-region <1>: Help. (line 111)
+* ess-eval-region-and-go: Evaluating code. (line 63)
+* ess-eval-region-or-function-or-paragraph: Evaluating code. (line 37)
+* ess-eval-region-or-function-or-paragraph-and-step: Evaluating code.
+ (line 40)
+* ess-eval-region-or-line-and-step: Evaluating code. (line 33)
+* ess-execute-objects: Hot keys. (line 23)
+* ess-execute-search: Hot keys. (line 33)
+* ess-goto-beginning-of-function-or-para: Other edit buffer commands.
+ (line 9)
+* ess-goto-end-of-function-or-para: Other edit buffer commands.
+ (line 13)
+* ess-handy-commands: Handy commands. (line 6)
+* ess-handy-commands <1>: Handy commands. (line 6)
+* ess-indent-command: roxygen2. (line 90)
+* ess-indent-exp: Indenting. (line 48)
+* ess-indent-or-complete: Indenting. (line 34)
+* ess-load-file: Hot keys. (line 49)
+* ess-load-file <1>: Loading. (line 11)
+* ess-mark-function: Other edit buffer commands.
+ (line 17)
+* ess-parse-errors: Hot keys. (line 54)
+* ess-parse-errors <1>: Error Checking. (line 9)
+* ess-quit: Hot keys. (line 70)
+* ess-quit <1>: Help. (line 170)
+* ess-R-complete-object-name: roxygen2. (line 80)
+* ess-r-package-list-available-packages: Package listing. (line 12)
+* ess-r-package-list-local-packages: Package listing. (line 9)
+* ess-r-package-update-packages: Package listing. (line 16)
+* ess-r-set-evaluation-env: Namespaced Evaluation.
+ (line 35)
+* ess-remote: ESS processes on Remote Computers.
+ (line 9)
+* ess-request-a-process: Multiple ESS processes.
+ (line 18)
+* ess-resynch: Object names. (line 52)
+* ess-roxy-hide-all: roxygen2. (line 71)
+* ess-roxy-move-beginning-of-line: roxygen2. (line 97)
+* ess-roxy-next-entry: roxygen2. (line 68)
+* ess-roxy-preview-HTML: roxygen2. (line 58)
+* ess-roxy-preview-Rd: roxygen2. (line 50)
+* ess-roxy-previous-entry: roxygen2. (line 65)
+* ess-roxy-toggle-roxy-region: roxygen2. (line 44)
+* ess-roxy-update-entry: roxygen2. (line 36)
+* ess-rutils-html-docs: Package listing. (line 32)
+* ess-rutils-load-workspace: Package listing. (line 23)
+* ess-rutils-rm-all: Package listing. (line 20)
+* ess-rutils-save-workspace: Package listing. (line 26)
+* ess-set-style: Styles. (line 14)
+* ess-skip-to-help-section: Help. (line 55)
+* ess-skip-to-next-section: Help. (line 46)
+* ess-skip-to-previous-section: Help. (line 46)
+* ess-smart-comma: Handy commands. (line 6)
+* ess-submit-bug-report: Reporting Bugs. (line 6)
+* ess-switch-to-end-of-ESS: Help. (line 117)
+* ess-switch-to-inferior-or-script-buffer: Other. (line 12)
+* ess-swv-latex: Sweave and AUCTeX. (line 23)
+* ess-swv-PDF: Sweave and AUCTeX. (line 29)
+* ess-swv-PS: Sweave and AUCTeX. (line 26)
+* ess-swv-weave: Sweave and AUCTeX. (line 19)
+* ess-tracebug: ESS tracebug. (line 6)
+* ess-transcript-clean-region: Clean. (line 10)
+* ess-transcript-copy-command: Resubmit. (line 13)
+* ess-transcript-send-command: Resubmit. (line 9)
+* ess-transcript-send-command-and-move: Resubmit. (line 17)
+* ess-use-ido, ess-completing-read: Minibuffer completion.
+ (line 6)
+* fill-paragraph: roxygen2. (line 94)
+* getting started with tracebug: Getting started with tracebug.
+ (line 6)
+* inferior-ess-send-input: Command-line editing.
+ (line 9)
+* mark-paragraph: roxygen2. (line 85)
+* newline-and-indent: roxygen2. (line 102)
+* objects(): Hot keys. (line 24)
+* printer(): printer. (line 11)
+* q(): Hot keys. (line 71)
+* R: Starting up. (line 11)
+* S: Starting up. (line 11)
+* search(): Hot keys. (line 34)
+* search() <1>: Object names. (line 19)
+* source(): Evaluating code. (line 20)
+* source() <1>: Loading. (line 11)
+* STERM: Statistical Process running in ESS?.
+ (line 6)
+
+\1f
+File: ess.info, Node: Variable index, Next: Concept index, Prev: Function and program index, Up: Indices
+
+Variable index
+==============
+
+\0\b[index\0\b]
+* Menu:
+
+* comint-delimiter-argument-list: History expansion. (line 28)
+* comint-input-ring-size: Command History. (line 9)
+* comment-column: Indenting. (line 24)
+* ess-ask-about-transfile: Customizing startup. (line 36)
+* ess-ask-about-transfile <1>: Saving transcripts. (line 12)
+* ess-ask-for-ess-directory: Customizing startup. (line 7)
+* ess-ask-for-ess-directory <1>: Customizing startup. (line 21)
+* ess-auto-width: Customizing startup. (line 56)
+* ess-auto-width-visible: Customizing startup. (line 56)
+* ess-delete-dump-files: Source Files. (line 12)
+* ess-directory: Source Directories. (line 48)
+* ess-dump-filename-template: Source Directories. (line 9)
+* ess-eldoc-abbreviation-style: ESS ElDoc. (line 24)
+* ess-eldoc-show-on-symbol: ESS ElDoc. (line 18)
+* ess-eval-visibly: Evaluating code. (line 14)
+* ess-execute-in-process-buffer: Hot keys. (line 13)
+* ess-first-tab-never-complete: Indenting. (line 42)
+* ess-first-tab-never-complete <1>: Object names. (line 6)
+* ess-function-template: Edit buffer. (line 17)
+* ess-handy-commands: Handy commands. (line 6)
+* ess-handy-commands <1>: Handy commands. (line 9)
+* ess-indent-with-fancy-comments: Indenting. (line 27)
+* ess-keep-dump-files: Source Files. (line 26)
+* ess-plain-first-buffername: Multiple ESS processes.
+ (line 14)
+* ess-post-run-hook: Customizing startup. (line 26)
+* ess-pre-run-hook: Customizing startup. (line 21)
+* ess-r-flymake-linters: ESS Flymake. (line 16)
+* ess-r-flymake-lintr-cache: ESS Flymake. (line 23)
+* ess-R-font-lock-keywords: Highlighting. (line 19)
+* ess-search-list: Source Directories. (line 62)
+* ess-source-directory: Source Directories. (line 22)
+* ess-style: Styles. (line 21)
+* ess-style-alist: Styles. (line 28)
+* ess-switch-to-end-of-proc-buffer: Other. (line 21)
+* ess-swv-pdflatex-commands: Sweave and AUCTeX. (line 35)
+* ess-use-eldoc: ESS ElDoc. (line 13)
+* ess-use-flymake: ESS Flymake. (line 12)
+* iESS program arguments: Customizing startup. (line 48)
+* inferior-ess-program: Customizing startup. (line 48)
+* inferior-R-font-lock-keywords: Highlighting. (line 12)
+* Rd-indent-level: R documentation files.
+ (line 78)
+* Rd-mode-hook: R documentation files.
+ (line 75)
+* Rd-to-help-command: R documentation files.
+ (line 82)
+
+\1f
+File: ess.info, Node: Concept index, Prev: Variable index, Up: Indices
+
+Concept Index
+=============
+
+\0\b[index\0\b]
+* Menu:
+
+* aborting R commands: Other. (line 9)
+* aborting S commands: Other. (line 9)
+* arguments to R program: Customizing startup. (line 51)
+* arguments to S program: Customizing startup. (line 51)
+* authors: Credits. (line 6)
+* autosaving: Source Files. (line 83)
+* bug reports: Reporting Bugs. (line 6)
+* bugs: Bugs. (line 6)
+* changing ESS processes: Multiple ESS processes.
+ (line 6)
+* cleaning up: Hot keys. (line 71)
+* comint: Credits. (line 6)
+* command history: Command History. (line 6)
+* command line arguments: iESS(R)--Inferior ESS processes.
+ (line 16)
+* command-line completion: Object names. (line 6)
+* command-line editing: Command-line editing.
+ (line 6)
+* commands: Entering commands. (line 6)
+* comments: Source Files. (line 41)
+* comments in R: Indenting. (line 18)
+* company: Company. (line 6)
+* completion in edit buffer: Other edit buffer commands.
+ (line 24)
+* completion of object names: Object names. (line 6)
+* completion on file names: Object names. (line 39)
+* completion on lists: Object names. (line 37)
+* completion, when prompted for object names: Edit buffer. (line 14)
+* creating new objects: Edit buffer. (line 14)
+* credits: Credits. (line 6)
+* customization: Customization. (line 6)
+* data frames: Object names. (line 20)
+* deleting output: Last command. (line 24)
+* directories: Starting up. (line 11)
+* dump file directories: Source Directories. (line 20)
+* dump file names: Source Directories. (line 6)
+* dump files: Edit buffer. (line 27)
+* dump files <1>: Source Files. (line 10)
+* echoing commands when evaluating: Evaluating code. (line 20)
+* edit buffer: Edit buffer. (line 6)
+* editing commands: Command History. (line 6)
+* editing functions: Editing objects. (line 6)
+* editing transcripts: Saving transcripts. (line 18)
+* ElDoc: ESS ElDoc. (line 6)
+* emacsclient: Emacsclient. (line 6)
+* entering commands: Entering commands. (line 6)
+* errors: Error Checking. (line 6)
+* ESS commands blocking Emacs: Evaluating code. (line 20)
+* ess developer: Namespaced Evaluation.
+ (line 6)
+* ESS process buffer: Starting up. (line 17)
+* ESS process directory: Starting up. (line 11)
+* ESS tracebug: ESS tracebug. (line 6)
+* ESS-elsewhere: ESS processes on Remote Computers.
+ (line 9)
+* ess-roxy: roxygen2. (line 6)
+* evaluating code with echoed commands: Evaluating code. (line 20)
+* evaluating R expressions: Evaluating code. (line 31)
+* evaluating S expressions: Evaluating code. (line 31)
+* finding function definitions: Xref. (line 6)
+* flymake: ESS Flymake. (line 6)
+* font-lock mode: Highlighting. (line 7)
+* formatting source code: Indenting. (line 32)
+* graphics: Graphics. (line 6)
+* Handy commands: Handy commands. (line 6)
+* help files: Help. (line 6)
+* highlighting: Highlighting. (line 7)
+* historic backups: Source Files. (line 41)
+* hot keys: Hot keys. (line 43)
+* icicles: Icicles. (line 6)
+* IDO completions: Minibuffer completion.
+ (line 6)
+* indenting: Indenting. (line 32)
+* installation: Installation. (line 6)
+* interactive use of R: Introduction. (line 31)
+* interactive use of S: Introduction. (line 31)
+* interrupting R commands: Other. (line 9)
+* interrupting S commands: Other. (line 9)
+* introduction: Introduction. (line 6)
+* keyboard short cuts: Hot keys. (line 43)
+* killing temporary buffers: Hot keys. (line 71)
+* killing the ESS process: Hot keys. (line 71)
+* lists, completion on: Object names. (line 37)
+* motion in transcript mode: Transcript Mode. (line 17)
+* multi-line commands, resubmitting: Transcript resubmit. (line 33)
+* multiple ESS processes: Multiple ESS processes.
+ (line 6)
+* multiple inferior processes: Multiple ESS processes.
+ (line 6)
+* multiple interactive processes: Multiple ESS processes.
+ (line 6)
+* new objects, creating: Edit buffer. (line 14)
+* objects: Hot keys. (line 24)
+* pages in the process buffer: Transcript. (line 24)
+* paging commands in help buffers: Help. (line 28)
+* paragraphs in the process buffer: Transcript. (line 13)
+* parsing errors: Error Checking. (line 6)
+* process buffer: Starting up. (line 17)
+* process names: Multiple ESS processes.
+ (line 8)
+* programming in R: Introduction. (line 43)
+* programming in S: Introduction. (line 43)
+* project work in R: Source Files. (line 41)
+* project work in S: Source Files. (line 41)
+* quitting from ESS: Hot keys. (line 71)
+* re-executing commands: Command History. (line 6)
+* reading long command outputs: Last command. (line 19)
+* remote Computers: ESS processes on Remote Computers.
+ (line 9)
+* reverting function definitions: Edit buffer. (line 27)
+* roxy: roxygen2. (line 6)
+* roxygen2: roxygen2. (line 6)
+* running R: Starting up. (line 6)
+* running S: Starting up. (line 6)
+* S+elsewhere: ESS processes on Remote Computers.
+ (line 9)
+* search list: Hot keys. (line 34)
+* search list <1>: Source Directories. (line 55)
+* sending input: Entering commands. (line 6)
+* Space in function argument completion: Function arguments. (line 10)
+* starting directory: Starting up. (line 11)
+* starting ESS: Starting up. (line 6)
+* STERM: Statistical Process running in ESS?.
+ (line 6)
+* temporary buffers: Help. (line 169)
+* temporary buffers, killing: Hot keys. (line 71)
+* tracebug tutorial: Getting started with tracebug.
+ (line 6)
+* tramp support: ESS processes on Remote Computers.
+ (line 9)
+* transcript: Transcript. (line 9)
+* transcript file: Customizing startup. (line 40)
+* transcript file names: Saving transcripts. (line 13)
+* transcript mode motion: Transcript Mode. (line 17)
+* transcripts of R sessions: Introduction. (line 38)
+* transcripts of S sessions: Introduction. (line 38)
+* using ESS interactively: Introduction. (line 31)
+* using R interactively: Introduction. (line 31)
+* using S interactively: Introduction. (line 31)
+* winjava: winjava. (line 6)
+* working directory: Starting up. (line 11)
+* working directory <1>: Source Directories. (line 55)
+* X Windows: X11. (line 6)
+* xref: Xref. (line 6)
+
+
+\1f
+Tag Table:
+Node: Top\7f268
+Node: Introduction\7f2914
+Node: Features\7f5668
+Node: Current Features\7f6494
+Node: New features\7f9945
+Node: Credits\7f35243
+Node: Manual\7f38860
+Node: Installation\7f41526
+Node: Installing from a third-party repository\7f42463
+Node: Installing from source\7f43410
+Node: Activating and Loading ESS\7f45002
+Node: Check Installation\7f46076
+Node: Interactive ESS\7f46296
+Node: Starting up\7f47141
+Node: Multiple ESS processes\7f47885
+Node: ESS processes on Remote Computers\7f48966
+Node: Customizing startup\7f53069
+Node: Controlling buffer display\7f55959
+Node: Entering commands\7f58580
+Node: Command-line editing\7f59738
+Node: Transcript\7f60971
+Node: Last command\7f62740
+Node: Process buffer motion\7f64166
+Node: Transcript resubmit\7f65669
+Node: Saving transcripts\7f67634
+Node: Command History\7f69424
+Node: Saving History\7f72833
+Node: History expansion\7f73594
+Node: Hot keys\7f76805
+Node: Statistical Process running in ESS?\7f80875
+Node: Emacsclient\7f82154
+Node: Other\7f82946
+Node: Evaluating code\7f83965
+Node: Transcript Mode\7f87761
+Node: Resubmit\7f88914
+Node: Clean\7f89977
+Node: Editing objects\7f90973
+Node: Edit buffer\7f92091
+Node: Loading\7f94137
+Node: Error Checking\7f95164
+Node: Indenting\7f96213
+Node: Styles\7f99257
+Node: Other edit buffer commands\7f101631
+Node: Source Files\7f103287
+Node: Source Directories\7f107891
+Node: Help\7f111044
+Node: Completion\7f115490
+Node: Object names\7f115705
+Node: Function arguments\7f118339
+Node: Minibuffer completion\7f119282
+Node: Company\7f119756
+Node: Icicles\7f120143
+Node: Developing with ESS\7f121463
+Node: ESS tracebug\7f121909
+Node: Getting started with tracebug\7f124916
+Node: Editing documentation\7f127074
+Node: R documentation files\7f127626
+Node: roxygen2\7f131329
+Node: Namespaced Evaluation\7f135740
+Node: Extras\7f137738
+Node: ESS ElDoc\7f138762
+Node: ESS Flymake\7f140258
+Node: Handy commands\7f141352
+Node: Highlighting\7f142549
+Node: Parens\7f143584
+Node: Graphics\7f144060
+Node: printer\7f144731
+Node: X11\7f145487
+Node: winjava\7f145826
+Node: Imenu\7f146238
+Node: Toolbar\7f147085
+Node: Xref\7f147493
+Node: Rdired\7f147821
+Node: Package listing\7f148884
+Node: Org\7f150268
+Node: Sweave and AUCTeX\7f151222
+Node: ESS for R\7f153774
+Node: ESS(R)--Editing files\7f154074
+Node: iESS(R)--Inferior ESS processes\7f154575
+Node: Philosophies for using ESS(R)\7f157230
+Node: Example ESS usage\7f158157
+Node: ESS for SAS\7f159562
+Node: ESS(SAS)--Design philosophy\7f160285
+Node: ESS(SAS)--Editing files\7f161218
+Node: ESS(SAS)--TAB key\7f163072
+Node: ESS(SAS)--Batch SAS processes\7f164438
+Node: ESS(SAS)--Function keys for batch processing\7f169466
+Node: iESS(SAS)--Interactive SAS processes\7f178953
+Node: iESS(SAS)--Common problems\7f182707
+Node: ESS(SAS)--Graphics\7f184230
+Node: ESS(SAS)--Windows\7f185013
+Node: ESS for BUGS\7f185591
+Node: ESS for JAGS\7f187347
+Node: Mailing lists/bug reports\7f190699
+Node: Bugs\7f190963
+Node: Reporting Bugs\7f192587
+Node: Mailing Lists\7f193480
+Node: Help with Emacs\7f194207
+Node: Customization\7f194739
+Node: Indices\7f195513
+Node: Key index\7f195688
+Node: Function and program index\7f200820
+Node: Variable index\7f210240
+Node: Concept index\7f213801
+\1f
+End Tag Table
+
+\1f
+Local Variables:
+coding: utf-8
+End:
--- /dev/null
+;;; 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 <rmhNOSPAMtemple.edu>
+;; Created: December 1998
+;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
+
+;;; 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
+;; <http://www.gnu.org/licenses/>
+
+;;; 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))))
+
+
+\f ; Provide package
+
+(provide 'essd-els)
+
+;;; essd-els.el ends here
--- /dev/null
+#!/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")
--- /dev/null
+## -*- 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)
+ })
+})
--- /dev/null
+#### 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('\1e\1eESSR::ERROR \"', conditionMessage(cnd), '\"\1e\1e')
+ }
+
+ 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
+}
--- /dev/null
+## 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)
+}
--- /dev/null
+## 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")
+ }
+})
+
+\f
+.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)
+}
+
+\f
+.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))
+ }
+}
+
+\f
+.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')
+}
--- /dev/null
+### 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)
+}
+
+\f
+.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))
+}
+
+\f
+.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)
+ }))
+}
+
+\f
+### 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' ))
+ }
+ }
+}
+
+\f
+.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)
+}
+
+\f
+.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
+ }
+}
--- /dev/null
+.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)
+}
+
+\f
+.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)
+}
+
+\f
+.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")
+}
+
+\f
+.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)
+}
--- /dev/null
+## 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 = "\1e")
+ cat(sprintf("\e_%s\1e%s\e\\", 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)
+}
+
--- /dev/null
+## 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)
+}
+
+\f
+##' 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)
+}
+
+\f
+.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
+}
+
+\f
+.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)
+}
+
+\f
+.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
+}
+
+\f
+.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)
+}
--- /dev/null
+
+.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
+}
--- /dev/null
+### 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
--- /dev/null
+module 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
+
+\f
+### 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
+
+\f
+### 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
--- /dev/null
+#!/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 </dev/tty 1>$1 2>$2 $3
+
+set -x
+stdout=$1
+stderr=$2
+shift 2
+set +x
+echo sas \</dev/tty 1\>$stdout 2\>$stderr $@
+sas </dev/tty 1>$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.
--- /dev/null
+;;; 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 <ESS-coreNOSPAMr-project.org>
+
+;; 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
+;; <http://www.gnu.org/licenses/>
+
+;;; 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
--- /dev/null
+;;; ess-font-lock.el --- font-lock color options -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2000-2022 Free Software Foundation, Inc.
+
+;; Author: Richard M. Heiberger <rmhNOSPAMtemple.edu>
+;; 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 <David.BrahmNOSPAMfmr.com>"
+ ;; 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
--- /dev/null
+;;; 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 <rmhNOSPAMtemple.edu>
+;; Created: 25 Mar 2001
+;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
+
+;; 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
+;; <http://www.gnu.org/licenses/>
+
+;;; 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:
+
+\f ; 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))))
+
+
+\f ; 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
--- /dev/null
+;;; 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 <blindglobeNOSPAMgmail.com>
+;; Created: 17 November 1999
+;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
+
+;; 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
+;; <http://www.gnu.org/licenses/>
+
+;;; 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))
+
+
+\f ; Provide package
+
+(provide 'ess-r-a)
+
+;;; ess-r-a.el ends here
--- /dev/null
+;;; 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 <howardNOSPAMsilverstream.com>
+;; 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
+;; <http://www.gnu.org/licenses/>
+
+;;; 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:
+;; <URL:http://foo.bar.com/sss/ss.html>
+;; <http://foo.bar.com/sss/ss.html>
+;; http://foo.bar.com/sss/ss.html
+;; http://www.ditherdog.com/howard/
+;; mailto:howardNOSPAMsilverstream.com
+;; howardNOSPAMsilverstream.com
+;; <howardNOSPAMsilverstream.com>
+;; import com.sssw.srv.agents.AgentsRsrc;
+;; public AgoHttpRequestEvent(Object o, String db, Request r)
+;; <DIV><A href=3D"http://www.amazon.com/exec/obidos/ASIN/156592391X"><IMG =
+;; <A HREF="http://www.suntimes.com/ebert/ebert.html">
+;; 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
--- /dev/null
+;;; 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 <rmhNOSPAMtemple.edu>
+;; Created: February 1999
+;; Maintainer: ESS-core <ESS-coreNOSPAMr-project.org>
+
+;; 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
+;; <http://www.gnu.org/licenses/>
+
+;;; 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