|
;;; 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 <rossini@biostat.washington.edu>
|
|
;; Created: 26 Aug 1997
|
|
;; Maintainer: ESS-core <ESS-core@r-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:
|
|
|
|
; Requires and autoloads
|
|
|
|
(require 'ess-mode)
|
|
(require 'ess-help)
|
|
(require 'ess-inf)
|
|
|
|
(declare-function speedbar-add-supported-extension "speedbar" (extension))
|
|
|
|
; Configuration variables
|
|
|
|
(defvar S-syntax-table
|
|
(let ((S-syntax-table (make-syntax-table)))
|
|
(modify-syntax-entry ?\\ "\\" S-syntax-table)
|
|
(modify-syntax-entry ?+ "." S-syntax-table)
|
|
(modify-syntax-entry ?- "." S-syntax-table)
|
|
(modify-syntax-entry ?= "." S-syntax-table)
|
|
(modify-syntax-entry ?% "." S-syntax-table)
|
|
(modify-syntax-entry ?< "." S-syntax-table)
|
|
(modify-syntax-entry ?> "." S-syntax-table)
|
|
(modify-syntax-entry ?& "." S-syntax-table)
|
|
(modify-syntax-entry ?| "." S-syntax-table)
|
|
(modify-syntax-entry ?\' "\"" S-syntax-table)
|
|
(modify-syntax-entry ?\" "\"" S-syntax-table)
|
|
(modify-syntax-entry ?# "<" S-syntax-table) ; open comment
|
|
(modify-syntax-entry ?\n ">" S-syntax-table) ; close comment
|
|
;;(modify-syntax-entry ?. "w" S-syntax-table) ; "." used in S obj names
|
|
(modify-syntax-entry ?. "_" S-syntax-table) ; see above/below,
|
|
; plus consider separation.
|
|
(modify-syntax-entry ?$ "_" S-syntax-table); foo$comp = 1 symbol(completion)
|
|
(modify-syntax-entry ?@ "_" S-syntax-table); foo@slot = 1 symbol(completion)
|
|
(modify-syntax-entry ?_ "_" S-syntax-table)
|
|
(modify-syntax-entry ?: "_" S-syntax-table)
|
|
(modify-syntax-entry ?* "." S-syntax-table)
|
|
(modify-syntax-entry ?< "." S-syntax-table)
|
|
(modify-syntax-entry ?> "." S-syntax-table)
|
|
(modify-syntax-entry ?/ "." S-syntax-table)
|
|
S-syntax-table)
|
|
"Syntax table for S code."
|
|
)
|
|
|
|
(defvar S-editing-alist
|
|
'((paragraph-start . (concat "\\s-*$\\|" page-delimiter))
|
|
(paragraph-separate . (concat "\\s-*$\\|" page-delimiter))
|
|
(paragraph-ignore-fill-prefix . t)
|
|
;;(comment-indent-function . 'S-comment-indent)
|
|
;;(ess-comment-indent . 'S-comment-indent)
|
|
;;(ess-calculate-indent . 'ess-calculate-indent)
|
|
;;(ess-keep-dump-files . 'ask)
|
|
;; For Changelog add, require ' ' before <- : "attr<-" is a function name :
|
|
(add-log-current-defun-header-regexp . "^\\(.+\\)\\s-+<-[ \t\n]*function"))
|
|
"General options for S and S+ source files.")
|
|
|
|
(defvar inferior-S-language-start
|
|
'(concat "options("
|
|
"STERM='" ess-STERM "'"
|
|
", str.dendrogram.last=\"'\""
|
|
(if ess-editor (concat ", editor='" ess-editor "'"))
|
|
(if ess-pager (concat ", pager='" ess-pager "', help.pager='" ess-pager "'"))
|
|
", show.error.locations=TRUE"
|
|
")")
|
|
"S language expression for startup -- default for all S dialects.")
|
|
|
|
(defconst S-common-cust-alist
|
|
'((ess-language . "S")
|
|
(inferior-ess-exit-command . "q()\n")
|
|
(inferior-ess-language-start . (eval inferior-S-language-start))
|
|
(comint-use-prompt-regexp . t) ;;use fields if nil
|
|
(comint-process-echoes . t)
|
|
;; these prompt are the same for all S-languages As long as custom prompt
|
|
;; ends in inferior-ess-primary-prompt everything should work as expected.
|
|
(inferior-ess-primary-prompt . "> ")
|
|
;; (inferior-ess-secondary-prompt . "[+:] ") ;; catch Selection: and alike
|
|
(inferior-ess-secondary-prompt . "+ ") ;; catch Selection: and alike
|
|
(comment-start . "#")
|
|
(comment-add . 1)
|
|
(comment-start-skip . "#+ *")
|
|
(comment-use-syntax . t) ; see log for bug report 2013-06-07
|
|
(comment-column . 40)
|
|
(ess-no-skip-regexp . (concat "^ *@\\|" (default-value 'ess-no-skip-regexp)))
|
|
;; inferior-ess-prompt is used by comint for navigation, only if
|
|
;; comint-use-prompt-regexp is t; (transcript-mode also relies on this regexp)
|
|
(inferior-ess-prompt . inferior-S-prompt)
|
|
(ess-getwd-command . "getwd()\n")
|
|
(ess-setwd-command . "setwd('%s')\n")
|
|
(ess-funargs-command . ".ess_funargs(\"%s\")\n")
|
|
(fill-nobreak-predicate . 'ess-inside-string-p)
|
|
(ess-execute-screen-options-command . "options(width=%d, length=99999)\n")
|
|
(font-lock-defaults . '(ess-build-font-lock-keywords
|
|
nil nil ((?\. . "w") (?\_ . "w")))))
|
|
"S-language common settings for all <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.")
|
|
|
|
; 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")
|
|
|
|
|
|
;;; 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
|