1
1
;;; essl-s.el --- Support for editing S source code
3
;; Copyright (C) 1989-2001 D. Bates, Kademan, Ritter, D.M. Smith, K. Hornik,
4
;; R.M. Heiberger, M. Maechler, and A.J. Rossini.
3
;; Copyright (C) 1989-1997 D. Bates, Kademan, Ritter, D.M. Smith, K. Hornik,
4
;; R.M. Heiberger, M. Maechler, and A.J. Rossini.
5
;; Copyright (C) 1998-2004 A.J. Rossini, Rich M. Heiberger, Martin
6
;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
6
;; Author: A.J. Rossini <rossini@biostat.washington.edu>
7
;; Maintainer: A.J. Rossini <rossini@biostat.washington.edu>
8
;; Original Author: A.J. Rossini <rossini@biostat.washington.edu>
8
9
;; Created: 26 Aug 1997
9
;; Modified: $Date: 2002/05/10 19:33:24 $
10
;; Version: $Revision: 5.29 $
11
;; RCS: $Id: essl-s.el,v 5.29 2002/05/10 19:33:24 rmh Exp $
10
;; Maintainers: ESS-core <ESS-core@stat.math.ethz.ch>
13
12
;; This file is part of ESS (Emacs Speaks Statistics).
44
43
(setq S-syntax-table (make-syntax-table))
45
44
(modify-syntax-entry ?\\ "\\" S-syntax-table)
46
(modify-syntax-entry ?+ "." S-syntax-table)
47
(modify-syntax-entry ?- "." S-syntax-table)
48
(modify-syntax-entry ?= "." S-syntax-table)
49
(modify-syntax-entry ?% "." S-syntax-table)
50
(modify-syntax-entry ?< "." S-syntax-table)
51
(modify-syntax-entry ?> "." S-syntax-table)
52
(modify-syntax-entry ?& "." S-syntax-table)
53
(modify-syntax-entry ?| "." S-syntax-table)
45
(modify-syntax-entry ?+ "." S-syntax-table)
46
(modify-syntax-entry ?- "." S-syntax-table)
47
(modify-syntax-entry ?= "." S-syntax-table)
48
(modify-syntax-entry ?% "." S-syntax-table)
49
(modify-syntax-entry ?< "." S-syntax-table)
50
(modify-syntax-entry ?> "." S-syntax-table)
51
(modify-syntax-entry ?& "." S-syntax-table)
52
(modify-syntax-entry ?| "." S-syntax-table)
54
53
(modify-syntax-entry ?\' "\"" S-syntax-table)
55
(modify-syntax-entry ?# "<" S-syntax-table) ; open comment
56
(modify-syntax-entry ?\n ">" S-syntax-table) ; close comment
54
(modify-syntax-entry ?\" "\"" S-syntax-table)
55
(modify-syntax-entry ?# "<" S-syntax-table) ; open comment
56
(modify-syntax-entry ?\n ">" S-syntax-table) ; close comment
57
57
;;(modify-syntax-entry ?. "w" S-syntax-table) ; "." used in S obj names
58
(modify-syntax-entry ?. "_" S-syntax-table) ; see above/below,
58
(modify-syntax-entry ?. "_" S-syntax-table) ; see above/below,
59
59
; plus consider separation.
60
(modify-syntax-entry ?$ "_" S-syntax-table) ; foo.bar$hack is 1 symbol
61
(modify-syntax-entry ?_ "." S-syntax-table)
62
(modify-syntax-entry ?* "." S-syntax-table)
63
(modify-syntax-entry ?< "." S-syntax-table)
64
(modify-syntax-entry ?> "." S-syntax-table)
65
(modify-syntax-entry ?/ "." S-syntax-table))
60
(modify-syntax-entry ?$ "_" S-syntax-table) ; foo.bar$hack is 1 symbol
61
(modify-syntax-entry ?_ "." S-syntax-table)
62
(modify-syntax-entry ?* "." S-syntax-table)
63
(modify-syntax-entry ?< "." S-syntax-table)
64
(modify-syntax-entry ?> "." S-syntax-table)
65
(modify-syntax-entry ?/ "." S-syntax-table))
67
67
(defvar S-editing-alist
68
'((paragraph-start . (concat "^$\\|" page-delimiter))
69
(paragraph-separate . (concat "^$\\|" page-delimiter))
68
'((paragraph-start . (concat "\\s-*$\\|" page-delimiter))
69
(paragraph-separate . (concat "\\s-*$\\|" page-delimiter))
70
70
(paragraph-ignore-fill-prefix . t)
71
(require-final-newline . t)
73
(comment-start-skip . "#+ *")
75
;;(comment-indent-function . 'S-comment-indent)
76
;;(ess-comment-indent . 'S-comment-indent)
77
;;(ess-indent-line . 'S-indent-line)
78
;;(ess-calculate-indent . 'S-calculate-indent)
79
(indent-line-function . 'S-indent-line)
80
(parse-sexp-ignore-comments . t)
81
(ess-set-style . ess-default-style)
82
(ess-local-process-name . nil)
83
;;(ess-keep-dump-files . 'ask)
84
(ess-mode-syntax-table . S-syntax-table)
71
(require-final-newline . t)
73
(comment-start-skip . "#+ *")
75
;;(comment-indent-function . 'S-comment-indent)
76
;;(ess-comment-indent . 'S-comment-indent)
77
;;(ess-indent-line . 'S-indent-line)
78
;;(ess-calculate-indent . 'S-calculate-indent)
79
(indent-line-function . 'S-indent-line)
80
(parse-sexp-ignore-comments . t)
81
(ess-set-style . ess-default-style)
82
(ess-local-process-name . nil)
83
;;(ess-keep-dump-files . 'ask)
84
(ess-mode-syntax-table . S-syntax-table)
85
85
;; For Changelog add, require ' ' before <- : "attr<-" is a function name :
86
86
(add-log-current-defun-header-regexp . "^\\(.+\\)\\s-+<-[ \t\n]*function")
87
(font-lock-defaults . '(ess-mode-font-lock-keywords
87
(font-lock-defaults . '(ess-mode-font-lock-keywords
88
88
nil nil ((?\. . "w"))))
90
90
"General options for editing S, S+, and R source files.")
92
92
(defvar inferior-S-language-start
93
93
'(concat "options("
94
"STERM='" ess-STERM "'"
94
"STERM='" ess-STERM "'"
95
95
(if ess-editor (concat ", editor='" ess-editor "'"))
96
(if ess-pager (concat ", pager='" ess-pager "', help.pager='" ess-pager "'"))
96
(if ess-pager (concat ", pager='" ess-pager "', help.pager='" ess-pager "'"))
98
98
"S language expression for startup -- default for all S dialects.")
169
169
(defconst ess-help-S+-sec-regex "^[A-Z. ---]+:$"
170
170
"Reg(ular) Ex(pression) of section headers in help file.")
172
(defconst ess-help-R-sec-regex "^\\s *[A-Z[a-z. ---]+:$"
172
(defconst ess-help-R-sec-regex "^[A-Z][a-z].+:$"
173
173
"Reg(ular) Ex(pression) of section headers in help file.")
175
175
;;; S-mode extras of Martin Maechler, Statistik, ETH Zurich.
176
176
;;; See also ./ess-utils.el
178
178
(defvar ess-function-outline-file
179
(concat ess-lisp-directory "/../etc/" "function-outline.S")
179
(concat ess-etc-directory "/function-outline.S")
180
180
"The file name of the ess-function outline that is to be inserted at point,
181
181
when \\<ess-mode-map>\\[ess-insert-function-outline] is used.
182
182
Placeholders (substituted `at runtime'): $A$ for `Author', $D$ for `Date'.")
387
387
(defun ess-fix-comments (&optional dont-query verbose)
388
388
"Fix ess-mode buffer so that single-line comments start with at least `##'."
389
389
(interactive "P")
391
(goto-char (point-min))
392
(let ((rgxp "^\\([ \t]*#\\)\\([^#]\\)")
395
(ess-rep-regexp rgxp to nil nil verbose)
396
(query-replace-regexp rgxp to nil)))))
390
(ess-replace-regexp-dump-to-src "^\\([ \t]*#\\)\\([^#]\\)"
391
"\\1#\\2" dont-query verbose))
398
393
(defun ess-dump-to-src (&optional dont-query verbose)
399
394
"Make the changes in an S - dump() file to improve human readability."
400
395
(interactive "P")
402
(if (not (equal major-mode 'ess-mode))
404
(goto-char (point-min))
405
(let ((rgxp "^\"\\([a-z.][a-z.0-9]*\\)\"<-\n")
408
(ess-rep-regexp rgxp to nil nil verbose)
409
(query-replace-regexp rgxp to nil)))))
396
(ess-replace-regexp-dump-to-src "^\"\\([a-z.][a-z.0-9]*\\)\"<-\n"
398
dont-query verbose 'ensure-ess))
411
400
(defun ess-num-var-round (&optional dont-query verbose)
412
401
"Is VERY useful for dump(.)'ed numeric variables; ROUND some of them by
413
replacing endings of 000000*.. and 999999*. Martin Maechler"
402
replacing endings of 000000*.. and 999999*. Martin Maechler"
414
403
(interactive "P")
416
405
(goto-char (point-min))
432
421
'fixedcase 'literal verbose)
433
422
(setq num (1+ num))))))
424
(defun ess-fix-dot (before-chars &optional dont-query verbose)
425
"Remove trailing decimal '.' (\"dot\"), before BEFORE; typically from S-plus"
426
;; typically, before-chars = "]:" or more
427
(ess-replace-regexp-dump-to-src
428
(concat "\\([0-9]\\)\\.\\( *[" before-chars "]\\)")
430
"\\1\\2" dont-query verbose))
432
(defun ess-fix-dot-1 (&optional do-query verbose)
433
"Remove trailing decimal '.' (\"dot\"), before ':' or ']', i.e.,
434
in cases where it's ugly and nonsense. DO-QUERY(prefix) asks before replacing."
436
(ess-fix-dot "]:" (not do-query) verbose))
438
(defun ess-fix-dot-more (&optional dont-query verbose)
439
"Remove trailing decimal '.' (\"dot\", typically from S+) in more cases
440
than `ess-fix-dot-1'."
442
(ess-fix-dot-1 nil verbose)
443
(ess-fix-dot ",)" dont-query verbose))
445
(defun ess-fix-EQ-assign (&optional dont-query verbose)
446
"Replace \"=\" by \"<-\" at least for function assignments.
447
CAREFUL if have list()s of functions!"
448
;;TODO: "in the few places we can be very sure.."
449
;;---- is hard in general: local functions: ok; but functions in
450
;; list(a = function(x) abs(x), b= function(y) bound(y)) *NOT* ok!
452
(ess-replace-regexp-dump-to-src
453
"^\\( *[a-z.][_a-z.0-9]*\\) *= *\\(function *(\\)"
454
"\\1 <- \\2" dont-query verbose))
435
456
;;; All of the above three :
436
457
(defun ess-MM-fix-src (&optional dont-query verbose)
437
"Clean up ess-source code which has been produced by dump(..).
438
Produces more readable code, and one that is well formatted in emacs ess-mode."
458
"Clean up ess-source code which has been produced by dump(..), and other
459
code not typically produced by other tools. Produces more readable code,
460
and one that is well formatted in emacs ess-mode."
439
461
(interactive "P")
440
462
;; each of the following does a save-excursion:
441
463
(ess-dump-to-src dont-query)
442
464
(ess-fix-comments dont-query)
443
(ess-num-var-round dont-query verbose))
465
(ess-num-var-round dont-query verbose)
466
(ess-fix-dot-more dont-query verbose)
467
(ess-fix-EQ-assign dont-query verbose)
445
470
(defun ess-fix-miscellaneous (&optional from verbose)
446
471
"Fix Miscellaneous S/R `ill-formation's from current \\[point].
491
518
(defun ess-smart-underscore ()
492
"Electrical \"_\" key: insert `ess-S-assign' after removing spaces, unless
493
in string/comment. `ess-S-assign', typically \" <- \", can be customized."
519
"Smart \"_\" key: insert `ess-S-assign', unless in string/comment.
520
If the underscore key is pressed a second time, the assignment
521
operator is removed and replaced by the underscore. `ess-S-assign',
522
typically \" <- \", can be customized. In ESS modes other than R/S,
523
an underscore is always inserted. "
495
525
;;(insert (if (inside-string/comment-p (point)) "_" ess-S-assign))
496
(if (inside-string/comment-p (point))
527
(inside-string/comment-p (point))
528
(not (equal ess-language "S")))
499
(delete-horizontal-space)
500
(insert ess-S-assign)))
530
;; Else one keypress produces ess-S-assign; a second keypress will delete
531
;; ess-S-assign and instead insert _
532
;; Rather than trying to count a second _ keypress, just check whether
533
;; the current point is preceded by ess-S-assign.
534
(let ((assign-len (length ess-S-assign)))
536
(>= (point) (+ assign-len (point-min))) ;check that we can move back
538
(backward-char assign-len)
539
(looking-at ess-S-assign)))
540
;; If we are currently looking at ess-S-assign, replace it with _
542
(delete-backward-char assign-len)
544
(delete-horizontal-space)
545
(insert ess-S-assign)))))
502
547
(defun ess-toggle-underscore (force)
503
548
"Set the \"_\" (underscore) key to \\[ess-smart-underscore] or back to \"_\".