Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
2701 views
1
;;; ess-mode.el --- Support for editing ESS source code
2
3
;; Copyright (C) 1989-1994 Doug Bates, Ed Kademan, Frank Ritter, David Smith.
4
;; Copyright (C) 1997--2010 A.J. Rossini, Richard M. Heiberger, Martin
5
;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
6
;; Copyright (C) 2011--2012 A.J. Rossini, Richard M. Heiberger, Martin Maechler,
7
;; Kurt Hornik, Rodney Sparapani, Stephen Eglen and Vitalie Spinu.
8
9
;; Author: David Smith <[email protected]>
10
;; Created: 7 Jan 1994
11
;; Maintainer: ESS-core <[email protected]>
12
13
;; This file is part of ESS
14
15
;; This file is free software; you can redistribute it and/or modify
16
;; it under the terms of the GNU General Public License as published by
17
;; the Free Software Foundation; either version 2, or (at your option)
18
;; any later version.
19
20
;; This file is distributed in the hope that it will be useful,
21
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
22
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23
;; GNU General Public License for more details.
24
25
;; A copy of the GNU General Public License is available at
26
;; http://www.r-project.org/Licenses/
27
28
;;; Commentary:
29
30
;; Code for editing ESS source code.
31
32
;;; Code:
33
34
; Requires and autoloads
35
36
;;; AJR: THIS IS GROSS AND DISGUSTING (but I wrote it).
37
;;; MM: and I had to add all other 'ess-eval-*** ...
38
;;; >>> why not just do the obvious instead of all these ? Namely,
39
;;; (require 'ess-inf)
40
;;; ------------------ ?
41
;;; AJR: The reason is that we ONLY need to load ess-inf for the
42
;;; functions which are interactive in nature. We don't want to load
43
;;; it when we are only editing.
44
45
;;; VS: ess-inf is always loaded form ess-toggle-underscore in ess-s-l.el. I am
46
;;; placing require ess-inf and ess-mode in ess. This cross autoloads are
47
;;; useless. Compiler is also silent without them. These funcs are used in mode-map
48
;;; only as symbols.
49
50
;; (autoload 'ess-mode-minibuffer-map "ess-inf" "" nil 'keymap)
51
;; (autoload 'ess-read-object-name "ess-inf" "" nil)
52
;; (autoload 'ess-list-object-completions "ess-inf" "" nil)
53
54
;; (autoload 'ess-eval-buffer "ess-inf" "" nil)
55
;; (autoload 'ess-eval-buffer-and-go "ess-inf" "" nil)
56
;; (autoload 'ess-eval-function "ess-inf" "" nil)
57
;; (autoload 'ess-eval-function-and-go "ess-inf" "" nil)
58
;; (autoload 'ess-eval-function-or-paragraph-and-step
59
;; "ess-inf" "" nil)
60
;; (autoload 'ess-eval-line "ess-inf" "" nil)
61
;; (autoload 'ess-eval-line-and-go "ess-inf" "" nil)
62
;; (autoload 'ess-eval-line-and-step "ess-inf" "" nil)
63
;; (autoload 'ess-eval-linewise "ess-inf" "" nil)
64
;; (autoload 'ess-eval-paragraph "ess-inf" "" nil)
65
;; (autoload 'ess-eval-paragraph-and-go "ess-inf" "" nil)
66
;; (autoload 'ess-eval-paragraph-and-step "ess-inf" "" nil)
67
;; (autoload 'ess-eval-region "ess-inf" "" nil)
68
;; (autoload 'ess-eval-region-and-go "ess-inf" "" nil)
69
70
;; (autoload 'ess-load-file "ess-inf" "" nil)
71
;; (autoload 'ess-switch-process "ess-inf" "" nil)
72
;; (autoload 'ess-switch-to-ESS "ess-inf" "" nil)
73
;; (autoload 'ess-request-a-process "ess-inf" "" nil)
74
;; (autoload 'ess-get-process "ess-inf" "" nil)
75
;; (autoload 'ess-command "ess-inf" "" nil)
76
;; (autoload 'ess-create-temp-buffer "ess-inf" "" nil)
77
;; (autoload 'ess-display-temp-buffer "ess-inf" "" nil)
78
;; (autoload 'ess-force-buffer-current "ess-inf" "" nil)
79
;; (autoload 'ess-make-buffer-current "ess-inf" "" nil)
80
;; (autoload 'ess-modtime-gt "ess-inf" "" nil)
81
;; (autoload 'ess-object-modtime "ess-inf" "" nil)
82
;; (autoload 'ess-quit "ess-inf" "" nil)
83
84
(autoload 'ess-turn-on-eldoc "ess-r-d" "" nil)
85
;; (autoload 'ess-ddeclient-p "ess-inf" "(autoload)" nil)
86
(autoload 'ess-dump-object-ddeclient "ess-dde" "(autoload)" nil)
87
(autoload 'SAS "ess-sas-d.el" "(autoload)" t)
88
89
(require 'ess-utils)
90
91
(defun ess-line-end-position (&optional N)
92
"return the 'point' at the end of N lines. N defaults to 1, i.e., current line."
93
(save-excursion
94
(end-of-line N)
95
(point)))
96
97
98
; ESS mode
99
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
100
;;;; In this section:
101
;;;;
102
;;;; * The major mode ess-mode
103
;;;; * Commands for ess-mode
104
;;;; * Code evaluation commands
105
;;;; * Indenting code and commands
106
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
107
108
;;*;; Major mode definition
109
110
111
(defvar ess-mode-map
112
(let ((map (make-sparse-keymap)))
113
114
;; By popular demand:
115
(define-key map "\C-m" 'newline-and-indent); = [RETURN]
116
(define-key map "\C-y" 'ess-yank)
117
118
(define-key map "\C-c\C-r" 'ess-eval-region)
119
(define-key map "\C-c\M-r" 'ess-eval-region-and-go)
120
(define-key map "\C-c\C-b" 'ess-eval-buffer)
121
(define-key map "\C-c\M-b" 'ess-eval-buffer-and-go)
122
(define-key map (kbd "C-c C-<up>") 'ess-eval-buffer-from-beg-to-here)
123
(define-key map (kbd "C-c C-<down>") 'ess-eval-buffer-from-here-to-end)
124
(define-key map "\C-c\C-f" 'ess-eval-function)
125
(define-key map "\C-c\M-f" 'ess-eval-function-and-go)
126
(define-key map "\C-c\C-c" 'ess-eval-region-or-function-or-paragraph-and-step)
127
(define-key map "\C-c\C-p" 'ess-eval-paragraph-and-step)
128
(define-key map "\C-c\M-p" 'ess-eval-paragraph-and-go)
129
(define-key map "\C-\M-x" 'ess-eval-region-or-function-or-paragraph)
130
(define-key map "\C-c\C-n" 'ess-eval-line-and-step)
131
(define-key map "\C-c\C-j" 'ess-eval-line)
132
(define-key map [(control return)] 'ess-eval-region-or-line-and-step)
133
(define-key map "\C-c\M-j" 'ess-eval-line-and-go)
134
;; the next three can only work in S/R - mode {FIXME}
135
(define-key map "\C-\M-a" 'ess-goto-beginning-of-function-or-para)
136
(define-key map "\C-\M-e" 'ess-goto-end-of-function-or-para)
137
(define-key map "\C-xnd" 'ess-narrow-to-defun)
138
(define-key map "\C-c\C-y" 'ess-switch-to-ESS-deprecated)
139
(define-key map "\C-c\C-z" 'ess-switch-to-inferior-or-script-buffer)
140
(define-key map "\C-c\C-l" 'ess-load-file)
141
(define-key map "\C-c\M-l" 'ess-load-file); alias, as in 'iESS' where C-c C-l is comint-list-*
142
(define-key map "\C-c\C-v" 'ess-display-help-on-object)
143
;;(define-key map "\C-c5\C-d"'ess-dump-object-into-edit-buffer-other-frame)
144
(define-key map "\C-c\C-s" 'ess-switch-process) ; use a
145
;; different process for the buffer.
146
;; (define-key map "\C-c\C-t" 'ess-execute-in-tb)
147
(define-key map "\C-c\t" 'ess-complete-object-name-deprecated)
148
;;M (define-key map "\C-c\t" 'comint-dynamic-complete-filename)
149
(unless (and (featurep 'emacs) (>= emacs-major-version 24))
150
(define-key map "\M-\t" 'comint-dynamic-complete))
151
(define-key map "\M-?" 'ess-list-object-completions)
152
;; wrong here (define-key map "\C-c\C-k" 'ess-request-a-process)
153
(define-key map "\C-c\C-k" 'ess-force-buffer-current)
154
(define-key map "\C-c`" 'ess-show-traceback)
155
(define-key map [(control ?c) ?~] 'ess-show-call-stack)
156
(define-key map "\C-c." (lambda () (interactive) (message "ess-set-style moved to C-c C-e C-s. Sorry for the inconvenience")))
157
(define-key map "{" 'ess-electric-brace)
158
(define-key map "}" 'ess-electric-brace)
159
(define-key map "\C-\M-q" 'ess-indent-exp)
160
(define-key map "\C-\M-h" 'ess-mark-function)
161
(if (featurep 'xemacs) ;; work around Xemacs bug (\C-\M-h redefines M-BS):
162
(define-key map [(meta backspace)] 'backward-kill-word))
163
;;(define-key map [delete] 'backward-delete-char-untabify)
164
(define-key map "\t" 'ess-indent-or-complete)
165
(define-key map "\C-c\C-q" 'ess-quit)
166
(define-key map "\M-\r" 'ess-use-this-dir)
167
168
;; smart operators; most likely will go in the future into a separate local map
169
(define-key map "," 'ess-smart-comma)
170
171
(define-key map "\C-c\C-d" 'ess-doc-map)
172
(define-key map "\C-c\C-e" 'ess-extra-map)
173
(define-key map "\C-c\C-t" 'ess-dev-map)
174
map)
175
"Keymap for `ess-mode'.")
176
177
178
(defvar ess-eval-map
179
(let ((map (make-sparse-keymap)))
180
;; (define-key map "\C-r" 'ess-eval-region)
181
;; (define-key map "\M-r" 'ess-eval-region-and-go)
182
;; (define-key map "\C-b" 'ess-eval-buffer)
183
;; (define-key map "\M-b" 'ess-eval-buffer-and-go)
184
;; (define-key map "\C-f" 'ess-eval-function)
185
;; (define-key map "\M-f" 'ess-eval-function-and-go)
186
;; (define-key map "\C-x" 'ess-eval-function)
187
;; (define-key map "\C-n" 'ess-eval-line-and-step)
188
;; (define-key map "\C-j" 'ess-eval-line)
189
;; (define-key map "\M-j" 'ess-eval-line-and-go)
190
map)
191
"Keymap for ess-eval functions.")
192
(make-obsolete-variable 'ess-eval-map nil "ESS[12.09.1]")
193
194
(defvar ess-extra-map
195
(let (ess-extra-map)
196
(define-prefix-command 'ess-extra-map)
197
(define-key ess-extra-map "\C-d" 'ess-dump-object-into-edit-buffer)
198
(define-key ess-extra-map "d" 'ess-dump-object-into-edit-buffer)
199
(define-key ess-extra-map "\C-e" 'ess-execute)
200
(define-key ess-extra-map "e" 'ess-execute)
201
(define-key ess-extra-map "\C-i" 'ess-install-library)
202
(define-key ess-extra-map "i" 'ess-install-library)
203
(define-key ess-extra-map "\C-l" 'ess-load-library)
204
(define-key ess-extra-map "l" 'ess-load-library)
205
(define-key ess-extra-map "\C-s" 'ess-set-style)
206
(define-key ess-extra-map "s" 'ess-set-style)
207
(define-key ess-extra-map "\C-t" 'ess-build-tags-for-directory)
208
(define-key ess-extra-map "t" 'ess-build-tags-for-directory)
209
(define-key ess-extra-map "\C-w" 'ess-execute-screen-options)
210
(define-key ess-extra-map "w" 'ess-execute-screen-options)
211
(define-key ess-extra-map "/" 'ess-set-working-directory)
212
ess-extra-map)
213
"ESS extra map")
214
215
216
(require 'ess-noweb-mode)
217
218
(easy-menu-define
219
ess-mode-menu ess-mode-map
220
"Menu for use in `ess-mode'."
221
'("ESS" ; ESS-mode
222
["What is this? (beta)" ess-mouse-me t]
223
["Load file" ess-load-file t]
224
["Eval region | func | para" ess-eval-region-or-function-or-paragraph t]
225
["Eval region | func | para & step" ess-eval-region-or-function-or-paragraph-and-step t]
226
["Eval region | line" ess-eval-region-or-line-and-step t]
227
["Enter expression" ess-execute t]
228
;; sub menus
229
"------"
230
("Process"
231
["Goto end of process buffer" ess-switch-to-end-of-ESS t]
232
["Switch to process buffer" ess-switch-to-inferior-or-script-buffer t]
233
["Switch Process" ess-switch-process t]
234
("Start Process"
235
;; SJE - :help not yet recognised in XEmacs.
236
["R" R t] ;; :help "Start a new R process" :active t
237
["S" S t] ;; :help "Start a new S process" :active t
238
["Sqpe" Sqpe ess-microsoft-p] ;; :help "Start a new Sqpe process" :active t
239
["S+6-exisiting" S+6-existing ess-microsoft-p] ;; :help "Access an existing S process" :active t
240
["SAS" SAS-menu t] ;; :help "Start a new SAS process" :active t
241
;; The following menu item "Other" is a place-holder that will
242
;; be replaced with the other versions of R and Sqpe that can be run.
243
;; See `ess-r-versions-create' and ess-site.el
244
("Other"
245
["No other R or Sqpe versions" nil nil])
246
["About"
247
(ess-goto-info "Starting up") t]
248
;; :help "Read about starting a new ESS process" :active t]
249
)
250
("Eval visibly "
251
:filter ess--generate-eval-visibly-submenu ))
252
"------"
253
("ESS Eval"
254
["Eval region | func | para" ess-eval-region-or-function-or-paragraph t]
255
["Eval region | func | para & step" ess-eval-region-or-function-or-paragraph-and-step t]
256
["Eval region | line" ess-eval-region-or-line-and-step t]
257
"-----"
258
["Eval buffer" ess-eval-buffer t]
259
["Eval buffer till here" ess-eval-buffer-from-beg-to-here t]
260
["Eval buffer from here" ess-eval-buffer-from-here-to-end t]
261
["Eval region" ess-eval-region t]
262
["Eval function" ess-eval-function t]
263
["Eval line" ess-eval-line t]
264
["Eval line & step" ess-eval-line-and-step t]
265
["Eval paragraph" ess-eval-paragraph t]
266
["Eval paragraph & step" ess-eval-paragraph-and-step t]
267
["Eval chunk" ess-eval-chunk ess-noweb-mode]
268
["Eval chunk and step" ess-eval-chunk-and-step ess-noweb-mode]
269
["Eval thread" ess-eval-thread ess-noweb-mode]
270
["About" (ess-goto-info "Evaluating code") t]
271
)
272
("Eval and Go"
273
["Eval buffer" ess-eval-buffer-and-go t]
274
["Eval region" ess-eval-region-and-go t]
275
["Eval function" ess-eval-function-and-go t]
276
["Eval line" ess-eval-line-and-go t]
277
["Eval paragraph" ess-eval-paragraph-and-go t]
278
["Eval chunk" ess-eval-chunk-and-go ess-noweb-mode]
279
["Eval thread" ess-eval-thread-and-go ess-noweb-mode]
280
["About" (ess-goto-info "Evaluating code") t]
281
)
282
("Motion"
283
["Beginning of function or para" ess-goto-beginning-of-function-or-para t]
284
["End of function or para" ess-goto-end-of-function-or-para t]
285
"-----"
286
["Backward list" backward-list t]
287
["Forward list" forward-list t]
288
["Next parenthesis" down-list t]
289
["Enclosing parenthesis" backward-up-list t]
290
["Backward sexp" backward-sexp t]
291
["Forward sexp" forward-sexp t]
292
["About" (Info-goto-node "(Emacs)Lists") t]
293
)
294
("ESS Edit"
295
["Edit new object" ess-dump-object-into-edit-buffer t]
296
["Complete Filename" comint-replace-by-expanded-filename t]
297
["Complete File or Object" ess-indent-or-complete t]
298
["Kill sexp" kill-sexp t]
299
["Mark function" ess-mark-function t]
300
["Indent expression" ess-indent-exp t]
301
["Indent line" ess-indent-command t]
302
["Toggle Auto-Fill Mode" auto-fill-mode t]
303
["Undo" undo t]
304
["About" (ess-goto-info "Edit buffer") t]
305
)
306
"------"
307
("start-dev" :visible nil)
308
("end-dev" :visible nil)
309
"------"
310
("Font Lock"
311
:active ess-font-lock-keywords
312
:filter ess--generate-font-lock-submenu)
313
"------"
314
["Describe" describe-mode t]
315
["About editing" (ess-goto-info "Editing") t]
316
["Read ESS info" (ess-goto-info "") t]
317
["Send bug report" ess-submit-bug-report t]
318
))
319
320
321
322
;; (defun test-gen-menu (men)
323
;; '(
324
;; ["About editing" (ess-goto-info "Editing") t]
325
;; ["Read ESS info" (ess-goto-info "") t]
326
;; ["Send bug report" ess-submit-bug-report t]))
327
328
(defun SAS-menu ()
329
"Start SAS from the menu."
330
(interactive)
331
(if ess-microsoft-p
332
;; replace with other choices for starting SAS under XEmacs?
333
(error "SAS cannot be started this way in ESS on Windows.")
334
(SAS)))
335
336
(defun ess-mode-xemacs-menu ()
337
"Hook to install `ess-mode' menu for XEmacs (w/ easymenu)."
338
(if 'ess-mode
339
(easy-menu-add ess-mode-menu)
340
(easy-menu-remove ess-mode-menu)))
341
342
(if (featurep 'xemacs)
343
(add-hook 'ess-mode-hook 'ess-mode-xemacs-menu))
344
345
(defun ess-mode (&optional alist proc-name)
346
"Major mode for editing ESS source.
347
Optional arg ALIST describes how to customize the editing mode.
348
Optional arg PROC-NAME is name of associated inferior process.
349
350
\\{ess-mode-map}
351
352
Extra binding to note: 'ESC C-\\' indent-region.
353
354
Entry to this mode runs the hooks in ess-mode-hook.
355
356
You can send text to the inferior ESS process from other buffers containing
357
ESS source.
358
`ess-eval-region' sends the current region to the ESS process.
359
`ess-eval-buffer' sends the current buffer to the ESS process.
360
`ess-eval-function' sends the current function to the ESS process.
361
`ess-eval-line' sends the current line to the ESS process.
362
`ess-beginning-of-function' and `ess-end-of-function' move the point to
363
the beginning and end of the current ESS function.
364
`ess-switch-to-ESS' switches the current buffer to the ESS process buffer.
365
`ess-switch-to-end-of-ESS' switches the current buffer to the ESS process
366
buffer and puts point at the end of it.
367
368
`ess-eval-region-and-go', `ess-eval-buffer-and-go',
369
`ess-eval-function-and-go', and `ess-eval-line-and-go' switch to the S
370
process buffer after sending their text.
371
372
`ess-load-file' sources a file of commands to the ESS process.
373
374
\\[ess-indent-command] indents for ESS code.
375
\\[backward-delete-char-untabify] converts tabs to spaces as it moves back.
376
Comments are indented in a similar way to Emacs-lisp mode:
377
`###' beginning of line
378
`##' the same level of indentation as the code
379
`#' the same column on the right, or to the right of such a
380
column if that is not possible.(default value 40).
381
\\[indent-for-comment] command automatically inserts such a
382
`#' in the right place, or aligns such a comment if it is
383
already inserted.
384
\\[ess-indent-exp] command indents each line of the ESS grouping following point.
385
386
Variables controlling indentation style:
387
`ess-tab-always-indent'
388
Non-nil means TAB in ESS mode should always reindent the current line,
389
regardless of where in the line point is when the TAB command is used.
390
`ess-auto-newline'
391
Non-nil means automatically newline before and after braces inserted in S
392
code.
393
`ess-indent-level'
394
Indentation of ESS statements within surrounding block.
395
The surrounding block's indentation is the indentation of the line on
396
which the open-brace appears.
397
`ess-first-continued-statement-offset'
398
Extra indentation given to the first continued statement.
399
`ess-continued-statement-offset'
400
Extra indentation given to a substatement, such as the then-clause of an
401
if or body of a while.
402
`ess-dont-align-on-assignment'
403
Whether we should align continued statements based on the position of a
404
`<-` or `=` assignment operator.
405
`ess-continued-brace-offset'
406
Extra indentation given to a brace that starts a substatement.
407
This is in addition to ess-continued-statement-offset.
408
`ess-brace-offset'
409
Extra indentation for line if it starts with an open brace.
410
`ess-arg-function-offset'
411
Extra indent for internal substatements of function `foo' that called
412
in `arg=foo(...)' form.
413
If not number, the statements are indented at open-parenthesis following
414
`foo'.
415
`ess-arg-function-offset-new-line'
416
Extra indent for function arguments when ( is folowed by new line.
417
`ess-expression-offset'
418
Extra indent for internal substatements of `expression' that specified
419
in `obj <- expression(...)' form.
420
If not number, the statements are indented at open-parenthesis following
421
`expression'.
422
`ess-brace-imaginary-offset'
423
An open brace following other text is treated as if it were
424
this far to the right of the start of its line.
425
`ess-else-offset'
426
Extra indentation for line if it starts with `else'.
427
`ess-close-brace-offset'
428
Extra indentation for closing braces.
429
`ess-fancy-comments'
430
Non-nil means distinguish between #, ##, and ### for indentation.
431
432
Furthermore, \\[ess-set-style] command enables you to set up predefined ess-mode
433
indentation style. At present, predefined style are `BSD', `GNU', `K&R', `C++',
434
`CLB' (quoted from C language style)."
435
(setq alist (or alist
436
(buffer-local-value 'ess-local-customize-alist (current-buffer))
437
(error "Customise alist is not specified, nor ess-local-customize-alist is set.")))
438
(kill-all-local-variables) ;; NOTICE THIS! *** NOTICE THIS! *** NOTICE THIS! ***
439
(ess-setq-vars-local alist)
440
;; must happen here, since the mode map is set up too early:
441
(if ess-r-args-electric-paren (define-key ess-mode-map "(" 'ess-r-args-auto-show))
442
(ess-write-to-dribble-buffer
443
(format "(ess-mode-1): ess-language=%s, ess-dialect=%s buf=%s \n"
444
ess-language
445
ess-dialect
446
(current-buffer)))
447
;; (ess-write-to-dribble-buffer
448
;; (format "(ess-mode-1.2): ess-process=%s \n"
449
;; (ess-local-process-name ess-local-process-name "none")))
450
(ess-write-to-dribble-buffer
451
(format "(ess-mode-1.5): alist=%s \n" alist))
452
(setq major-mode 'ess-mode)
453
(setq mode-name (concat "ESS[" ess-language "]")) ; was ess-dialect
454
;; The following line does the next 20 or so :-).
455
(ess-write-to-dribble-buffer
456
(format "(ess-mode-1.6): editing-alist=%s \n"
457
ess-mode-editing-alist))
458
(ess-setq-vars-local ess-mode-editing-alist)
459
460
(ess-set-style ess-style t)
461
(use-local-map ess-mode-map)
462
(set-syntax-table ess-mode-syntax-table)
463
464
;; Keep <tabs> out of the code.
465
(make-local-variable 'indent-tabs-mode)
466
(setq indent-tabs-mode nil)
467
468
(put 'ess-local-process-name 'permanent-local t) ; protect from RCS
469
(setq mode-line-process
470
'(" ["
471
(:eval (ess--get-mode-line-indicator))
472
ess--local-mode-line-process-indicator
473
"]"))
474
;; completion
475
(if (and (featurep 'emacs)
476
(>= emacs-major-version 24))
477
(add-hook 'completion-at-point-functions 'ess-filename-completion nil 'local)
478
(add-hook 'comint-dynamic-complete-functions 'ess-complete-filename nil 'local)
479
(delq t comint-dynamic-complete-functions)
480
)
481
(set (make-local-variable 'comint-completion-addsuffix)
482
(cons "/" ""))
483
;; timer
484
(add-hook 'ess-idle-timer-functions 'ess-synchronize-dirs nil 'local)
485
;;; extras
486
(ess-load-extras)
487
;; SJE Tue 28 Dec 2004: do not attempt to load object name db.
488
;; (ess-load-object-name-db-file)
489
(if (> emacs-major-version 21)
490
(run-mode-hooks 'ess-mode-hook)
491
;; old emacs 21.x
492
(run-hooks 'ess-mode-hook))
493
(ess-write-to-dribble-buffer "\nFinished setting up ESS-mode.\n"))
494
495
496
(defun ess--get-mode-line-indicator ()
497
"Get `ess--mode-line-process-indicator' from process buffer.
498
Internal function to be used for dynamic mode-line dysplay in
499
ess-mode."
500
(if ess-local-process-name
501
(let* ((proc (get-process ess-local-process-name))
502
(buff (when proc (process-buffer proc))))
503
(if (and proc (buffer-live-p buff))
504
(with-current-buffer buff (mapcar 'eval ess--mode-line-process-indicator))
505
"none"))
506
"none"))
507
508
509
;;*;; User commands in ess-mode
510
511
;;;*;;; Handy commands
512
513
(defun ess-execute-in-tb ()
514
"Like `ess-execute', but always evaluates in temp buffer."
515
(interactive)
516
(let ((ess-execute-in-process-buffer nil))
517
(call-interactively 'ess-execute)))
518
519
;;;*;;; Buffer motion/manipulation commands
520
521
(defvar ess-set-function-start
522
;; setAs, setGeneric; setMethod, setReplaceMethod, setGroupMethod
523
"^set[MGAR][Ma-z]+\\s-?("
524
)
525
526
;; common R and S
527
;; SJE: 2007-07-16 add to quieten byte-compiler.
528
(defvar ess-function-pattern nil
529
"Regexp to match the beginning of a function in S buffers.")
530
531
(let*
532
((Q "\\s\"") ; quote
533
(repl "\\(<-\\)?") ; replacement (function)
534
(Sym-0 "\\(\\sw\\|\\s_\\)") ; symbol
535
(Symb (concat Sym-0 "+"))
536
(xSymb "[^ \t\n\"']+") ;; (concat "\\[?\\[?" Sym-0 "*")); symbol / [ / [[ / [symbol / [[symbol
537
;; FIXME: allow '%foo%' but only when quoted; don't allow [_0-9] at beg.
538
(_or_ "\\)\\|\\(") ; OR
539
(space "\\(\\s-\\|\n\\)*") ; white space
540
541
(part-1 (concat
542
"\\(" ;;--------outer Either-------
543
"\\(\\(" ; EITHER
544
Q xSymb Q ; any function name between quotes
545
_or_
546
"\\(^\\|[ ]\\)" Symb ; (beginning of name) + Symb
547
"\\)\\)")) ; END EITHER OR
548
549
(set-S4-exp
550
(concat
551
"^set\\(As\\|Method\\|Generic\\|GroupMethod\\|ReplaceMethod\\)(" ; S4 ...
552
Q xSymb Q "," space
553
;; and now often `` signature(......), : ''
554
".*" ;; <<< FIXME ???
555
))
556
557
(part-2 (concat
558
"\\|" ;;--------outer Or ---------
559
set-S4-exp
560
"\\)" ;;--------end outer Either/Or-------
561
562
"\\(" space "\\s<.*\\s>\\)*" ; whitespace, comment
563
;; FIXME: in principle we should skip 'definition *= *' here
564
space "function\\s-*(" ; whitespace, function keyword, parenthesis
565
))
566
)
567
568
(defvar ess-R-function-pattern
569
(concat part-1
570
"\\s-*\\(<-\\|=\\)" ; whitespace, assign
571
part-2)
572
"The regular expression for matching the beginning of an R function.")
573
574
(defvar ess-S-function-pattern
575
(concat part-1
576
"\\s-*\\(<-\\|_\\|=\\)" ; whitespace, assign (incl. "_")
577
part-2)
578
"The regular expression for matching the beginning of an S function.")
579
580
); {end let}
581
582
(defun ess-beginning-of-function (&optional no-error)
583
"Leave (and return) the point at the beginning of the current ESS function.
584
If the optional argument NO-ERROR is non-nil, the function returns nil when
585
it cannot find a function beginning."
586
587
;; FIXME: should not throw error in accordance with beginning-of-defun and
588
;; beginning-of-defun-function specification
589
590
(interactive)
591
(let ((init-point (point))
592
(in-set-S4 nil)
593
beg end done)
594
595
;; Note that we must be sure that we are past the 'function (' text,
596
;; such that ess-function-pattern is found in BACKwards later.
597
;; In case we're sitting in a function or setMethod() header,
598
;; we need to move further.
599
;; But not too far! {wrongly getting into next function}
600
(if (search-forward "("
601
(ess-line-end-position 2) t); at most end of next line
602
(forward-char 1))
603
;; TODO: replace the above by hopefully more sucessful logic:
604
;; 1. If we have 'function *(' in the same line, move to end of that line
605
;; 2. if *not*, skip all comment lines (concat space comment-char .* "\n")
606
;; and only* then do something like the
607
;; (search-forward '(' .. (..line-end.. 2) ) above
608
609
(setq end (point)); = init-point when nothing found
610
611
(ess-write-to-dribble-buffer
612
(format "ess-BEG-of-fun after 'search-FWD (': Ini-pt %d, (p)-Ini-pt = %d\n"
613
init-point (- end init-point)))
614
(if (and (> end 1)
615
(re-search-backward ;; in case of setMethod() etc ..
616
ess-set-function-start
617
;; at most 1 line earlier {2 is too much: finds previous sometimes}
618
(+ 1 (ess-line-end-position -1)) t))
619
620
(progn ;; yes we *have* an S4 setMethod(..)-like
621
(setq in-set-S4 t
622
beg (point))
623
(ess-write-to-dribble-buffer
624
(format " set*() function start at position %d" beg))
625
;; often need to move even further to have 'function(' to our left
626
;; (if (search-forward "function" end t)
627
;; (ess-write-to-dribble-buffer
628
;; (format " -> 'function' already at pos %d\n" (point)))
629
;; ;; else need to move further
630
(goto-char end)
631
;; search 4 lines, we are pretty sure now:
632
(search-forward
633
"function" (ess-line-end-position 4) t)
634
;; )
635
(search-forward "(" (ess-line-end-position) t)
636
)
637
;; else: regular function; no set*Method(..)
638
(ess-write-to-dribble-buffer "ELSE not in setMethod() header ...\n")
639
)
640
641
(while (not done)
642
;; Need this while loop to skip over local function definitions
643
644
;; In the case of non-success, it is inefficiently
645
;; going back in the buffer through all function definitions...
646
(unless
647
(and (re-search-backward ess-function-pattern (point-min) t)
648
(not (ess-inside-string-or-comment-p (point))))
649
(goto-char init-point)
650
(if no-error
651
(setq done t beg nil)
652
;; else [default]:
653
(error "Point is not in a function according to 'ess-function-pattern'.")
654
))
655
(unless done
656
(setq beg (point))
657
(ess-write-to-dribble-buffer
658
(format "\tMatch,Pt:(%d,%d),%d\n"
659
(match-beginning 0) (match-end 0) beg))
660
(setq in-set-S4 (looking-at ess-set-function-start))
661
(forward-list 1) ; get over arguments
662
663
;; The following used to bomb "Unbalanced parentheses", n1, n2
664
;; when the above (search-forward "(" ..) wasn't delimited :
665
(unless in-set-S4 (forward-sexp 1)) ; move over braces
666
;;DBG (ess-write-to-dribble-buffer "|")
667
(setq end (point))
668
(goto-char beg)
669
;; current function must begin and end around point
670
(setq done (and (>= end init-point) (<= beg init-point)))))
671
beg))
672
673
(defun ess-end-of-function (&optional beginning no-error)
674
"Leave the point at the end of the current ESS function.
675
Optional argument for location of beginning. Return '(beg end)."
676
(interactive)
677
(if beginning
678
(goto-char beginning)
679
(setq beginning (ess-beginning-of-function no-error)))
680
(if beginning
681
;; *hack* only for S (R || S+): are we in setMethod(..) etc?
682
(let ((in-set-S4 (looking-at ess-set-function-start))
683
(end-pos) (npos))
684
(ess-write-to-dribble-buffer
685
(format "ess-END-of-fun: S4=%s, beginning = %d\n" in-set-S4 beginning))
686
(forward-list 1) ; get over arguments || whole set*(..)
687
(unless in-set-S4 (forward-sexp 1)) ; move over braces
688
(ess-write-to-dribble-buffer
689
(format "ess-END-of-fun: found #1 : %d\n" (point)))
690
691
;; For one-line functions withOUT '{ .. }' body -- added 2008-07-23 --
692
;; particularly helpful for C-c C-c (ess-eval-function-or-paragraph-and-step):
693
(setq end-pos (ess-line-end-position))
694
(while (< (point) end-pos) ; if not at end of line, move further forward
695
(goto-char ;; careful not to move too far; e.g. *not* over empty lines:
696
(min (save-excursion (forward-sexp 1) (point))
697
(save-excursion (forward-paragraph 1) (point)))))
698
(list beginning (point))
699
)
700
;; else: 'no-error': we are not in a function
701
nil))
702
703
704
(defun ess-goto-beginning-of-function-or-para ()
705
"If inside a function go to the beginning of it, otherwise go to the beginning
706
of paragraph."
707
(interactive)
708
(unless (ess-beginning-of-function 'no-error)
709
(backward-paragraph)))
710
711
(defun ess-goto-end-of-function-or-para ()
712
"If inside a function go to end of it, otherwise go to the end
713
of paragraph."
714
(interactive)
715
(unless (ess-end-of-function nil 'no-error)
716
(forward-paragraph)))
717
718
;;; Kurt's version, suggested 1997-03-06.
719
(defun ess-mark-function ()
720
"Put mark at end of ESS function, point at beginning."
721
(interactive)
722
(let ((beg (ess-beginning-of-function)))
723
(push-mark (point))
724
(ess-end-of-function beg)
725
(exchange-point-and-mark)))
726
727
;; Donated by Stephen Eglen, 2001-08-29:
728
;; This command is analogous to `narrow-to-defun' (elisp)
729
;; and `py-narrow-to-defun' (python)."
730
(defun ess-narrow-to-defun ()
731
"Make text outside current function invisible.
732
If text is already narrowed, this is removed before narrowing to the
733
current function."
734
(interactive)
735
;; if point is not in a function, ess-end-of-function catches the error.
736
(save-excursion
737
(widen)
738
(let* ((beg-end (ess-end-of-function)))
739
(narrow-to-region (nth 0 beg-end) (nth 1 beg-end)))))
740
741
;;*;; Loading files
742
743
(defun ess-check-modifications nil
744
"Check whether loading this file would overwrite some ESS objects
745
which have been modified more recently than this file, and confirm
746
if this is the case."
747
;; FIXME: this should really cycle through all top-level assignments in
748
;; the buffer
749
;;VS[02-04-2012|ESS 12.03]: this is sooo ugly
750
(when (> (length ess-change-sp-regexp) 0)
751
(and (buffer-file-name) ess-filenames-map
752
(let ((sourcemod (nth 5 (file-attributes (buffer-file-name))))
753
(objname))
754
(save-excursion
755
(goto-char (point-min))
756
;; Get name of assigned object, if we can find it
757
(setq objname
758
(and
759
(re-search-forward
760
"^\\s *\"?\\(\\(\\sw\\|\\s_\\)+\\)\"?\\s *[<_]"
761
nil
762
t)
763
(buffer-substring (match-beginning 1)
764
(match-end 1)))))
765
(and
766
sourcemod ; the file may have been deleted
767
objname ; may not have been able to
768
; find name
769
(ess-modtime-gt (ess-object-modtime objname) sourcemod)
770
(not (y-or-n-p
771
772
(format
773
"The ESS object %s is newer than this file. Continue?"
774
objname)))
775
(error "Aborted"))))))
776
777
(defun ess-check-source (fname)
778
"If file FNAME has an unsaved buffer, offer to save it.
779
Returns t if the buffer existed and was modified, but was not saved."
780
(let ((buff (get-file-buffer fname)))
781
;; RMH: Corrections noted below are needed for C-c C-l to work
782
;; correctly when issued from *S* buffer.
783
;; The following barfs since
784
;; 1. `if' does not accept a buffer argument, `not' does.
785
;; 2. (buffer-file-name) is not necessarily defined for *S*
786
;;(if buff
787
;; (let ((deleted (not (file-exists-p (buffer-file-name)))))
788
;; Next 2 lines are RMH's solution:
789
(if (not(not buff))
790
(let ((deleted (not (file-exists-p fname))))
791
(if (and deleted (not (buffer-modified-p buff)))
792
;; Buffer has been silently deleted, so silently save
793
(with-current-buffer buff
794
(set-buffer-modified-p t)
795
(save-buffer))
796
(if (and (buffer-modified-p buff)
797
(or ess-mode-silently-save
798
(y-or-n-p
799
(format "Save buffer %s first? "
800
(buffer-name buff)))))
801
(with-current-buffer buff
802
(save-buffer))))
803
(buffer-modified-p buff)))))
804
805
(defvar ess-error-regexp "^\\(Syntax error: .*\\) at line \\([0-9]*\\), file \\(.*\\)$"
806
"Regexp to search for errors.")
807
808
(defun ess-parse-errors (&optional showerr reset)
809
"Jump to error in last loaded ESS source file.
810
With prefix argument, only shows the errors ESS reported."
811
;; reset argument is for compatibility with emacs next-error (tracebug
812
;; rebinds ess-parse-errors to next-error), This silences the compiler.
813
(interactive "P")
814
(ess-make-buffer-current)
815
(let ((errbuff (get-buffer ess-error-buffer-name)))
816
(if (not errbuff)
817
(error "You need to do a load first!")
818
(set-buffer errbuff)
819
(goto-char (point-max))
820
(if
821
(re-search-backward
822
;; FIXME: R does not give "useful" error messages -
823
;; ----- by default: We (ESS) could try to use a more useful one, via
824
;; options(error=essErrorHandler)
825
ess-error-regexp
826
nil
827
t)
828
(let* ((filename (buffer-substring (match-beginning 3) (match-end 3)))
829
(fbuffer (get-file-buffer filename))
830
(linenum
831
(string-to-number
832
(buffer-substring (match-beginning 2) (match-end 2))))
833
(errmess (buffer-substring (match-beginning 1) (match-end 1))))
834
(if showerr
835
(ess-display-temp-buffer errbuff)
836
(if fbuffer nil
837
(setq fbuffer (find-file-noselect filename))
838
(with-current-buffer fbuffer
839
(ess-mode)))
840
(pop-to-buffer fbuffer)
841
;;(goto-line linenum) gives warning: is said to be replaced by
842
(goto-char (point-min)) (forward-line (1- linenum)))
843
(princ errmess t))
844
(message "Not a syntax error.")
845
(ess-display-temp-buffer errbuff)))))
846
847
;;*;; ESS code formatting/indentation
848
849
;;;*;;; User commands
850
851
(defun ess-electric-brace (arg)
852
"Insert character and correct line's indentation."
853
(interactive "P")
854
;; skeleton-pair takes precedence
855
(if (and (boundp 'skeleton-pair) skeleton-pair (featurep 'skeleton))
856
(skeleton-pair-insert-maybe "{")
857
;; else
858
(let (insertpos)
859
(if (and (not arg)
860
(eolp)
861
(or (save-excursion
862
(skip-chars-backward " \t")
863
(bolp))
864
(if ess-auto-newline (progn (ess-indent-line) (newline) t) nil)))
865
(progn
866
(insert (if (featurep 'xemacs) (event-to-character last-command-event) last-command-event))
867
(ess-indent-line)
868
(if ess-auto-newline
869
(progn
870
(newline)
871
;; (newline) may have done auto-fill
872
(setq insertpos (- (point) 2))
873
(ess-indent-line)))
874
(save-excursion
875
(if insertpos (goto-char (1+ insertpos)))
876
(delete-char -1))))
877
(if insertpos
878
(save-excursion
879
(goto-char insertpos)
880
(self-insert-command (prefix-numeric-value arg)))
881
(self-insert-command (prefix-numeric-value arg))))))
882
883
;; fixeme: move into ess-indent-or-complete, indentation functions are overly
884
;; scattered around
885
(defun ess-indent-command (&optional whole-exp)
886
"Indent current line as ESS code, or in some cases insert a tab character.
887
If `ess-tab-always-indent' is non-nil (the default), always indent
888
current line. Otherwise, indent the current line only if point is at
889
the left margin or in the line's indentation; otherwise insert a tab.
890
A numeric argument, regardless of its value, means indent rigidly all
891
the lines of the expression starting after point so that this line
892
becomes properly indented. The relative indentation among the lines
893
of the expression are preserved."
894
(interactive "P")
895
(if whole-exp
896
;; If arg, always indent this line as S
897
;; and shift remaining lines of expression the same amount.
898
(let ((shift-amt (ess-indent-line))
899
beg end)
900
(save-excursion
901
(if ess-tab-always-indent
902
(beginning-of-line))
903
(setq beg (point))
904
(backward-up-list 1)
905
(forward-list 1)
906
(setq end (point))
907
(goto-char beg)
908
(forward-line 1)
909
(setq beg (point)))
910
(if (> end beg)
911
(indent-code-rigidly beg end shift-amt)))
912
(if (and (not ess-tab-always-indent)
913
(save-excursion
914
(skip-chars-backward " \t")
915
(not (bolp))))
916
(insert-tab)
917
;; call ess-indent-line
918
(funcall indent-line-function))))
919
920
921
(defun ess-indent-or-complete ()
922
"When region is selected indent the region, otherwise, if
923
`ess-tab-complete-in-script' is non-nil, try to indent, if code
924
is already indented, complete instead.
925
926
The default of `ess-tab-complete-in-script' is nil. Also see
927
`ess-first-tab-never-complete'."
928
(interactive)
929
(if (use-region-p)
930
(indent-region (region-beginning) (region-end))
931
(let ((shift (ess-indent-command)))
932
(when (and ess-tab-complete-in-script
933
(numberp shift) ;; can be nil if ess-tab-always-indent is nil
934
(equal shift 0)
935
(or (eq last-command 'ess-indent-or-complete)
936
(null ess-first-tab-never-complete)
937
(and (eq ess-first-tab-never-complete 'unless-eol)
938
(looking-at "\\s-*$"))
939
(and (eq ess-first-tab-never-complete 'symbol)
940
(not (looking-at "\\w\\|\\s_")))
941
(and (eq ess-first-tab-never-complete 'symbol-or-paren)
942
(not (looking-at "\\w\\|\\s_\\|\\s)")))
943
(and (eq ess-first-tab-never-complete 'symbol-or-paren-or-punct)
944
(not (looking-at "\\w\\|\\s_\\|\\s)\\|\\s.")))
945
))
946
(if (and (featurep 'emacs) (>= emacs-major-version 24))
947
(completion-at-point)
948
(comint-dynamic-complete)
949
)))))
950
951
(defun ess-indent-exp ()
952
"Indent each line of the ESS grouping following point."
953
(interactive)
954
(save-excursion
955
(let ((start (point))
956
(end (ignore-errors (forward-sexp 1) (point))))
957
(when end
958
(indent-region start end)))))
959
960
;;;*;;; Support functions for indentation
961
962
(defun ess-comment-indent ()
963
(if (or (looking-at "###")
964
(and (looking-at "#!") (= 1 (line-number-at-pos))))
965
(current-column)
966
(if (looking-at "##")
967
(let ((tem (ess-calculate-indent)))
968
(if (listp tem) (car tem) tem))
969
(skip-chars-backward " \t")
970
(max (if (bolp) 0 (1+ (current-column)))
971
comment-column))))
972
973
(defun ess-indent-line ()
974
"Indent current line as ESS code.
975
Return the amount the indentation changed by."
976
;; fixme: make this work with standard indent-line-function
977
(if (fboundp ess-indent-line-function)
978
(funcall ess-indent-line-function)
979
;; else S and R default behavior
980
(let ((indent (ess-calculate-indent nil))
981
beg shift-amt
982
(case-fold-search nil)
983
(pos (- (point-max) (point))))
984
(beginning-of-line)
985
(setq beg (point))
986
(cond ((eq indent nil)
987
(setq indent (current-indentation)))
988
(t
989
(skip-chars-forward " \t")
990
(cond ((and ess-fancy-comments ;; ### or #!
991
(or (looking-at "###")
992
(and (looking-at "#!") (= 1 (line-number-at-pos)))))
993
(setq indent 0))
994
;; Single # comment
995
((and ess-fancy-comments
996
(looking-at "#") (not (looking-at "##")) (not (looking-at "#'")))
997
(setq indent comment-column))
998
(t
999
(if (eq indent t) (setq indent 0))
1000
(if (listp indent) (setq indent (car indent)))
1001
(cond ((and (looking-at "else\\b")
1002
(not (looking-at "else\\s_")))
1003
(setq indent (save-excursion
1004
(ess-backward-to-start-of-if)
1005
(+ ess-else-offset (current-column)))))
1006
((= (following-char) ?})
1007
(setq indent
1008
(+ indent
1009
(- ess-close-brace-offset ess-indent-level))))
1010
((= (following-char) ?{)
1011
(setq indent (+ indent ess-brace-offset))))))))
1012
(skip-chars-forward " \t")
1013
(setq shift-amt (- indent (current-column)))
1014
(if (zerop shift-amt)
1015
(if (> (- (point-max) pos) (point))
1016
(goto-char (- (point-max) pos)))
1017
(delete-region beg (point))
1018
(indent-to indent)
1019
;; If initial point was within line's indentation,
1020
;; position after the indentation.
1021
;; Else stay at same point in text.
1022
(when (> (- (point-max) pos) (point))
1023
(goto-char (- (point-max) pos))))
1024
shift-amt)))
1025
1026
1027
(defun ess-looking-at-last-open-paren-p ()
1028
(looking-at "[[:blank:]]*([[:blank:]]*\\($\\|#\\)"))
1029
1030
(defun ess-calculate-indent--closing-paren ()
1031
(search-forward ")")
1032
(backward-sexp)
1033
(if (ess-looking-at-last-open-paren-p)
1034
;; If this line ends with "("
1035
(current-indentation)
1036
;; otherwise
1037
(+ (current-column) 1)))
1038
1039
(defun ess-calculate-indent--default (&optional parse-start)
1040
(let ((indent-point (point))
1041
(beginning-of-defun-function nil) ;; don't call ess-beginning-of-function
1042
(open-paren-in-column-0-is-defun-start t) ;; basically go to point-min (no better solution aparently)
1043
(case-fold-search nil)
1044
state ind
1045
containing-sexp)
1046
(if parse-start
1047
(goto-char parse-start)
1048
;; this one is awful; with open-paren-in-column-0-is-defun-start t, it
1049
;; always goes to point-min
1050
(beginning-of-defun))
1051
(while (< (point) indent-point)
1052
(setq parse-start (point))
1053
(setq state (parse-partial-sexp (point) indent-point 0))
1054
(setq containing-sexp (car (cdr state))))
1055
(cond ((or (nth 3 state) (nth 4 state))
1056
;; return nil (in string) or t (in comment)
1057
(nth 4 state))
1058
((and (null containing-sexp)
1059
(= (following-char) ?\{))
1060
0)
1061
((setq ind (ess--continued-block-statement containing-sexp))
1062
(+ ind ess-indent-level))
1063
((setq ind (ess--continued-statement containing-sexp))
1064
(+ ind ess-continued-statement-offset))
1065
((null containing-sexp)
1066
0)
1067
;; ;; Line is at top level. May be data or function definition
1068
;; ;; or continuation of if,for,else not folowed by {
1069
;; (beginning-of-line)
1070
;; (if (/= (following-char) ?\{)
1071
;; (cond ((setq ind (ess--continued-block-statement containing-sexp))
1072
;; (+ ind ess-indent-level))
1073
;; ((setq ind (ess--continued-statement containing-sexp))
1074
;; (+ ind ess-continued-statement-offset))
1075
;; (t 0))
1076
;; 0))
1077
((/= (char-after containing-sexp) ?{)
1078
;; line is expression, not statement:
1079
;; indent to just after the surrounding open.
1080
(goto-char containing-sexp)
1081
(let ((bol (line-beginning-position)))
1082
1083
(cond ((and (numberp ess-expression-offset)
1084
(re-search-backward "[ \t]*expression[ \t]*(" bol t))
1085
;; obj <- expression(...
1086
;; modified by shiba (forward-sexp -1)
1087
1088
(beginning-of-line)
1089
(skip-chars-forward " \t")
1090
;; end{modified}
1091
(+ (current-column) ess-expression-offset))
1092
((and (numberp ess-arg-function-offset)
1093
(re-search-backward
1094
"=[ \t]*\\s\"*\\(\\w\\|\\s_\\)+\\s\"*[ \t]*"
1095
bol t))
1096
(forward-sexp -1)
1097
(+ (current-column) ess-arg-function-offset))
1098
;; now, distinguish between
1099
;; a <- some.function(arg1,
1100
;; arg2)
1101
;; and
1102
;; a <- some.function(
1103
;; arg1,
1104
;; arg2)
1105
;;
1106
;; case 1: numeric
1107
((and (numberp ess-arg-function-offset-new-line)
1108
(ess-looking-at-last-open-paren-p))
1109
(forward-sexp -1)
1110
(+ (current-column) ess-arg-function-offset-new-line))
1111
;; case 2: list
1112
((and (listp ess-arg-function-offset-new-line)
1113
(numberp (car ess-arg-function-offset-new-line))
1114
(ess-looking-at-last-open-paren-p))
1115
;; flush args to the begining of
1116
(beginning-of-line)
1117
(skip-chars-forward " \t")
1118
(+ (current-column) (car ess-arg-function-offset-new-line)))
1119
;; End
1120
(t
1121
(progn (goto-char (1+ containing-sexp))
1122
(current-column))))))
1123
(t
1124
;; Statement level (containing-sexp char is "{"). Is it a continuation
1125
;; or a new statement? Find previous non-comment character.
1126
(goto-char indent-point)
1127
(ess-backward-to-noncomment containing-sexp)
1128
;; Back up over label lines, since they don't
1129
;; affect whether our line is a continuation.
1130
(while (eq (preceding-char) ?\,)
1131
(ess-backward-to-start-of-continued-exp containing-sexp)
1132
(beginning-of-line)
1133
(ess-backward-to-noncomment containing-sexp))
1134
(forward-line 1)
1135
;; Now we get the answer.
1136
(if (ess--continued-statement)
1137
;; This line is continuation of preceding line's statement;
1138
;; indent ess-continued-statement-offset more than the
1139
;; previous line of the statement.
1140
(progn
1141
(ess-backward-to-start-of-continued-exp containing-sexp)
1142
(+ ess-continued-statement-offset (current-column)
1143
(if (save-excursion (goto-char indent-point)
1144
(skip-chars-forward " \t")
1145
(eq (following-char) ?{))
1146
ess-continued-brace-offset 0)))
1147
;; This line starts a new statement.
1148
;; Position following last unclosed open.
1149
(goto-char containing-sexp)
1150
;; Is line first statement after an open-brace?
1151
(or
1152
;; If no, find that first statement and indent like it.
1153
(save-excursion
1154
(forward-char 1)
1155
(while (progn (skip-chars-forward " \t\n")
1156
(looking-at "#"))
1157
;; Skip over comments following openbrace.
1158
(forward-line 1))
1159
;; The first following code counts
1160
;; if it is before the line we want to indent.
1161
(and (< (point) indent-point)
1162
(current-column)))
1163
;; If no previous statement,
1164
;; indent it relative to line brace is on.
1165
;; For open brace in column zero, don't let statement
1166
;; start there too. If ess-indent-level is zero,
1167
;; use ess-brace-offset +
1168
;; ess-continued-statement-offset instead.
1169
;; For open-braces not the first thing in a line,
1170
;; add in ess-brace-imaginary-offset.
1171
(+ (if (and (bolp) (zerop ess-indent-level))
1172
(+ ess-brace-offset ess-continued-statement-offset)
1173
ess-indent-level)
1174
;; Move back over whitespace before the openbrace.
1175
;; If openbrace is not first nonwhite thing on the line,
1176
;; add the ess-brace-imaginary-offset.
1177
(progn (skip-chars-backward " \t")
1178
(if (bolp) 0 ess-brace-imaginary-offset))
1179
;; If the openbrace is preceded by a parenthesized exp,
1180
;; move to the beginning of that;
1181
;; possibly a different line
1182
(progn
1183
(if (eq (preceding-char) ?\))
1184
(forward-sexp -1))
1185
;; Get initial indentation of the line we are on.
1186
(current-indentation)))))))))
1187
1188
1189
(defun ess-calculate-indent (&optional parse-start)
1190
"Return appropriate indentation for current line as ESS code.
1191
In usual case returns an integer: the column to indent to.
1192
Returns nil if line starts inside a string, t if in a comment."
1193
(save-excursion
1194
(beginning-of-line)
1195
(cond
1196
1197
;; Identation for a closing parenthesis
1198
((looking-at "[[:blank:]]*\)")
1199
(ess-calculate-indent--closing-paren))
1200
1201
;; Unindent lines that begin with ','
1202
((looking-at "[[:blank:]]*\,")
1203
(let ((indent (save-excursion
1204
(ess-calculate-indent--default parse-start)))
1205
(unindent (progn (skip-chars-forward " \t")
1206
;; return number of skiped chars
1207
(skip-chars-forward ", \t"))))
1208
(- indent unindent)))
1209
1210
;; default indentation rules
1211
(t
1212
(ess-calculate-indent--default parse-start)))))
1213
1214
1215
(defun ess--continued-block-statement (&optional containing-sexp)
1216
"If a continuation line of a block, return and indent of this line, otherwise nil."
1217
(save-excursion
1218
(beginning-of-line)
1219
(ess-backward-to-noncomment containing-sexp)
1220
(cond ((memq (preceding-char) '(nil ?\, ?\; ?\} ?\{ ?\] ?\())
1221
nil)
1222
;; treat <- to avoid creating another check function
1223
((looking-back "<-")
1224
(current-indentation))
1225
((= (preceding-char) ?\)) ;; if, for, while
1226
(ignore-errors
1227
;; if throws an error clearly not a continuation
1228
;; can happen if the parenthetical statement starts a new line
1229
;; (foo) ## or
1230
;; !(foo)
1231
(forward-sexp -2)
1232
(cond ((looking-at "for\\b[ \t]*(\\|while\\b[ \t]*(")
1233
(current-column))
1234
((looking-at "if\\b[ \t]*(")
1235
(when (looking-back "\\belse[ \t]*")
1236
(backward-sexp 1))
1237
(current-column))
1238
((looking-at "function\\b[ \t]*(")
1239
(current-indentation)))))
1240
((progn (ignore-errors (forward-sexp -1))
1241
(looking-at "else\\b\\|repeat\\b\\([:blank:]*\|\\&\\)"))
1242
(let ((col (current-column)))
1243
(skip-chars-backward " \t")
1244
(if (or (bolp)
1245
(eq (preceding-char) ?\;))
1246
(- col (current-column))
1247
(when (eq ?} (preceding-char))
1248
(- (current-column) 1)))))
1249
)))
1250
1251
1252
(defun ess--continued-statement (&optional containing-sexp)
1253
"If a continuation line, return an indent of this line, otherwise nil."
1254
(save-excursion
1255
(beginning-of-line)
1256
(ess-backward-to-noncomment containing-sexp)
1257
;; this function is always called at eol
1258
(let ((eol (point)))
1259
(cond ((memq (preceding-char) '(nil ?\, ?\; ?\} ?\{ ?\] ?\())
1260
nil)
1261
((ignore-errors (up-list -1)
1262
(looking-back "if[ \t]*"))
1263
;; statements withing "if" condition it always ignore our
1264
;; continuation rules
1265
nil)
1266
((progn (goto-char eol)
1267
(skip-chars-backward " \t")
1268
(or (and (> (current-column) 1)
1269
(and (not (looking-back "<-"))
1270
(looking-back "[-:+*/><=&|]")))
1271
(and (> (current-column) 3)
1272
(progn (backward-char 3)
1273
(looking-at "%[^ \t]%")))))
1274
(let ((first-indent
1275
(or (and (/= ess-first-continued-statement-offset 0)
1276
(null (ess--continued-statement containing-sexp))
1277
ess-first-continued-statement-offset)
1278
0)))
1279
(+ first-indent
1280
(if containing-sexp
1281
(if (> (point-at-bol) containing-sexp)
1282
(current-indentation)
1283
(goto-char containing-sexp)
1284
(1+ (current-column)))
1285
(+ (current-indentation))))))
1286
(t nil)))))
1287
1288
(defun ess-backward-to-noncomment (lim)
1289
;; this one is bad. Use
1290
(let ((lim (or lim (point-min)))
1291
opoint stop)
1292
(while (not stop)
1293
(skip-chars-backward " \t\n\f" lim)
1294
(setq opoint (point))
1295
(beginning-of-line)
1296
(search-forward "#" opoint 'move)
1297
(skip-chars-backward " \t#")
1298
(setq stop (or (/= (preceding-char) ?\n) (<= (point) lim)))
1299
(if stop (point)
1300
(beginning-of-line)))))
1301
1302
(defun ess-backward-to-start-of-continued-exp (lim)
1303
(if (= (preceding-char) ?\))
1304
(forward-sexp -1))
1305
(beginning-of-line)
1306
(if (<= (point) lim)
1307
(goto-char (1+ lim)))
1308
(skip-chars-forward " \t"))
1309
1310
(defun ess-backward-to-start-of-if (&optional limit)
1311
"Move to the start of the last ``unbalanced'' 'if' or 'else if'
1312
expression."
1313
(let ((beginning-of-defun-function nil))
1314
(or limit (setq limit (save-excursion (beginning-of-defun) (point))))
1315
(let ((if-level 1)
1316
(case-fold-search nil))
1317
(while (not (zerop if-level))
1318
(backward-sexp 1)
1319
(cond ((looking-at "else\\b")
1320
(setq if-level (1+ if-level)))
1321
((looking-at "if\\b")
1322
(when (looking-back "\\belse[[:blank:]]*")
1323
(backward-sexp 1))
1324
(setq if-level (1- if-level)))
1325
((< (point) limit)
1326
(setq if-level 0)
1327
(goto-char limit)))))))
1328
1329
;;;*;;; Predefined indentation styles
1330
1331
(defun ess-set-style (&optional style quiet)
1332
"Set up the `ess-mode' style variables from the `ess-style' variable
1333
or if STYLE argument is given, use that. It makes the ESS indentation
1334
style variables buffer local."
1335
1336
(interactive)
1337
(let ((ess-styles (mapcar 'symbol-name (mapcar 'car ess-style-alist))))
1338
(if (called-interactively-p 'any)
1339
(setq style
1340
(intern (ess-completing-read "Set ESS mode indentation style"
1341
ess-styles nil t nil nil ess-default-style))))
1342
(setq style (or style ess-style))
1343
(make-local-variable 'ess-style)
1344
(if (memq (symbol-name style) ess-styles)
1345
(setq ess-style style)
1346
(error (format "Bad ESS style: %s" style)))
1347
(if (not quiet)
1348
(message "ESS-style: %s" ess-style))
1349
;; finally, set the indentation style variables making each one local
1350
(mapc (lambda (ess-style-pair)
1351
(make-local-variable (car ess-style-pair))
1352
(set (car ess-style-pair)
1353
(eval (cdr ess-style-pair))))
1354
(cdr (assq ess-style ess-style-alist)))
1355
ess-style))
1356
1357
;;*;; Creating and manipulating dump buffers
1358
1359
;;;*;;; The user command
1360
1361
(defun ess-dump-object-into-edit-buffer (object)
1362
"Edit an ESS object in its own buffer.
1363
1364
Without a prefix argument, this simply finds the file pointed to by
1365
`ess-source-directory'. If this file does not exist, or if a
1366
prefix argument is given, a dump() command is sent to the ESS process to
1367
generate the source buffer."
1368
(interactive
1369
(progn
1370
(ess-force-buffer-current "Process to dump from: ")
1371
(if (ess-ddeclient-p)
1372
(list (read-string "Object to edit: "))
1373
(ess-read-object-name "Object to edit"))))
1374
1375
(let* ((dirname (file-name-as-directory
1376
(if (stringp ess-source-directory)
1377
ess-source-directory
1378
(with-current-buffer (process-buffer (ess-get-process
1379
ess-local-process-name))
1380
(ess-setq-vars-local ess-customize-alist)
1381
(apply ess-source-directory nil)))))
1382
(filename (concat dirname (format ess-dump-filename-template object)))
1383
(old-buff (get-file-buffer filename)))
1384
1385
;; If the directory doesn't exist, offer to create it
1386
(if (file-exists-p (directory-file-name dirname)) nil
1387
(if (y-or-n-p ; Approved
1388
(format "Directory %s does not exist. Create it? " dirname))
1389
(make-directory (directory-file-name dirname))
1390
(error "Directory %s does not exist." dirname)))
1391
1392
;; Three options:
1393
;; (1) Pop to an existing buffer containing the file in question
1394
;; (2) Find an existing file
1395
;; (3) Create a new file by issuing a dump() command to S
1396
;; Force option (3) if there is a prefix arg
1397
1398
(if current-prefix-arg
1399
(ess-dump-object object filename)
1400
(if old-buff
1401
(progn
1402
(pop-to-buffer old-buff)
1403
(message "Popped to edit buffer."))
1404
;; No current buffer containing desired file
1405
(if (file-exists-p filename)
1406
(progn
1407
(ess-find-dump-file-other-window filename)
1408
(message "Read %s" filename))
1409
;; No buffer and no file
1410
(ess-dump-object object filename))))))
1411
1412
(defun ess-dump-object (object filename)
1413
"Dump the ESS object OBJECT into file FILENAME."
1414
(let ((complete-dump-command (format inferior-ess-dump-command
1415
object filename)))
1416
(if (file-writable-p filename) nil
1417
(error "Can't dump %s as %f is not writeable." object filename))
1418
1419
(if (ess-ddeclient-p)
1420
;; ddeclient version
1421
(ess-dump-object-ddeclient object filename)
1422
1423
;; else: "normal", non-DDE behavior:
1424
1425
;; Make sure we start fresh
1426
(if (get-file-buffer filename)
1427
(kill-buffer (get-file-buffer filename)))
1428
1429
(ess-command complete-dump-command)
1430
(message "Dumped in %s" filename)
1431
1432
(ess-find-dump-file-other-window filename)
1433
1434
;; PD, 1Apr97
1435
;;This ensures that the object gets indented according to ess-mode,
1436
;;not as the R/S deparser does it. At the same time, it gets rid
1437
;;of the mess generated by sending TAB characters to the readline
1438
;;functions in R when you eval-buffer-*.
1439
(indent-region (point-min-marker) (point-max-marker) nil)
1440
(set-buffer-modified-p nil) ; no need to safe just because of indenting
1441
1442
;; Don't make backups for temporary files; it only causes clutter.
1443
;; The ESS object itself is a kind of backup, anyway.
1444
(unless ess-keep-dump-files
1445
(make-local-variable 'make-backup-files)
1446
(setq make-backup-files nil))
1447
1448
;; Don't get confirmation to delete dumped files when loading
1449
(if (eq ess-keep-dump-files 'check)
1450
(setq ess-keep-dump-files nil))
1451
1452
;; Delete the file if necessary
1453
(if ess-delete-dump-files
1454
(delete-file (buffer-file-name))))))
1455
1456
(defun ess-find-dump-file-other-window (filename)
1457
"Find ESS source file FILENAME in another window."
1458
1459
(if (file-exists-p filename) nil
1460
(ess-write-to-dribble-buffer
1461
(format "%s does not exist. Bad dump, starting fresh." filename)))
1462
1463
;; Generate a buffer with the dumped data
1464
(find-file-other-window filename)
1465
(ess-mode ess-customize-alist)
1466
1467
(auto-save-mode 1) ; Auto save in this buffer
1468
(setq ess-local-process-name ess-current-process-name)
1469
1470
(if ess-function-template
1471
(progn
1472
(goto-char (point-max))
1473
(if (re-search-backward ess-dumped-missing-re nil t)
1474
(progn
1475
(replace-match ess-function-template t t)
1476
(set-buffer-modified-p nil) ; Don't offer to save if killed now
1477
(goto-char (point-min))
1478
(condition-case nil
1479
;; This may fail if there are no opens
1480
(down-list 1)
1481
(error nil)))))))
1482
1483
;; AJR: XEmacs, makes sense to dump into "other frame".
1484
(defun ess-dump-object-into-edit-buffer-other-frame (object)
1485
"Edit an ESS object in its own frame."
1486
(switch-to-buffer-other-frame (ess-dump-object-into-edit-buffer object)))
1487
1488
(provide 'ess-mode)
1489
1490
; Local variables section
1491
1492
;;; This file is automatically placed in Outline minor mode.
1493
;;; The file is structured as follows:
1494
;;; Chapters: ^L ;
1495
;;; Sections: ;;*;;
1496
;;; Subsections: ;;;*;;;
1497
;;; Components: defuns, defvars, defconsts
1498
;;; Random code beginning with a ;;;;* comment
1499
1500
;;; Local variables:
1501
;;; mode: emacs-lisp
1502
;;; outline-minor-mode: nil
1503
;;; mode: outline-minor
1504
;;; outline-regexp: "\^L\\|\\`;\\|;;\\*\\|;;;\\*\\|(def[cvu]\\|(setq\\|;;;;\\*"
1505
;;; End:
1506
1507
;;; ess-mode.el ends here
1508
1509