;;; ess.el --- Emacs Speaks Statistics -*- lexical-binding: t; -*-
|
|
;;
|
|
;; Author: David Smith <dsmith@stats.adelaide.edu.au>
|
|
;; A.J. Rossini <blindglobe@gmail.com>
|
|
;; Richard M. Heiberger <rmh@temple.edu>
|
|
;; Kurt Hornik <Kurt.Hornik@R-project.org>
|
|
;; Martin Maechler <maechler@stat.math.ethz.ch>
|
|
;; Rodney A. Sparapani <rsparapa@mcw.edu>
|
|
;; Stephen Eglen <stephen@gnu.org>
|
|
;; Sebastian P. Luque <spluque@gmail.com>
|
|
;; Henning Redestig <henning.red@googlemail.com>
|
|
;; Vitalie Spinu <spinuvit@gmail.com>
|
|
;; Lionel Henry <lionel.hry@gmail.com>
|
|
;; J. Alexander Branham <alex.branham@gmail.com>
|
|
;;
|
|
;; Maintainer: ESS Core Team <ESS-core@r-project.org>
|
|
;; Copyright (C) 1997-2018 ESS Core Team <ESS-core@r-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)
|
|
|
|
|
|
;; 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 "]")))
|
|
|
|
|
|
;;; Bug Reporting
|
|
|
|
;;;###autoload
|
|
(defun ess-submit-bug-report ()
|
|
"Submit a bug report to the ESS maintainers."
|
|
(interactive)
|
|
(let ((reporter-prompt-for-summary-p 't))
|
|
(reporter-submit-bug-report
|
|
"ess-bugs@r-project.org"
|
|
(concat "ess-mode " (ess-version-string))
|
|
(list 'ess-language
|
|
'ess-dialect
|
|
'ess-ask-for-ess-directory
|
|
'ess-ask-about-transfile
|
|
'default-directory
|
|
'ess-keep-dump-files
|
|
'ess-source-directory
|
|
'ess-use-ido
|
|
'ess-use-eldoc
|
|
'ess-use-tracebug
|
|
'ess-use-auto-complete
|
|
'ess-use-company
|
|
'ess-eval-visibly-p
|
|
'ess-can-eval-in-background
|
|
'ess-local-process-name)
|
|
nil
|
|
(lambda ()
|
|
;;(goto-char (point-max))
|
|
(rfc822-goto-eoh)
|
|
(forward-line 1)
|
|
(insert "\n\n-------------------------------------------------------\n")
|
|
(insert "This bug report will be sent to the ESS bugs email list\n")
|
|
(insert "Press C-c C-c when you are ready to send your message.\n")
|
|
(insert "-------------------------------------------------------\n\n")
|
|
(insert (with-current-buffer ess-dribble-buffer
|
|
(goto-char (point-max))
|
|
(forward-line -100)
|
|
(buffer-substring-no-properties (point) (point-max))))))))
|
|
|
|
|
|
|
|
;;; Timer
|
|
|
|
(defcustom ess-idle-timer-interval 1
|
|
"Number of 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'.")
|
|
|
|
|
|
;;; 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
|