Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
2701 views
1
;;; ess-help.el --- Support for viewing ESS help files
2
3
;; Copyright (C) 1989-1994 Bates, Kademan, Ritter and Smith
4
;; Copyright (C) 1997, A.J. Rossini <[email protected]>
5
;; Copyright (C) 1998--2001 A.J. Rossini, Martin Maechler, Kurt Hornik and
6
;; Richard M. Heiberger <[email protected]>.
7
;; Copyright (C) 2001--2010 A.J. Rossini, Richard M. Heiberger, Martin
8
;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
9
;; Copyright (C) 2011--2012 A.J. Rossini, Richard M. Heiberger, Martin Maechler,
10
;; Kurt Hornik, Rodney Sparapani, Stephen Eglen and Vitalie Spinu.
11
12
;; Author: David Smith <[email protected]>
13
;; Created: 7 Jan 1994
14
;; Maintainer: ESS-core <[email protected]>
15
16
;; This file is part of ESS
17
18
;; This file is free software; you can redistribute it and/or modify
19
;; it under the terms of the GNU General Public License as published by
20
;; the Free Software Foundation; either version 2, or (at your option)
21
;; any later version.
22
23
;; This file is distributed in the hope that it will be useful,
24
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
25
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26
;; GNU General Public License for more details.
27
28
;; A copy of the GNU General Public License is available at
29
;; http://www.r-project.org/Licenses/
30
31
;;; Commentary:
32
33
;; Code for dealing with ESS help files. See README.<LANGUAGE> where
34
;; <LANGUAGE> is one of `S', `SAS', `Stata'or `XLispStat'.
35
36
;;; Code:
37
38
; Requires and autoloads
39
40
(eval-when-compile
41
(require 'reporter)
42
(require 'ess-inf)
43
(require 'info))
44
45
(require 'ess)
46
47
(autoload 'ess-eval-region "ess-inf" "[autoload]" t)
48
(autoload 'ess-eval-region-and-go "ess-inf" "[autoload]" t)
49
(autoload 'ess-eval-function "ess-inf" "[autoload]" t)
50
(autoload 'ess-eval-function-and-go "ess-inf" "[autoload]" t)
51
(autoload 'ess-eval-line "ess-inf" "[autoload]" t)
52
(autoload 'ess-eval-line-and-go "ess-inf" "[autoload]" t)
53
(autoload 'ess-eval-line-and-step "ess-inf" "[autoload]" t)
54
(autoload 'ess-with-current-buffer "ess-inf" "[autoload]" t)
55
56
(autoload 'ess-goto-beginning-of-function-or-para "ess-mode" "[autoload]" t)
57
(autoload 'ess-goto-end-of-function-or-para "ess-mode" "[autoload]" t)
58
59
(autoload 'ess-load-file "ess-inf" "[autoload]" t)
60
(autoload 'ess-command "ess-inf" "(autoload)" nil)
61
(autoload 'ess-display-temp-buffer "ess-inf" "(autoload)" nil)
62
(autoload 'ess-switch-to-ESS "ess-inf" "(autoload)" nil)
63
(autoload 'ess-read-object-name-default "ess-inf" "(autoload)" nil)
64
(autoload 'ess-make-buffer-current "ess-inf" "(autoload)" nil)
65
(autoload 'ess-search-list "ess-inf" "(autoload)" nil)
66
(autoload 'ess-get-object-list "ess-inf" "(autoload)" nil)
67
68
(autoload 'ess-ddeclient-p "ess-inf" "(autoload)" nil)
69
70
(autoload 'ess-display-help-on-object-ddeclient "ess-dde" "(autoload)" nil)
71
72
(autoload 'tramp-tramp-file-p "tramp" "(autoload).")
73
(autoload 'tramp-file-name-localname "tramp" "(autoload).")
74
(autoload 'tramp-dissect-file-name "tramp" "(autoload).")
75
(autoload 'with-parsed-tramp-file-name "tramp" "(autolaod).")
76
77
; ess-help-mode
78
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
79
;;;; In this section:
80
;;;;
81
;;;; * The function ess-display-help-on-object
82
;;;; * The major mode ess-help-mode
83
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
84
85
(defun ess--help-get-bogus-buffer-substring (buffer &optional nr-first)
86
"Return non-nil if BUFFER looks like a bogus ESS help buffer.
87
Return the pair (match-beg. match-end) which can be used in error message.
88
NR-FIRST is the number of characters at the start of the buffer
89
to examine when deciding if the buffer if bogus. If nil, the
90
first 150 characters of the buffer are searched."
91
92
(if (not nr-first) (setq nr-first 150))
93
94
(with-current-buffer buffer
95
(let ((PM (point-min))
96
(case-fold-search t)
97
searching res)
98
99
(setq res
100
(or ;; evaluate up to first non-nil (or end):
101
(< (- (point-max) PM) 80); buffer less than 80 chars
102
(not (setq searching t))
103
;; todo: move to customize-alist
104
(progn (goto-char PM) ;; R:
105
(re-search-forward "Error in help" nr-first t))
106
(progn (goto-char PM) ;; S-plus 5.1 :
107
(re-search-forward "^cat: .*--" nr-first t))
108
(progn (goto-char PM) ;; S version 3 ; R :
109
(re-search-forward "no documentation .+" nr-first t))
110
(progn (goto-char PM) ;; stata
111
(re-search-forward "^help .*not found" nr-first t))
112
))
113
(ess-write-to-dribble-buffer
114
(format " |--> %s [searching %s]\n" res searching))
115
116
(when res
117
(if searching
118
(buffer-substring (match-beginning 0) (match-end 0))
119
(buffer-string))))))
120
121
(defvar ess-help-type nil
122
"Type of help file, help, index, vingettes etc.
123
Local in ess-help buffers.")
124
(make-variable-buffer-local 'ess-help-type)
125
126
(defvar ess-help-object nil
127
"Name of the object the help is displayed for.
128
Is name of the package for package index.
129
Local in ess-help buffers.")
130
(make-variable-buffer-local 'ess-help-object)
131
132
133
(defun ess-display-help-on-object (object &optional command)
134
"Display documentation for OBJECT in another window.
135
If prefix arg is given, force an update of the cached help topics
136
and query the ESS process for the help file instead of reusing an
137
existing buffer if it exists. Uses the variable
138
`inferior-ess-help-command' for the actual help command. Prompts
139
for the object name based on the cursor location for all cases
140
except the S-Plus GUI. With S-Plus on Windows (both GUI and in
141
an inferior emacs buffer) the GUI help window is used.
142
143
If COMMAND is suplied, it is used instead of `inferior-ess-help-command'.
144
"
145
(interactive
146
(progn
147
(ess-force-buffer-current)
148
(when current-prefix-arg ;update cache if prefix
149
(ess-process-put 'sp-for-help-changed? t))
150
(if (ess-ddeclient-p)
151
(list (read-string "Help on: "))
152
(list (ess-find-help-file "Help on")))))
153
154
(if (or (ess-ddeclient-p)
155
(equal inferior-ess-help-filetype "chm"))
156
(if (ess-ddeclient-p)
157
(ess-display-help-on-object-ddeclient object) ;; ddeclient version
158
(ess-eval-linewise (concat "help(" object ")"))) ;; "chm" version
159
160
;; else: "normal", non-DDE behavior:
161
(let* ((hb-name (concat "*help["
162
ess-current-process-name
163
"](" (replace-regexp-in-string "^\\?\\|`" "" object) ")*"))
164
(old-hb-p (get-buffer hb-name))
165
(tbuffer (get-buffer-create hb-name)))
166
(when (or (not old-hb-p)
167
current-prefix-arg
168
(ess--help-get-bogus-buffer-substring old-hb-p))
169
(ess-with-current-buffer tbuffer
170
(setq ess-help-object object
171
ess-help-type 'help)
172
(ess--flush-help-into-current-buffer object command)))
173
(unless (ess--help-kill-bogus-buffer-maybe tbuffer)
174
(ess--switch-to-help-buffer tbuffer)))))
175
176
(defun ess--flush-help-into-current-buffer (object &optional command dont-ask)
177
(ess-write-to-dribble-buffer
178
(format "(ess-help '%s' start ..\n" (buffer-name (current-buffer))))
179
180
;; Ask the corresponding ESS process for the help file:
181
(if buffer-read-only (setq buffer-read-only nil))
182
(delete-region (point-min) (point-max))
183
(ess-help-mode)
184
(when (and (null command)
185
(string-match "^R" ess-dialect))
186
;;VS[16-12-2012]: ugly hack to avoid tcl/tk dialogs (should go away soon)
187
(let ((packs (ess-get-words-from-vector
188
(format "as.character(help('%s'))\n" object))))
189
(when (> (length packs) 1)
190
(setq
191
command (format ;; crippled S3 :(
192
"do.call(structure, c('%s', attributes(help('%s'))))\n"
193
(if dont-ask
194
(car packs)
195
(ess-completing-read "Choose location" packs nil t))
196
object)))))
197
(ess-command (format (or command inferior-ess-help-command)
198
object) (current-buffer))
199
(ess-help-underline)
200
;;VS[03-09-2012]: todo: this should not be here:
201
;; Stata is clean, so we get a big BARF from this.
202
(unless (string= ess-language "STA")
203
(ess-nuke-help-bs))
204
(goto-char (point-min))
205
(set-buffer-modified-p 'nil)
206
(setq buffer-read-only t)
207
(setq truncate-lines nil))
208
209
210
(defun ess--help-kill-bogus-buffer-maybe (buffer)
211
"Internal, try to kill bogus buffer with message. Return t if killed."
212
(when ess-help-kill-bogus-buffers
213
(let ((bog-mes (ess--help-get-bogus-buffer-substring buffer)))
214
(when bog-mes
215
(when (< (length bog-mes) 10) ;;no message at all, how to treat this properly?
216
(setq bog-mes (format "No documentation found; %s" bog-mes)))
217
(ess-write-to-dribble-buffer
218
(format "(ess-help: kill bogus buffer %s ..\n" (buffer-name buffer)))
219
(message "%s" (replace-regexp-in-string "\n" "" bog-mes))
220
;; (ding) ;; don't ding, in julia a lot of doc strings are very short
221
(kill-buffer buffer)))))
222
223
(defun ess-display-help-in-browser ()
224
"Displaying html help where available, using \\[browse-url]."
225
(interactive)
226
;; Three ways to find html help, 1) ask sub-process 2) get url/file from subproces
227
;; 3) call elisp function to get the file path
228
;; For 2 and 3 call browse-url on the output
229
(let (com-html-help ;1) command for sub-process to trigger
230
;help, must contain %s for help obj
231
com-get-file-path ;2) command for sub-process to return a
232
; location for the help page, must
233
; contain %s for help obj
234
fun-get-file-path ;3) elisp function to return the
235
;location, gets one argument, help topic
236
not-implemented
237
)
238
(cond
239
((string-match "^R" ess-dialect)
240
(setq com-html-help "help('%s', help_type='html')\n"))
241
(t (setq not-implemented t))
242
)
243
(if not-implemented
244
(message "Sorry, not implemented for %s " ess-dialect)
245
(if (or (not ess-help-object)
246
(not (eq ess-help-type 'help)))
247
(message "No help topic found")
248
(if com-html-help
249
(ess-command (format com-html-help ess-help-object))
250
(require 'browse-url)
251
(if com-get-file-path
252
(browse-url (car (ess-get-words-from-vector (format com-get-file-path ess-help-object))))
253
(when (functionp fun-get-file-path)
254
(browse-url (funcall fun-get-file-path ess-help-object))))))
255
)))
256
257
(defun ess--action-help-on-object (&optional button)
258
"Provide help on object at the beginning of line.
259
It's intended to be used in R-index help pages. Load the package
260
if necessary. It is bound to RET and C-m in R-index pages."
261
(interactive)
262
(let* ((string (button-label button))
263
(command
264
(when (equal ess-dialect "R")
265
(cond ((string-match"::" string)
266
(format "?%s\n" (ess-R--sanitize-help-topic string)))
267
((eq ess-help-type 'index)
268
(concat "?" ess-help-object "::`%s`\n"))
269
))))
270
(ess-display-help-on-object string command)
271
))
272
273
274
(defun ess-display-package-index ()
275
"Prompt for package name and display its index."
276
(interactive)
277
(let ((object (buffer-name))
278
(alist ess-local-customize-alist)
279
(pname ess-local-process-name)
280
pack buff all-packs not-implemented
281
;; Available customization for ess languages/dialects:
282
com-package-for-object ;command to get the package of current help object
283
com-packages ;command to get a list of available packages (REQUIRED)
284
com-package-index ;command to get the package index (REQUIRED)
285
reg-keyword ;regexp used to find keywords for linking in index listing
286
; only (1st subexpression is used)
287
reg-start ;regexp from where to start searching for keywords in index listing
288
)
289
(cond
290
((string-match "^R" ess-dialect)
291
;; carefully using syntax to be parsed in old R versions (no '::', '_'):
292
(setq com-package-for-object "sub('package:', '', .ess.findFUN('%s'))\n"
293
com-packages ".packages(all.available=TRUE)\n"
294
com-package-index ".ess.help(package='%s', help.type='text')\n"
295
reg-keyword "^\\([-a-zA-Z0-9._@$]+\\)[^:\n]*$"
296
reg-start "^Index:"))
297
((string-match "julia" ess-dialect)
298
(setq com-packages "_ess_list_categories()\n"
299
com-package-index "_ess_print_index(\"%s\")\n"
300
reg-keyword "^\\(.*+\\):$*"
301
reg-start ":"
302
))
303
(t (error "Sorry, not implemented for %s " ess-dialect)))
304
305
(when (and com-package-for-object
306
ess-help-object
307
(eq ess-help-type 'help))
308
(setq pack (car (ess-get-words-from-vector
309
(format com-package-for-object ess-help-object)))))
310
311
(setq all-packs (ess-get-words-from-vector com-packages))
312
(unless pack ;try symbol at point
313
(setq pack (car (member (ess-read-object-name-default) all-packs))))
314
(setq pack (ess-completing-read "Index of"
315
all-packs nil nil nil nil pack))
316
;; (setq buff (get-buffer-create (format "*help[%s](index:%s)*" ess-dialect pack)))
317
318
319
(ess--display-indexed-help-page
320
(format com-package-index pack)
321
reg-keyword
322
(format "*help[%s](index:%s)*" ess-dialect pack)
323
'index nil nil reg-start pack)
324
))
325
326
327
(defalias 'ess-display-index 'ess-display-package-index)
328
(make-obsolete 'ess-display-index 'ess-display-package-index "ESS[12.09]")
329
330
(defun ess--display-indexed-help-page (command item-regexp title help-type
331
&optional action help-echo reg-start help-object)
332
"Internal function to display help pages with linked actions
333
;; COMMAND to produce the indexed help page
334
;; ITEM-REGEXP -- first subexpression is highlighted
335
;; TITLE of the help page
336
;; HELP-TYPE to be stored in `ess-help-type' local variable
337
;; ACTION is a function with no argument (default is `ess--action-help-on-object')
338
;; HELP-ECHO
339
;; REG-START gives the start location from where to search linkifying"
340
(interactive)
341
(let ((object (buffer-name))
342
(alist ess-local-customize-alist)
343
(pname ess-local-process-name)
344
(buff (get-buffer-create title))
345
)
346
(with-current-buffer buff
347
(setq ess-help-object help-object)
348
(ess-setq-vars-local (eval alist))
349
(setq ess-help-sec-regex "\\(^\\s-.*\n\\)\\|\\(^\n\\)"
350
ess-local-process-name pname)
351
(setq buffer-read-only nil)
352
(delete-region (point-min) (point-max))
353
(ess-help-mode)
354
(ess-command command buff)
355
(ess-help-underline)
356
(set-buffer-modified-p 'nil)
357
(goto-char (point-min))
358
(when reg-start ;; go to the beginning of listing
359
(re-search-forward reg-start nil t))
360
(when (and item-regexp (featurep 'emacs))
361
;;linkify the buffer
362
(save-excursion
363
(while (re-search-forward item-regexp nil t)
364
(make-text-button (match-beginning 1) (match-end 1)
365
'mouse-face 'highlight
366
'action (or action #'ess--action-help-on-object)
367
'help-object (buffer-substring-no-properties (match-beginning 1) (match-end 1))
368
'follow-link t
369
'help-echo (or help-echo "help on object")))
370
))
371
372
;; (save-excursion ;; why R places all these spaces?
373
;; (goto-char (point-min))
374
;; (while (re-search-forward " \\{10,\\} *" nil t)
375
;; (replace-match "\t\t\t")))
376
(setq buffer-read-only t)
377
(setq ess-help-type help-type)
378
(setq truncate-lines nil)
379
)
380
(unless (ess--help-kill-bogus-buffer-maybe buff)
381
(ess--switch-to-help-buffer buff))
382
))
383
384
385
(defun ess-display-help-apropos (&optional pattern)
386
"Create an ess-apropos buffer with a *linked* list of apropos topics."
387
(interactive "sPattern: ")
388
(let (com regexp)
389
(cond ((equal ess-dialect "R")
390
(setq com "help.search('%s')\n"
391
regexp "^\\([^ \t\n:]+::[^ \t\n:]+\\)[ \t\n]+"))
392
((equal ess-dialect "julia")
393
(setq com "apropos(\"%s\")\n"
394
regexp "^\\(\\(\\w\\|\\s_\\)+\\)("))
395
(t (error "Not implemented for dialect %s" ess-dialect)))
396
397
(ess--display-indexed-help-page
398
(format com pattern) regexp
399
(format "*ess-apropos[%s](%s)*" ess-current-process-name pattern)
400
'appropos)))
401
402
(defun ess-display-demos ()
403
"Create an ess-demos buffer with a *linked* list of available demos."
404
(interactive)
405
(let (com regexp)
406
(cond ((equal ess-dialect "R")
407
(setq com "demo()\n"
408
regexp "^\\([^ \n:]+\\) +"))
409
(t (error "Not implemented for dialect %s" ess-dialect)))
410
411
(ess--display-indexed-help-page
412
com regexp
413
(format "*ess-demos[%s]*" ess-current-process-name)
414
'demos #'ess--action-demo)))
415
416
417
(defun ess--action-demo (&optional button)
418
"Provide help on object at the beginning of line.
419
It's intended to be used in R-index help pages. Load the package
420
if necessary. It is bound to RET and C-m in R-index pages."
421
(interactive)
422
(let* ((string (button-label button))
423
(command
424
(cond ((equal ess-dialect "R")
425
(format "demo('%s')\n" string))
426
(t (error "Not implemented for dialect %s" ess-dialect)))))
427
(ess-eval-linewise command)
428
(ess-switch-to-end-of-ESS)))
429
430
(defun ess-display-vignettes ()
431
"Display vignettes if available for the current dialect."
432
(interactive)
433
(cond
434
((string-match "^R" ess-dialect) (ess-R-display-vignettes))
435
(t (message "Sorry, not implemented for %s" ess-dialect))))
436
437
(defun ess-R-display-vignettes ()
438
"Display R vignettes in ess-help-like buffer."
439
(interactive)
440
(let* ((vslist (with-current-buffer (ess-command ".ess_vignettes()\n")
441
(goto-char (point-min))
442
(when (re-search-forward "(list" nil t)
443
(goto-char (match-beginning 0))
444
(ignore-errors (eval (read (current-buffer)))))))
445
(proc-name ess-current-process-name)
446
(alist ess-local-customize-alist)
447
(remote (file-remote-p default-directory))
448
(buff (get-buffer-create (format "*[%s]vignettes*" ess-dialect))))
449
(with-current-buffer buff
450
(setq buffer-read-only nil)
451
(delete-region (point-min) (point-max))
452
(ess-setq-vars-local (eval alist))
453
(setq ess-help-sec-regex "^\\w+:$"
454
ess-help-type 'vignettes
455
ess-local-process-name proc-name)
456
(ess-help-mode)
457
(set-buffer-modified-p 'nil)
458
(goto-char (point-min))
459
(dolist (el vslist)
460
(let ((pack (car el)))
461
(insert (format "\n\n%s:\n\n" (propertize pack 'face 'underline)))
462
(dolist (el2 (cdr el))
463
(let ((path (if remote
464
(with-parsed-tramp-file-name default-directory nil
465
(tramp-make-tramp-file-name method user host (nth 1 el2)))
466
(nth 1 el2))))
467
;; (if xemacs-p
468
;; (insert (format "Dir: %s \t%s\n" (concat path "/doc/") (nth 2 el2)))
469
(insert-text-button "Pdf"
470
'mouse-face 'highlight
471
'action (if remote
472
#'ess--action-open-in-emacs
473
#'ess--action-R-open-vignette)
474
'follow-link t
475
'vignette (file-name-sans-extension (nth 2 el2))
476
'package pack
477
'help-echo (concat path "/doc/" (nth 2 el2)))
478
(insert " ")
479
(insert-text-button "Rnw"
480
'mouse-face 'highlight
481
'action #'ess--action-open-in-emacs
482
'follow-link t
483
'help-echo (concat path "/doc/" (nth 3 el2)))
484
(insert " ")
485
(insert-text-button "R"
486
'mouse-face 'highlight
487
'action #'ess--action-open-in-emacs
488
'follow-link t
489
'help-echo (concat path "/doc/" (nth 4 el2)))
490
(insert (format "\t%s\n" (nth 0 el2)))
491
))))
492
(goto-char (point-min))
493
(insert (propertize "\t\t**** Vignettes ****\n" 'face 'bold-italic))
494
(unless (eobp) (delete-char 1))
495
(setq buffer-read-only t))
496
(ess--switch-to-help-buffer buff)
497
))
498
499
(defun ess--action-open-in-emacs (pos)
500
(display-buffer (find-file-noselect (get-text-property pos 'help-echo))))
501
(defun ess--action-R-open-vignette (pos)
502
(ess-command (format "vignette('%s', package='%s')\n"
503
(get-text-property pos 'vignette)
504
(get-text-property pos 'package))))
505
506
(defun ess-help-quit (&optional kill)
507
"Quit help."
508
;;VS: `quit-window', doesn't focus previously selected buffer, which is annoying
509
(interactive "P")
510
(let* ((buffer (window-buffer))
511
(obuffer (other-buffer buffer t)))
512
(bury-buffer)
513
(pop-to-buffer obuffer)
514
(if kill
515
(kill-buffer buffer))))
516
517
(defun ess-help-kill ()
518
"Quit and kill the help buffer"
519
(interactive)
520
(ess-help-quit t))
521
522
(defun ess--find-displayed-help-window ()
523
(catch 'win
524
(dolist (f (frame-list))
525
(when (frame-visible-p f)
526
(dolist (w (window-list f))
527
(when (eq (buffer-local-value 'major-mode (window-buffer w))
528
'ess-help-mode)
529
(throw 'win w)))))))
530
531
(defun ess--switch-to-help-buffer (buff &optional curr-major-mode)
532
"Switch to help buffer and take into account `ess-help-own-frame'.
533
For internal use. Used in `ess-display-help-on-object',
534
`ess-display-package-index', and `ess-display-vignettes'.
535
CURR-MAJOR-MODE default to current major mode.
536
"
537
(setq curr-major-mode (or curr-major-mode major-mode))
538
(let ((special-display-regexps (if ess-help-own-frame '(".") nil))
539
(special-display-frame-alist ess-help-frame-alist)
540
(special-display-function (if (eq ess-help-own-frame 'one)
541
'ess-help-own-frame
542
special-display-function))
543
(help-win (or (and (eq curr-major-mode 'ess-help-mode)
544
(selected-window))
545
(and ess-help-reuse-window
546
(ess--find-displayed-help-window)))))
547
(if help-win
548
(progn
549
(select-window help-win 'norecord)
550
(set-window-buffer help-win buff)
551
;; (switch-to-buffer buff nil 'force) <- 3rd argument appeared in emacs 24
552
)
553
(if ess-help-pop-to-buffer
554
(pop-to-buffer buff)
555
(ess-display-temp-buffer buff)))))
556
557
(defvar ess-help-frame nil
558
"Stores the frame used for displaying R help buffers.")
559
560
(defun ess-help-own-frame (buffer &rest ignore)
561
"Put all ESS help buffers into `ess-help-frame'."
562
;; SJE: Code adapted from Kevin Rodgers.
563
(if (frame-live-p ess-help-frame)
564
(progn
565
(or (frame-visible-p ess-help-frame)
566
(make-frame-visible ess-help-frame))
567
(raise-frame ess-help-frame)
568
(select-frame ess-help-frame)
569
(switch-to-buffer buffer)
570
(selected-window))
571
;; else
572
(let ((window (special-display-popup-frame buffer)))
573
(set-window-dedicated-p window nil)
574
(setq ess-help-frame (window-frame window))
575
window)))
576
577
578
(defun ess-help-web-search ()
579
"Search the web for documentation"
580
(interactive)
581
(ess-execute-dialect-specific ess-help-web-search-command "Search for: "))
582
583
(defun ess-manual-lookup ()
584
"Search manual for topic"
585
(interactive)
586
(ess-execute-dialect-specific ess-manual-lookup-command ))
587
588
(defun ess-reference-lookup ()
589
"Search manual for topic"
590
(interactive)
591
(ess-execute-dialect-specific ess-reference-lookup-command))
592
593
(defvar ess-help-sec-map nil "Sub-keymap for ESS help mode.")
594
;; this breaks "s ?" rather than to fix any (unbroken !) thing:
595
;; (make-variable-buffer-local 'ess-help-sec-map)
596
597
(defvar ess-doc-map
598
(let (ess-doc-map)
599
(define-prefix-command 'ess-doc-map)
600
(define-key ess-doc-map "\C-e" 'ess-describe-object-at-point)
601
(define-key ess-doc-map "e" 'ess-describe-object-at-point)
602
(define-key ess-doc-map "\C-d" 'ess-display-help-on-object)
603
(define-key ess-doc-map "d" 'ess-display-help-on-object)
604
(define-key ess-doc-map "\C-i" 'ess-display-package-index)
605
(define-key ess-doc-map "i" 'ess-display-package-index)
606
(define-key ess-doc-map "\C-a" 'ess-display-help-apropos)
607
(define-key ess-doc-map "a" 'ess-display-help-apropos)
608
(define-key ess-doc-map "\C-v" 'ess-display-vignettes)
609
(define-key ess-doc-map "v" 'ess-display-vignettes)
610
(define-key ess-doc-map "\C-o" 'ess-display-demos)
611
(define-key ess-doc-map "o" 'ess-display-demos)
612
(define-key ess-doc-map "\C-w" 'ess-help-web-search)
613
(define-key ess-doc-map "w" 'ess-help-web-search)
614
(define-key ess-doc-map "\C-m" 'ess-manual-lookup)
615
(define-key ess-doc-map "m" 'ess-manual-lookup)
616
(define-key ess-doc-map "\C-r" 'ess-reference-lookup)
617
(define-key ess-doc-map "r" 'ess-reference-lookup)
618
ess-doc-map
619
)
620
"ESS documentation map.")
621
622
623
(defvar ess-help-mode-map
624
(let ((map (make-keymap))); Full keymap, in order to
625
(suppress-keymap map) ; suppress all usual "printing" characters
626
(when (boundp 'special-mode-map)
627
(set-keymap-parent map special-mode-map))
628
(define-key map "q" 'ess-help-quit) ;was 'ess-switch-to-end-of-ESS)
629
(define-key map "\C-m" 'next-line)
630
;; (define-key map "s" ess-help-sec-map)
631
(define-key map "h" 'ess-display-help-on-object)
632
(define-key map "w" 'ess-display-help-in-browser)
633
(define-key map "i" 'ess-display-package-index)
634
(define-key map "a" 'ess-display-help-apropos)
635
(define-key map "v" 'ess-display-vignettes)
636
;; TODO: `electric mouse-2'
637
;; (define-key map [mouse-2] 'ess-display-help-on-object)
638
(define-key map "l" 'ess-eval-line-and-step)
639
(define-key map "r" 'ess-eval-region-and-go)
640
(define-key map "f" 'ess-eval-function-or-paragraph-and-step)
641
(define-key map "n" 'ess-skip-to-next-section)
642
(define-key map "p" 'ess-skip-to-previous-section)
643
(define-key map "/" 'isearch-forward)
644
(define-key map "x" 'ess-kill-buffer-and-go)
645
(define-key map "k" 'kill-this-buffer)
646
(define-key map "?" 'ess-describe-help-mode)
647
;;-- those should be "inherited" from ess-mode-map ( ./ess-mode.el )
648
(define-key map "\C-ch" 'ess-handy-commands)
649
(define-key map "\C-c\C-s" 'ess-switch-process)
650
(define-key map "\C-c\C-r" 'ess-eval-region)
651
(define-key map "\C-c\M-r" 'ess-eval-region-and-go)
652
(define-key map "\C-c\C-f" 'ess-eval-function)
653
(define-key map "\M-\C-x" 'ess-eval-function)
654
(define-key map "\C-c\M-f" 'ess-eval-function-and-go)
655
(define-key map "\C-c\C-j" 'ess-eval-line)
656
(define-key map "\C-c\C-n" 'ess-eval-line-and-step)
657
(define-key map "\C-c\C-c" 'ess-eval-region-or-function-or-paragraph-and-step)
658
(define-key map [(control return)] 'ess-eval-region-or-line-and-step)
659
(define-key map "\C-c\M-j" 'ess-eval-line-and-go)
660
(define-key map "\M-\C-a" 'ess-goto-beginning-of-function-or-para)
661
(define-key map "\M-\C-e" 'ess-goto-end-of-function-or-para)
662
(define-key map "\C-c\C-y" 'ess-switch-to-ESS)
663
(define-key map "\C-c\C-z" 'ess-switch-to-end-of-ESS)
664
(define-key map "\C-c\C-l" 'ess-load-file)
665
(define-key map "\C-c\M-l" 'ess-load-file); alias, as in 'iESS' where C-c C-l is comint-list-*
666
(define-key map "\C-c\C-v" 'ess-display-help-on-object)
667
(define-key map "\C-c\C-k" 'ess-request-a-process)
668
669
(define-key map "\C-c\C-d" 'ess-doc-map)
670
(define-key map "\C-c\C-e" 'ess-extra-map)
671
(define-key map "\C-c\C-t" 'ess-dev-map)
672
map)
673
"Keymap for ESS help mode.")
674
675
;; One reason for the following menu is to <TEACH> the user about key strokes
676
(defvar ess-help-mode-menu
677
(list "ESS-help"
678
["Search Forward" isearch-forward t]
679
["Next Section" ess-skip-to-next-section t]
680
["Previous Section" ess-skip-to-previous-section t]
681
["Help on Section Skipping" ess-describe-sec-map t]
682
["Beginning of Buffer" beginning-of-buffer t]
683
["End of Buffer" end-of-buffer t]
684
"-"
685
["Help on ..." ess-display-help-on-object t]
686
["Apropos of ..." ess-display-help-apropos t]
687
["Index of ..." ess-display-package-index t]
688
["Vignettes" ess-display-vignettes t]
689
["Open in Browser" ess-display-help-in-browser t]
690
"-"
691
["Eval Line" ess-eval-line-and-step t]
692
["Eval Paragraph & step" ess-eval-paragraph-and-step t]
693
["Eval Region & Go" ess-eval-region-and-go t]
694
["Switch to ESS Process" ess-switch-to-ESS t]
695
["Switch to End of ESS Proc." ess-switch-to-end-of-ESS t]
696
["Switch _the_ Process" ess-switch-process t]
697
"-"
698
["Kill Buffer" kill-this-buffer t]
699
["Kill Buffer & Go" ess-kill-buffer-and-go t]
700
"-"
701
["Handy commands" ess-handy-commands t]
702
["Describe ESS-help Mode" ess-describe-help-mode t]
703
)
704
"Menu used in ess-help mode.")
705
706
(defun ess-help-mode ()
707
;;; Largely ripped from more-mode.el,
708
;;; originally by Wolfgang Rupprecht [email protected]
709
"Mode for viewing ESS help files.
710
Use SPC and DEL to page back and forth through the file.
711
Use `n' and `p' to move to next and previous section,
712
`s' to jump to a particular section; `s ?' for help.
713
Use `q' to return to your ESS session; `x' to kill this buffer first.
714
The usual commands for evaluating ESS source are available.
715
Other keybindings are as follows:
716
\\{ess-help-mode-map}"
717
(interactive)
718
(setq major-mode 'ess-help-mode)
719
(setq mode-name "ESS Help")
720
(use-local-map ess-help-mode-map)
721
722
;;; Keep <tabs> out of the code.
723
(make-local-variable 'indent-tabs-mode)
724
(setq indent-tabs-mode nil)
725
726
(if ess-mode-syntax-table ;;set in advance by ess-setq-local
727
(set-syntax-table ess-mode-syntax-table))
728
729
(require 'easymenu)
730
(easy-menu-define ess-help-mode-menu-map ess-help-mode-map
731
"Menu keymap for ess-help mode." ess-help-mode-menu)
732
(easy-menu-add ess-help-mode-menu-map ess-help-mode-map)
733
734
;; Add the keys for navigating among sections; this is done
735
;; dynamically since different languages (e.g. S vs R) have different
736
;; section headings.
737
738
(setq ess-help-sec-map (make-sparse-keymap))
739
(dolist (pair ess-help-sec-keys-alist)
740
(define-key ess-help-sec-map (char-to-string (car pair))
741
'ess-skip-to-help-section))
742
(define-key ess-help-sec-map "?" 'ess-describe-sec-map)
743
(define-key ess-help-sec-map ">" 'end-of-buffer)
744
(define-key ess-help-sec-map "<" 'beginning-of-buffer)
745
(define-key ess-help-mode-map "s" ess-help-sec-map)
746
747
(run-hooks 'ess-help-mode-hook))
748
749
;;*;; User commands defined in ESS help mode
750
751
(defun ess-skip-to-help-section nil
752
"Jump to a section heading of a help buffer. The section selected
753
is determined by the command letter used to invoke the command, as
754
indicated by `ess-help-sec-keys-alist'. Use \\[ess-describe-sec-map]
755
to see which keystrokes find which sections."
756
(interactive)
757
(let ((old-point (point))
758
(case-fold-search nil))
759
(goto-char (point-min))
760
(let ((the-sec (cdr (assoc (if (featurep 'xemacs) last-command-char last-command-event)
761
ess-help-sec-keys-alist))))
762
(if (not the-sec) (error "Invalid section key: %c"
763
last-command-event)
764
(if (re-search-forward (concat "^" the-sec) nil t)
765
(recenter)
766
(message "No %s section in this help. Sorry." the-sec)
767
(goto-char old-point))))))
768
769
(defun ess-skip-to-next-section nil
770
"Jump to next section in ESS help buffer."
771
(interactive)
772
(let ((case-fold-search nil))
773
(if (re-search-forward ess-help-sec-regex nil 'no-error) nil
774
(message "No more sections."))))
775
776
(defun ess-skip-to-previous-section nil
777
"Jump to previous section in ESS help buffer."
778
(interactive)
779
(let ((case-fold-search nil))
780
(if (re-search-backward ess-help-sec-regex nil 'no-error) nil
781
(message "No previous section."))))
782
783
(defun ess-describe-help-mode nil
784
"Display help for `ess-mode'."
785
(interactive)
786
(describe-function 'ess-help-mode))
787
788
(defun ess-kill-buffer-and-go nil
789
"Kill the current buffer and switch back to the ESS process."
790
(interactive)
791
(kill-buffer (current-buffer))
792
(ess-switch-to-ESS nil))
793
794
(defun ess-describe-sec-map nil
795
"Display help for the `s' key."
796
(interactive)
797
(let ((keys-alist ess-help-sec-keys-alist))
798
(describe-function 'ess-skip-to-help-section)
799
800
(with-current-buffer "*Help*"
801
(setq buffer-read-only nil)
802
(goto-char (point-max))
803
(insert "\n\nCurrently defined keys are:
804
805
Keystroke Section
806
--------- -------\n")
807
(dolist (cs keys-alist)
808
(insert " "
809
(car cs)
810
" "
811
(cdr cs) "\n"))
812
(insert "\nFull list of key definitions:\n"
813
(substitute-command-keys
814
"\\{ess-help-sec-map}")))))
815
816
(defun ess-helpobjs-at-point (slist)
817
;;; Return a list (def obj fun) where OBJ is a name at point, FUN - name of
818
;;; the function call point is in. DEF is either OBJ or FUN (in that order)
819
;;; which has a a help file, i.e. it is a member of slist (string-list). nil
820
;;; otherwise
821
(let ((obj (ess-read-object-name-default))
822
(fun (condition-case ()
823
(save-excursion
824
(save-restriction
825
(narrow-to-region (max (point-min) (- (point) 1000))
826
(point-max))
827
(backward-up-list 1)
828
(backward-char 1)
829
(ess-read-object-name-default)))
830
(error nil))))
831
(if (and obj (not (string-match "[[:alpha:]]" obj))) ;;exclude numbers
832
(setq obj nil))
833
(list (or (car (member obj slist))
834
(car (member fun slist)))
835
obj fun)))
836
837
;; defunct old name:
838
;; (defun ess-read-helpobj-name-default (slist)
839
;; (car (delq nil (ess-helpobjs-at-point slist))))
840
841
(defun ess-find-help-file (p-string)
842
"Find help, prompting for P-STRING. Note that we can't search SAS,
843
Stata or XLispStat for additional information."
844
(ess-make-buffer-current)
845
(if ess-get-help-topics-function
846
(let* ((help-files-list (funcall ess-get-help-topics-function ess-current-process-name))
847
(hlpobjs (ess-helpobjs-at-point help-files-list)))
848
(ess-completing-read p-string (append (delq nil hlpobjs) help-files-list)
849
nil nil nil nil (car hlpobjs)))
850
;; (string-match "\\(XLS\\)\\|\\(STA\\)\\|\\(SAS\\)" ess-language)
851
(read-string (format "%s: " p-string))))
852
853
;;*;; Utility functions
854
855
(defun ess-get-S-help-topics-function (name)
856
"Return a list of current S help topics associated with process NAME.
857
If 'sp-for-help-changed?' process variable is non-nil or
858
`ess-help-topics-list' is nil, (re)-populate the latter and
859
return it. Otherwise, return `ess-help-topics-list'."
860
(with-ess-process-buffer nil
861
(ess-write-to-dribble-buffer
862
(format "(ess-get-help-topics-list %s) .." name))
863
(if (or (not ess-help-topics-list)
864
(ess-process-get 'sp-for-help-changed?))
865
(progn
866
(ess-process-put 'sp-for-help-changed? nil)
867
(setq ess-help-topics-list
868
(ess-uniq-list
869
(append (ess-get-object-list name 'exclude-1st)
870
(ess-get-help-files-list)
871
(ess-get-help-aliases-list)
872
))))
873
;; else return the existing list
874
ess-help-topics-list)))
875
876
(defun ess-get-help-files-list ()
877
"Return a list of files which have help available."
878
(apply 'nconc
879
(mapcar (lambda (str)
880
(let ((dirname (concat str "/.Help")))
881
(and (file-directory-p dirname)
882
(directory-files dirname))))
883
(ess-search-list))))
884
885
(defun ess-get-help-aliases-list ()
886
"Return a list of aliases which have help available."
887
(ess-write-to-dribble-buffer "Processing RDS files ...\n")
888
(ess-get-words-from-vector ".ess.getHelpAliases()\n"))
889
890
(defun ess-nuke-help-bs ()
891
"Remove ASCII underlining and overstriking performed by ^H codes."
892
;; This function is a modification of nuke-nroff-bs in man.el from the
893
;; standard emacs 18 lisp library.
894
;; Nuke underlining and overstriking (only by the same letter)
895
(goto-char (point-min))
896
(while (search-forward "\b" nil t)
897
(let* ((preceding (char-after (- (point) 2)))
898
(following (following-char)))
899
(cond ((= preceding following)
900
;; x\bx
901
(delete-char -2))
902
((= preceding ?\_)
903
;; _\b
904
(delete-char -2))
905
((= following ?\_)
906
;; \b_
907
(delete-region (1- (point)) (1+ (point)))))))
908
(goto-char (point-min))
909
(while (re-search-forward "URL:" nil t)
910
;; quick fix for C-x f confusiong
911
(delete-region (match-beginning 0) (match-end 0)))
912
;; Crunch blank lines
913
(goto-char (point-min))
914
(while (re-search-forward "\n\n\n\n*" nil t)
915
(replace-match "\n\n"))
916
;; Nuke blanks lines at start.
917
(goto-char (point-min))
918
(skip-chars-forward "\n")
919
(delete-region (point-min) (point)))
920
921
(defun ess-help-underline ()
922
"Replace _^H codes with underline face."
923
(save-excursion
924
(goto-char (point-min))
925
(while (search-forward "_" nil t)
926
(backward-delete-char 2)
927
(put-text-property (point) (1+ (point)) 'face 'underline))))
928
929
;;*;; Link to Info
930
931
(defun ess-goto-info (node)
932
"Display node NODE from ess-mode info."
933
(require 'info)
934
(split-window)
935
;;(other-window 1)
936
(Info-goto-node (concat "(ess)" node)))
937
938
939
;; describe object at point
940
941
(defvar ess-describe-object-at-point-commands nil
942
"Commands cycled by `ess-describe-object-at-point'. Dialect
943
specific.")
944
(make-variable-buffer-local 'ess-describe-at-point-commands)
945
946
(defvar ess--descr-o-a-p-commands nil)
947
948
(defun ess-describe-object-at-point ()
949
"Get info for object at point, and display it in an electric buffer or tooltip.
950
If region is active use it instead of the object at point.
951
952
This is an electric command (`ess--execute-electric-command'),
953
which means that you can use the last key to cycle through the
954
action set (in this case `C-e').
955
956
After invocation of this command all standard emacs commands,
957
except those containing 'window' in their names, remove the
958
electric *ess-describe* buffer. Use `other-window' to switch to
959
*ess-describe* window.
960
961
Customize `ess-describe-at-point-method' if you wan to display
962
the description in a tooltip.
963
964
See also `ess-R-describe-object-at-point-commands' (and similar
965
option for other dialects)."
966
(interactive)
967
(if (not ess-describe-object-at-point-commands)
968
(message "Not implemented for dialect %s" ess-dialect)
969
(ess-force-buffer-current)
970
(let ((map (make-sparse-keymap))
971
(objname (or (and (use-region-p)
972
(buffer-substring-no-properties (point) (mark)))
973
(symbol-at-point)))
974
bs ess--descr-o-a-p-commands) ;; used in ess--describe-object-at-point
975
(unless objname (error "No object at point "))
976
(define-key map (vector last-command-event) 'ess--describe-object-at-point)
977
;; todo: put digits into the map
978
(let* ((inhibit-quit t) ;; C-g removes the buffer
979
(buf (ess--execute-electric-command
980
map (format "Press %s to cycle"
981
(single-key-description last-command-event))
982
nil nil objname))
983
;; read full command
984
(keys (read-key-sequence-vector ""))
985
(command (and keys (key-binding keys))))
986
(when (and (commandp command)
987
(bufferp buf)
988
(or (not (symbolp command)) ;; kill on lambdas
989
(not (string-match "window" (symbol-name command)))))
990
(kill-buffer buf)) ;; bury does not work here :( (emacs bug?)
991
(setq unread-command-events
992
(append keys unread-command-events)))
993
)))
994
995
(defun ess--describe-object-at-point (ev objname)
996
(setq ess--descr-o-a-p-commands (or ess--descr-o-a-p-commands
997
(symbol-value ess-describe-object-at-point-commands)))
998
(let* ((com (format (car (pop ess--descr-o-a-p-commands)) objname))
999
(buf (get-buffer-create "*ess-describe*"))
1000
pos)
1001
(unless (eq ess-describe-at-point-method 'tooltip)
1002
;; can take some time for the command to execute
1003
(display-buffer buf))
1004
(sit-for .01)
1005
(ess-command (concat com "\n") buf) ;; erases buf
1006
(with-current-buffer buf
1007
(goto-char (point-min))
1008
(insert (propertize (format "%s:\n\n" com) 'face 'font-lock-string-face))
1009
(forward-line -1)
1010
(setq pos (point))
1011
;; set the keys that we are used to in help mode
1012
(special-mode)
1013
(local-set-key "k" 'kill-this-buffer))
1014
(if (eq ess-describe-at-point-method 'tooltip)
1015
(ess-tooltip-show-at-point
1016
(with-current-buffer buf (buffer-string)) 0 30)
1017
(display-buffer buf)
1018
(set-window-point (get-buffer-window buf) pos) ;; don't move window point
1019
buf)))
1020
1021
1022
; Bug Reporting
1023
1024
(defun ess-submit-bug-report ()
1025
"Submit a bug report on the ess-mode package."
1026
(interactive)
1027
(require 'ess-mode)
1028
(require 'reporter)
1029
(let ((reporter-prompt-for-summary-p 't))
1030
(reporter-submit-bug-report
1031
"[email protected]"
1032
(concat "ess-mode " (ess-version-string))
1033
(list 'ess-language
1034
'ess-dialect
1035
'ess-ask-for-ess-directory
1036
'ess-ask-about-transfile
1037
'ess-directory
1038
'ess-keep-dump-files
1039
'ess-source-directory
1040
'ess-use-ido
1041
'ess-use-eldoc
1042
'ess-use-tracebug
1043
'ess-use-auto-complete
1044
'ess-eval-visibly-p
1045
'ess-can-eval-in-background
1046
'ess-local-process-name)
1047
nil
1048
(lambda ()
1049
;;(goto-char (point-max))
1050
(rfc822-goto-eoh)
1051
(forward-line 1)
1052
(insert "\n\n-------------------------------------------------------\n")
1053
(insert "This bug report will be sent to the ESS bugs email list\n")
1054
(insert "Press C-c C-c when you are ready to send your message.\n")
1055
(insert "-------------------------------------------------------\n\n")
1056
(insert (with-current-buffer "*ESS*"
1057
(goto-char (point-max))
1058
(forward-line -100)
1059
(buffer-substring-no-properties (point) (point-max))))
1060
))))
1061
1062
1063
1064
;;; Provide
1065
1066
(provide 'ess-help)
1067
1068
; Local variables section
1069
1070
;;; This file is automatically placed in Outline minor mode.
1071
;;; The file is structured as follows:
1072
;;; Chapters: ^L ;
1073
;;; Sections: ;;*;;
1074
;;; Subsections: ;;;*;;;
1075
;;; Components: defuns, defvars, defconsts
1076
;;; Random code beginning with a ;;;;* comment
1077
1078
;;; Local variables:
1079
;;; mode: emacs-lisp
1080
;;; mode: outline-minor
1081
;;; outline-regexp: "\^L\\|\\`;\\|;;\\*\\|;;;\\*\\|(def[cvu]\\|(setq\\|;;;;\\*"
1082
;;; End:
1083
1084
;;; ess-help.el ends here
1085
1086