summaryrefslogtreecommitdiff
path: root/lisp/ess-mode.el
diff options
context:
space:
mode:
authorAlex Branham <branham@utexas.edu>2018-07-11 17:51:13 -0500
committerVitalie Spinu <spinuvit@gmail.com>2018-07-13 00:38:33 +0200
commit1b388017a97b4b2c15b41b41e2df455180e61339 (patch)
tree946149660202714ca3be627aaecde1e875d05b14 /lisp/ess-mode.el
parent4697717b89103b432a868f583e829a705a4d0623 (diff)
Rename ess-mode.el to ess.el
This lets people defer loading ESS and instead rely on autoloads. You can do something like the following: (with-eval-after-load "ess" <ess-config-here>) as well as use `use-package': (use-package ess :bind (:map ess-mode-map ("=" . ess-cycle-assignment)) :config (setq ess-ask-for-ess-directory nil)) and then ESS will only load what it needs when it needs it, rather than the traditional (require 'ess-site), which is rather expensive. Closes #592
Diffstat (limited to 'lisp/ess-mode.el')
-rw-r--r--lisp/ess-mode.el1019
1 files changed, 0 insertions, 1019 deletions
diff --git a/lisp/ess-mode.el b/lisp/ess-mode.el
deleted file mode 100644
index e102ef9..0000000
--- a/lisp/ess-mode.el
+++ /dev/null
@@ -1,1019 +0,0 @@
-;;; ess-mode.el --- Support for editing ESS source code
-
-;; Copyright (C) 1989-1994 Doug Bates, Ed Kademan, Frank Ritter, David Smith.
-;; 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: David Smith <dsmith@stats.adelaide.edu.au>
-;; Created: 7 Jan 1994
-;; 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
-;; http://www.r-project.org/Licenses/
-
-;;; Commentary:
-
-;; Code for editing ESS source code.
-
-;;; Code:
-
-(eval-when-compile
- (require 'cl)
- (require 'cl-lib))
-(require 'ess-custom)
-(require 'ess-utils)
-(require 'ess-generics)
-(require 'ess-inf)
-
-;; FIXME: should this be optional?
-(require 'ess-noweb-mode)
-
- ; ESS mode
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;;; In this section:
-;;;;
-;;;; * The major mode ess-mode
-;;;; * Commands for ess-mode
-;;;; * Code evaluation commands
-;;;; * Indenting code and commands
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-;;*;; Major mode definition
-
-(defvar ess-mode-map
- (let ((map (make-sparse-keymap)))
-
- ;; By popular demand:
- (define-key map (kbd "RET") 'ess-newline-and-indent)
- (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-and-step)
- (define-key map "\C-c\C-j" 'ess-eval-line)
- (define-key map [(control return)] 'ess-eval-region-or-line-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-y" 'ess-switch-to-ESS-deprecated)
- (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\t" 'ess-complete-object-name-deprecated)
- (define-key map "\M-?" 'ess-list-object-completions)
- (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)
- (when ess-smart-S-assign-key
- (define-key map ess-smart-S-assign-key 'ess-insert-assign))
- (define-key map (kbd "C-c C-=") 'ess-cycle-assignment)
- 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
- ["What is this? (beta)" ess-mouse-me t]
- ["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-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-versions-create' 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))
- "------"
- ("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" ess-eval-region-or-line-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]
- ["Eval chunk" ess-eval-chunk ess-noweb-mode]
- ["Eval chunk and step" ess-eval-chunk-and-step ess-noweb-mode]
- ["Eval thread" ess-eval-thread ess-noweb-mode]
- ["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]
- ["Eval chunk" ess-eval-chunk-and-go ess-noweb-mode]
- ["Eval thread" ess-eval-thread-and-go ess-noweb-mode]
- ["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
-(defun ess-mode (&optional alist proc-name is-derived)
- "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}
-
-Extra binding to note: 'ESC C-\\' indent-region.
-
-Entry to this mode runs the hooks in ess-mode-hook.
-
-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-beginning-of-function' and `ess-end-of-function' move the point to
- the beginning and end of the current ESS function.
- `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-tab-always-indent'
- Non-nil means TAB in ESS mode should always reindent the current line,
- regardless of where in the line point is when the TAB command is used.
- `ess-auto-newline'
- Non-nil means automatically newline before and after braces inserted in S
- code.
- `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. At present, predefined style are `BSD', `GNU', `K&R', `C++',
-`CLB' (quoted from C language style)."
- (setq alist (or alist
- (buffer-local-value 'ess-local-customize-alist (current-buffer))
- (error "Customise alist is not specified, nor ess-local-customize-alist is set.")))
- (unless is-derived
- (kill-all-local-variables)) ;; NOTICE THIS! *** NOTICE THIS! *** NOTICE THIS! ***
- (ess-setq-vars-local alist)
- (ess-write-to-dribble-buffer
- (format "(ess-mode-1): ess-language=%s, ess-dialect=%s buf=%s \n"
- ess-language
- ess-dialect
- (current-buffer)))
- ;; (ess-write-to-dribble-buffer
- ;; (format "(ess-mode-1.2): ess-process=%s \n"
- ;; (ess-local-process-name ess-local-process-name "none")))
- (ess-write-to-dribble-buffer
- (format "(ess-mode-1.5): alist=%s \n" alist))
- (unless is-derived
- (setq major-mode 'ess-mode)
- (setq mode-name (concat "ESS[" (or ess-dialect ess-language) "]")))
- ;; The following line does the next 20 or so :-).
- (ess-write-to-dribble-buffer
- (format "(ess-mode-1.6): editing-alist=%s \n"
- ess-mode-editing-alist))
- (ess-setq-vars-local ess-mode-editing-alist)
-
- (ess-set-style ess-style t)
- (use-local-map ess-mode-map)
- (when ess-mode-syntax-table
- (set-syntax-table ess-mode-syntax-table))
-
- ;; Keep <tabs> out of the code.
- (make-local-variable 'indent-tabs-mode)
- (setq indent-tabs-mode nil)
-
- (put 'ess-local-process-name 'permanent-local t) ; protect from RCS
- (setq mode-line-process
- '(" ["
- (:eval (ess--get-mode-line-indicator))
- ess--local-mode-line-process-indicator
- "]"))
- ;; completion
- (add-hook 'comint-dynamic-complete-functions 'ess-complete-filename nil 'local)
- (delq t comint-dynamic-complete-functions)
- (set (make-local-variable 'comint-completion-addsuffix)
- (cons "/" ""))
-
- (add-hook 'ess-idle-timer-functions 'ess-synchronize-dirs nil 'local)
- (ess-load-extras)
- (run-mode-hooks 'prog-mode-hook)
- (run-mode-hooks 'ess-mode-hook)
- (ess-write-to-dribble-buffer "\nFinished setting up ESS-mode.\n"))
-
-;; Set parent to `prog-mode'
-(put 'ess-mode 'derived-mode-parent 'prog-mode)
-(set-keymap-parent ess-mode-map prog-mode-map)
-
-(defun ess--get-mode-line-indicator ()
- "Get `ess--mode-line-process-indicator' from process buffer.
-Internal function to be used for dynamic mode-line dysplay 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"))
-
-
-;;*;; Dispatching infrastructure for dialects
-
-(defvar ess--make-local-vars-permanent nil
- "If this variable is non-nil in a buffer make all variable permannet.
-Used in noweb modes.")
-(make-variable-buffer-local 'ess--make-local-vars-permanent)
-(put 'ess--make-local-vars-permanent 'permanent-local t)
-
-(defun ess-setq-vars-local (alist &optional buf)
- "Set language variables from ALIST, in buffer BUF, if desired."
- (if buf (set-buffer buf))
- (mapc (lambda (pair)
- (make-local-variable (car pair))
- (set (car pair) (eval (cdr pair)))
- (when ess--make-local-vars-permanent
- (put (car pair) 'permanent-local t)) ;; hack for Rnw
- )
- alist)
- (ess-write-to-dribble-buffer
- (format "(ess-setq-vars-LOCAL): language=%s, dialect=%s, buf=%s, comint..echoes=%s, comint..sender=%s\n"
- ess-language ess-dialect buf comint-process-echoes comint-input-sender)))
-
-(defun ess-setq-vars-default (alist &optional buf)
- "Set language variables from ALIST, in buffer BUF, if desired."
- (ess-write-to-dribble-buffer
- (format "ess-setq-vars-default 0: ess-language=%s, -dialect=%s, buf=%s, comint..echoes=%s, comint..sender=%s\n"
- ess-language ess-dialect buf comint-process-echoes comint-input-sender))
- (if buf (set-buffer buf))
- (mapc (lambda (pair)
- (set-default (car pair) (eval (cdr pair))))
- alist)
- (ess-write-to-dribble-buffer
- (format "ess-setq-vars-default 1: ess-language=%s, -dialect=%s, buf=%s, comint..echoes=%s, comint..sender=%s\n"
- ess-language ess-dialect buf comint-process-echoes comint-input-sender)))
-
-
-;;*;; User commands in ess-mode
-
-;;;*;;; Miscellaneous
-
-(defun ess-install-library ()
- "Install library/package for current dialect.
-Currently works only for R."
- (interactive)
- (cond
- ((fboundp ess-install-library-function)
- (funcall ess-install-library-function))
- (t
- (error "Sorry, not available for %s" ess-dialect))))
-
-
-;;;*;;; Motion / manipulation commands
-
-(defun ess-beginning-of-function (&optional no-error)
- "Leave (and return) the point at the beginning of the current ESS function.
-If the optional argument NO-ERROR is non-nil, the function returns nil when
-it cannot find a function beginning."
- ;; FIXME: should not throw error in accordance with beginning-of-defun and
- ;; beginning-of-defun-function specification
- ;; FIXME: should __WORK__ in the crucial case: large function w/ internal function defs
- (interactive)
- (let ((init-point (point))
- (in-set-S4 nil)
- beg end done)
-
- ;; Note that we must be sure that we are past the 'function (' text,
- ;; such that ess-function-pattern is found in BACKwards later.
- ;; In case we're sitting in a function or setMethod() header,
- ;; we need to move further.
- ;; But not too far! {wrongly getting into next function}
- (if (search-forward "("
- (ess-line-end-position 2) t) ; at most end of next line
- (forward-char 1))
- ;; TODO: replace the above by hopefully more sucessful logic:
- ;; 1. If we have 'function *(' in the same line, move to end of that line
- ;; 2. if *not*, skip all comment lines (concat space comment-char .* "\n")
- ;; and only* then do something like the
- ;; (search-forward '(' .. (..line-end.. 2) ) above
-
- (setq end (point)) ; = init-point when nothing found
-
- (ess-write-to-dribble-buffer
- (format "ess-BEG-of-fun after 'search-FWD (': Ini-pt %d, (p)-Ini-pt = %d\n"
- init-point (- end init-point)))
- (if (and (> end 1)
- (re-search-backward ;; in case of setMethod() etc ..
- ess-r-set-function-start
- ;; at most 1 line earlier {2 is too much: finds previous sometimes}
- (+ 1 (ess-line-end-position -1)) t))
-
- (progn ;; yes we *have* an S4 setMethod(..)-like
- (setq in-set-S4 t
- beg (point))
- (ess-write-to-dribble-buffer
- (format " set*() function start at position %d" beg))
- ;; often need to move even further to have 'function(' to our left
- ;; (if (search-forward "function" end t)
- ;; (ess-write-to-dribble-buffer
- ;; (format " -> 'function' already at pos %d\n" (point)))
- ;; ;; else need to move further
- (goto-char end)
- ;; search 4 lines, we are pretty sure now:
- (search-forward
- "function" (ess-line-end-position 4) t)
- ;; )
- (search-forward "(" (ess-line-end-position) t))
- ;; else: regular function; no set*Method(..)
- (ess-write-to-dribble-buffer "ELSE not in setMethod() header ...\n"))
-
- (while (not done)
- ;; Need this while loop to skip over local function definitions
-
- ;; In the case of non-success, it is inefficiently
- ;; going back in the buffer through all function definitions...
- (unless
- (and (re-search-backward ess-function-pattern (point-min) t)
- (not (ess-inside-string-or-comment-p (point))))
- (goto-char init-point)
- (if no-error
- (setq done t beg nil)
- ;; else [default]:
- (error "Point is not in a function according to 'ess-function-pattern'.")))
- (unless done
- (setq beg (point))
- (ess-write-to-dribble-buffer
- (format "\tMatch,Pt:(%d,%d),%d\n"
- (match-beginning 0) (match-end 0) beg))
- (setq in-set-S4 (looking-at ess-r-set-function-start))
- (forward-list 1) ; get over arguments
-
- ;; The following used to bomb "Unbalanced parentheses", n1, n2
- ;; when the above (search-forward "(" ..) wasn't delimited :
- (unless in-set-S4 (forward-sexp 1)) ; move over braces
- ;;DBG (ess-write-to-dribble-buffer "|")
- (setq end (point))
- (goto-char beg)
- ;; current function must begin and end around point
- (setq done (and (>= end init-point) (<= beg init-point)))))
- beg))
-
-(defun ess-end-of-function (&optional beginning no-error)
- "Leave the point at the end of the current ESS function.
-Optional argument for location of beginning. Return '(beg end)."
- (interactive)
- (if beginning
- (goto-char beginning)
- (setq beginning (ess-beginning-of-function no-error)))
- (if beginning
- ;; *hack* only for S (R || S+): are we in setMethod(..) etc?
- (let ((in-set-S4 (looking-at ess-r-set-function-start))
- (end-pos) (npos))
- (ess-write-to-dribble-buffer
- (format "ess-END-of-fun: S4=%s, beginning = %d\n" in-set-S4 beginning))
- (forward-list 1) ; get over arguments || whole set*(..)
- (unless in-set-S4 (forward-sexp 1)) ; move over braces
- (ess-write-to-dribble-buffer
- (format "ess-END-of-fun: found #1 : %d\n" (point)))
-
- ;; For one-line functions withOUT '{ .. }' body -- added 2008-07-23 --
- ;; particularly helpful for C-c C-c (ess-eval-function-or-paragraph-and-step):
- (setq end-pos (ess-line-end-position))
- (while (< (point) end-pos) ; if not at end of line, move further forward
- (goto-char ;; careful not to move too far; e.g. *not* over empty lines:
- (min (save-excursion (forward-sexp 1) (point))
- (save-excursion (forward-paragraph 1) (point)))))
- (list beginning (point)))
- ;; else: 'no-error': we are not in a function
- nil))
-
-(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)
- (or (ess-beginning-of-function 'no-error)
- (backward-paragraph))
- (point))
-
-(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)
- (or (ess-end-of-function nil 'no-error)
- (forward-paragraph))
- (point))
-
-(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)
- ;; if point is not in a function, ess-end-of-function catches the error.
- (save-excursion
- (widen)
- (let* ((beg (ess-goto-beginning-of-function-or-para))
- (end (ess-goto-end-of-function-or-para)))
- (narrow-to-region beg end))))
-
-(define-obsolete-function-alias 'ess-narrow-to-defun 'ess-narrow-to-defun-or-para "15.09")
-
-(defun ess-newline-and-indent ()
- (interactive)
- (cond ((string= ess-dialect "R")
- (ess-roxy-newline-and-indent))
- (t
- (newline-and-indent))))
-
-(defun ess-indent-new-comment-line ()
- (interactive)
- (cond ((string= ess-dialect "R")
- (ess-roxy-indent-new-comment-line))
- (t
- (indent-new-comment-line))))
-
-
-;;;*;;; Formatting / indentation
-
-(defun ess-set-style (&optional style quiet)
- "Set up the `ess-mode' style variables from the `ess-style' variable
-or if STYLE argument is given, use that. It makes the ESS indentation
-style variables buffer local."
-
- (interactive)
- (let ((ess-styles (mapcar 'symbol-name (mapcar 'car ess-style-alist))))
- (unless style
- (setq style
- (intern (ess-completing-read "Set ESS mode indentation style"
- ess-styles nil t nil nil ess-default-style))))
- (setq style (or style ess-style))
- (make-local-variable 'ess-style)
- (if (memq (symbol-name style) ess-styles)
- (setq ess-style style)
- (error (format "Bad ESS style: %s" style)))
- (if (not quiet)
- (message "ESS-style: %s" ess-style))
- ;; finally, set the indentation style variables making each one local
- (mapc (lambda (ess-style-pair)
- (make-local-variable (car ess-style-pair))
- (set (car ess-style-pair)
- (cdr ess-style-pair)))
- (cdr (assq ess-style ess-style-alist)))
- ess-style))
-
-;; FIXME: Move into ess-indent-or-complete, indentation functions are overly
-;; scattered around
-(defun ess-indent-command (&optional whole-exp)
- "Indent current line as ESS code, or in some cases insert a tab character.
-If `ess-tab-always-indent' is non-nil (the default), 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.
-A numeric argument, regardless of its value, 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."
- (interactive "P")
- (if whole-exp
- ;; If arg, always indent this line as S
- ;; and shift remaining lines of expression the same amount.
- (let ((shift-amt (ess-indent-line))
- beg end)
- (save-excursion
- (if ess-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)))
- (if (and (not ess-tab-always-indent)
- (save-excursion
- (skip-chars-backward " \t")
- (not (bolp))))
- (insert-tab)
- ;; call ess-indent-line
- (funcall indent-line-function))))
-
-(defun ess-indent-or-complete ()
- "When region is selected indent the region, otherwise, if
-`ess-tab-complete-in-script' is non-nil, try to indent, if code
-is already indented, complete instead.
-
-The default of `ess-tab-complete-in-script' is nil. Also see
-`ess-first-tab-never-complete'."
- (interactive)
- (if (use-region-p)
- (indent-region (region-beginning) (region-end))
- (let ((shift (ess-indent-command)))
- (when (and ess-tab-complete-in-script
- (numberp shift) ;; can be nil if ess-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 ((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."
- ;; fixme: make this work with standard indent-line-function
- (if (fboundp ess-indent-line-function)
- (funcall ess-indent-line-function)
- ;; else S and R default behavior
- (ess-r-indent-line)))
-
-
-;;*;; Loading files
-
-(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"))))))
-
-(defun ess-check-source (fname)
- "If file FNAME has an unsaved buffer, offer to save it.
-Returns t if the buffer existed and was modified, but was not saved."
- (let ((buff (get-file-buffer fname)))
- ;; RMH: Corrections noted below are needed for C-c C-l to work
- ;; correctly when issued from *S* buffer.
- ;; The following barfs since
- ;; 1. `if' does not accept a buffer argument, `not' does.
- ;; 2. (buffer-file-name) is not necessarily defined for *S*
- ;;(if buff
- ;; (let ((deleted (not (file-exists-p (buffer-file-name)))))
- ;; Next 2 lines are RMH's solution:
- (if (not(not buff))
- (let ((deleted (not (file-exists-p fname))))
- (if (and deleted (not (buffer-modified-p buff)))
- ;; Buffer has been silently deleted, so silently save
- (with-current-buffer buff
- (set-buffer-modified-p t)
- (save-buffer))
- (if (and (buffer-modified-p buff)
- (or ess-mode-silently-save
- (y-or-n-p
- (format "Save buffer %s first? "
- (buffer-name buff)))))
- (with-current-buffer buff
- (save-buffer))))
- (buffer-modified-p buff)))))
-
-(defvar ess-error-regexp "^\\(Syntax error: .*\\) at line \\([0-9]*\\), file \\(.*\\)$"
- "Regexp to search for errors.")
-
-;;;###autoload
-(defun ess-parse-errors (&optional showerr reset)
- "Jump to error in last loaded ESS source file.
-With prefix argument, only shows 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
- (ess-mode)))
- (pop-to-buffer fbuffer)
- (ess-goto-line linenum))
- (princ errmess t)))
- (t
- (message "Not a syntax error.")
- (ess-display-temp-buffer errbuff)))))
-
-
-;;*;; Creating and manipulating dump buffers
-;;;###autoload
-(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-customize-alist)
- (apply ess-source-directory nil)))))
- (filename (concat dirname (format ess-dump-filename-template object)))
- (old-buff (get-file-buffer filename)))
-
- ;; If the directory doesn't exist, offer to create it
- (if (file-exists-p (directory-file-name dirname)) nil
- (if (y-or-n-p ; Approved
- (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
-
- (if current-prefix-arg
- (ess-dump-object object filename)
- (if old-buff
- (progn
- (pop-to-buffer old-buff)
- (message "Popped to edit buffer."))
- ;; No current buffer containing desired file
- (if (file-exists-p filename)
- (progn
- (ess-find-dump-file-other-window filename)
- (message "Read %s" filename))
- ;; No buffer and no file
- (ess-dump-object object filename))))))
-
-(ess-defgeneric ess-dump-object (object filename)
- "Dump the ESS object OBJECT into file FILENAME."
- (let ((complete-dump-command (format inferior-ess-dump-command
- object filename)))
- (if (file-writable-p filename) nil
- (error "Can't dump %s as %f is not writeable." object filename))
-
- (:override
- ;; Make sure we start fresh
- (when (get-file-buffer filename)
- (kill-buffer (get-file-buffer filename)))
-
- (ess-command complete-dump-command)
- (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."
-
- (if (file-exists-p filename) nil
- (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)
- (ess-mode ess-customize-alist)
-
- (auto-save-mode 1) ; Auto save in this buffer
- (setq ess-local-process-name ess-current-process-name)
-
- (if ess-function-template
- (progn
- (goto-char (point-max))
- (if (re-search-backward ess-dumped-missing-re nil t)
- (progn
- (replace-match ess-function-template t t)
- (set-buffer-modified-p nil) ; Don't offer to save if killed now
- (goto-char (point-min))
- (condition-case nil
- ;; This may fail if there are no opens
- (down-list 1)
- (error nil)))))))
-
-(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."
- (lexical-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)))
- (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))))))))
-
-(defun ess-version ()
- (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 "]")))
-
-
-(provide 'ess-mode)
-
-;;; ess-mode.el ends here