version 0.68
[sepia.git] / sepia.el
blob87eec3e382fc9da94a9cfb47893ff97d9e49ab5e
1 ;;; Sepia -- Simple Emacs-Perl InterAction: ugly, yet effective.
2 ;;; (a.k.a. Septik -- Sean's Emacs-Perl Total Integration Kludge.)
4 ;; Copyright (C) 2004-2007 Sean O'Rourke. All rights reserved, some
5 ;; wrongs reversed. This code is distributed under the same terms as
6 ;; Perl itself.
8 ;;; Commentary:
10 ;; See the README file that comes with the distribution.
12 ;;; Code:
14 (require 'cperl-mode)
15 (require 'comint)
16 (require 'cl)
17 ;; try optional modules, but don't bitch if we fail:
18 (require 'sepia-w3m nil t)
19 (require 'sepia-tree nil t)
20 (require 'sepia-ido nil t)
22 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
23 ;;; Comint communication
25 (defvar sepia-perl5lib nil
26 "* Extra PERL5LIB directory for Sepia.pm")
28 (defvar sepia-program-name "perl"
29 "* Perl program name.")
31 (defvar sepia-process nil
32 "The perl process with which we're interacting.")
33 (defvar sepia-output nil
34 "Current perl output for a response to `sepia-eval-raw', appended
35 to by `perl-collect-output'.")
36 (defvar sepia-passive-output ""
37 "Current perl output for miscellaneous user interaction, used to
38 look for \";;;###\" lisp evaluation markers.")
40 (defun sepia-collect-output (string)
41 "Collect perl output for `sepia-eval-raw' into sepia-output."
42 (setq sepia-output (concat sepia-output string))
43 "")
45 (defun sepia-eval-raw (str)
46 "Evaluate perl code STR, returning a pair (RESULT-STRING . OUTPUT)."
47 (let (ocpof)
48 (unwind-protect
49 (let ((sepia-output "")
50 (start 0))
51 (with-current-buffer (process-buffer sepia-process)
52 (setq ocpof comint-preoutput-filter-functions
53 comint-preoutput-filter-functions '(sepia-collect-output)))
54 (setq str (concat "local $Sepia::stopdie=0;"
55 "local $Sepia::stopwarn=0;"
56 "{ package " (sepia-buffer-package) ";"
57 str " }\n"))
58 (comint-send-string sepia-process
59 (concat (format "<<%d\n" (length str)) str))
60 (while (not (and sepia-output
61 (string-match "> $" sepia-output)))
62 (accept-process-output sepia-process))
63 (if (string-match "^;;;[0-9]+\n" sepia-output)
64 (cons
65 (let* ((x (read-from-string sepia-output
66 (+ (match-beginning 0) 3)))
67 (len (car x))
68 (pos (cdr x)))
69 (prog1 (substring sepia-output (1+ pos) (+ len pos 1))
70 (setq start (+ pos len 1))))
71 (and (string-match ";;;[0-9]+\n" sepia-output start)
72 (let* ((x (read-from-string
73 sepia-output
74 (+ (match-beginning 0) 3)))
75 (len (car x))
76 (pos (cdr x)))
77 (substring sepia-output (1+ pos) (+ len pos 1)))))
78 (cons sepia-output nil)))
79 (with-current-buffer (process-buffer sepia-process)
80 (setq comint-preoutput-filter-functions ocpof)))))
82 (defun sepia-eval (str &optional context detailed)
83 "Evaluate STR in CONTEXT (void by default), and return its result
84 as a Lisp object. If DETAILED is specified, return a
85 pair (RESULT . OUTPUT)."
86 (let* ((tmp (sepia-eval-raw
87 (case context
88 (list-context
89 (concat "Sepia::tolisp([" str "])"))
90 (scalar-context
91 (concat "Sepia::tolisp(scalar(" str "))"))
92 (t (concat str ";1")))))
93 (res (car tmp))
94 (errs (cdr tmp)))
95 (setq res (if context (car (read-from-string res)) 1))
96 (if detailed
97 (cons res errs)
98 res)))
100 (defun sepia-call (fn context &rest args)
101 "Call perl function FN in CONTEXT with arguments ARGS, returning
102 its result as a Lisp value."
103 (sepia-eval (concat fn "(" (mapconcat #'sepia-lisp-to-perl args ", ") ")")
104 context))
106 (defun sepia-watch-for-eval (string)
107 "Monitor inferior Perl output looking for Lisp evaluation
108 requests. The format for these requests is
109 \"\\n;;;###LENGTH\\nDATA\". Only one such request can come from
110 each inferior Perl prompt."
111 (setq sepia-passive-output (concat sepia-passive-output string))
112 (cond
113 ((string-match "^;;;###[0-9]+" sepia-passive-output)
114 (when (string-match "^;;;###\\([0-9]+\\)\n\\(?:.\\|\n\\)*\\(\n.*> \\)"
115 sepia-passive-output)
116 (let* ((len (car (read-from-string
117 (match-string 1 sepia-passive-output))))
118 (pos (1+ (match-end 1)))
119 (res (ignore-errors (eval (car (read-from-string
120 sepia-passive-output pos
121 (+ pos len)))))))
122 (insert (format "%s => %s\n"
123 (substring sepia-passive-output pos (+ pos len)) res))
124 (goto-char (point-max))
125 (comint-set-process-mark)
126 (sepia-eval "''" 'scalar-context)
127 (message "%s => %s" (substring sepia-passive-output pos (+ pos len))
128 res)
129 (setq sepia-passive-output "")))
131 (t (setq sepia-passive-output "") string)))
133 (defun sepia-comint-setup ()
134 "Set up the inferior Perl process buffer."
135 (comint-mode)
136 (set (make-local-variable 'comint-dynamic-complete-functions)
137 '(sepia-complete-symbol comint-dynamic-complete-filename))
138 (set (make-local-variable 'comint-preoutput-filter-functions)
139 '(sepia-watch-for-eval))
140 (set (make-local-variable 'comint-use-prompt-regexp) t)
141 (modify-syntax-entry ?: "_")
142 (modify-syntax-entry ?> ".")
143 (use-local-map (copy-keymap (current-local-map)))
144 (sepia-install-keys)
145 (local-set-key (kbd "TAB") 'comint-dynamic-complete)
146 (local-set-key "\C-a" 'comint-bol)
147 (set (make-local-variable 'comint-prompt-regexp)
148 "^[^>\n]*> *")
151 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
152 ;;; Keymaps, user variables, setup.
154 (defvar sepia-use-completion t
155 "* Use completion based on Xref database. Turning this off may
156 speed up some operations, if you don't mind losing completion.")
158 (defvar sepia-eval-defun-include-decls t
159 "* Generate and use a declaration list for ``sepia-eval-defun''.
160 Without this, code often will not parse; with it, evaluation may
161 be a bit less responsive. Note that since this only includes
162 subs from the evaluation package, it may not always work.")
164 (defvar sepia-prefix-key "\M-."
165 "* Prefix for functions in ``sepia-keymap''.")
167 (defvar sepia-keymap
168 (eval-when (load eval)
169 (let ((km (make-sparse-keymap)))
170 (dolist (kv '(("c" . sepia-callers)
171 ("C" . sepia-callees)
172 ("a" . sepia-apropos)
173 ("A" . sepia-var-apropos)
174 ("v" . sepia-var-uses)
175 ("V" . sepia-var-defs)
176 ;; ("V" . sepia-var-assigns)
177 ;; ("\M-." . sepia-dwim)
178 ("\M-." . sepia-location)
179 ("f" . sepia-defs)
180 ("r" . sepia-rebuild)
181 ("m" . sepia-module-find)
182 ("n" . sepia-next)
183 ("t" . find-tag)))
184 (define-key km (car kv) (cdr kv)))
185 (when (featurep 'sepia-w3m)
186 (define-key km "d" 'sepia-w3m-perldoc-this))
187 (when (featurep 'sepia-ido)
188 (define-key km "j" 'sepia-jump-to-symbol))
189 km))
190 "Keymap for Sepia functions. This is just an example of how you
191 might want to bind your keys, which works best when bound to
192 `\\M-.'.")
194 (defun sepia-install-keys (&optional map)
195 "Install Sepia bindings in the current local keymap."
196 (interactive)
197 (let ((map (or map (current-local-map))))
198 (define-key map sepia-prefix-key sepia-keymap)
199 (define-key map "\M-," 'sepia-next)
200 (define-key map "\C-\M-x" 'sepia-eval-defun)
201 (define-key map "\C-c\C-l" 'sepia-load-file)
202 (define-key map "\C-c\C-d" 'sepia-w3m-view-pod)
203 (define-key map (kbd "TAB") 'sepia-indent-or-complete)))
205 (defun perl-name (sym &optional mod)
206 "Convert a Perl name to a Lisp name."
207 (setq sym (substitute ?_ ?- (if (symbolp sym) (symbol-name sym) sym)))
208 (if mod
209 (concat mod "::" sym)
210 sym))
212 ;;;###autoload
213 (defun sepia-init (&optional noinit)
214 "Perform the initialization necessary to start Sepia.
216 The following keys are bound to the prefix
217 ``sepia-prefix-key'' (`\\M-.' by default), which can be changed
218 by setting ``sepia-prefix'' before calling ``sepia-init'':
220 \\{sepia-keymap}
221 In addition to these keys, Sepia defines the following keys,
222 which may conflict with keys in your setup, but which are
223 intended to shadow similar functionality in elisp-mode:
225 `\\C-c\\C-d' ``sepia-w3m-view-pod''
226 `\\C-c\\C-l' ``sepia-load-file''
227 `\\C-\\M-x' ``sepia-eval-defun''
228 `\\M-,' ``sepia-next'' (shadows ``tags-loop-continue'')
230 (interactive "P")
231 (ignore-errors
232 (kill-process "perl")
233 (setq sepia-process nil))
234 (unless noinit
235 ;; Load perl defs:
236 (setq sepia-process
237 (get-buffer-process
238 (comint-exec (get-buffer-create "*perl-interaction*")
239 "perl" sepia-program-name nil
240 (append (and sepia-perl5lib
241 (mapcar
242 (lambda (x) (concat "-I" x))
243 (split-string sepia-perl5lib ":")))
244 '("-MData::Dumper" "-MSepia" "-MSepia::Xref"
245 "-e" "Sepia::repl(*STDIN)")))))
246 (with-current-buffer "*perl-interaction*"
247 (sepia-comint-setup))
248 (accept-process-output sepia-process 0 1)
250 ;; Create glue wrappers for Module::Info funcs.
251 (dolist (x '((name "Find module name.\n\nDoes not require loading.")
252 (version "Find module version.\n\nDoes not require loading.")
253 (inc-dir
254 "Find directory in which this module was found.\n\nDoes not require loading.")
255 (file
256 "Absolute path of file defining this module.\n\nDoes not require loading.")
257 (is-core
258 "Guess whether or not a module is part of the core distribution.
259 Does not require loading.")
260 (modules-used
261 "List modules used by this module.\n\nRequires loading.")
262 (packages-inside
263 "List sub-packages in this module.\n\nRequires loading.")
264 (superclasses
265 "List module's superclasses.\n\nRequires loading.")))
266 (apply #'define-modinfo-function x))
268 ;; Create low-level wrappers for Sepia
269 (dolist (x '((completions "Find completions in the symbol table.")
270 (location "Find an identifier's location.")
271 (mod-subs "Find all subs defined in a package.")
272 (mod-decls "Generate declarations for subs in a package.")
273 (apropos "Find subnames matching RE.")
274 (lexicals "Find lexicals for a sub.")
276 (apply #'define-xref-function "Sepia" x))
278 (dolist (x '((rebuild "Build Xref database for current Perl process.")
279 (redefined "Rebuild Xref information for a given sub.")
281 (callers "Find all callers of a function.")
282 (callees "Find all functions called by a function.")
284 (var-apropos "Find varnames matching RE.")
285 (mod-apropos "Find modules matching RE.")
286 (file-apropos "Find files matching RE.")
288 (var-defs "Find all definitions of a variable.")
289 (var-assigns "Find all assignments to a variable.")
290 (var-uses "Find all uses of a variable.")
292 (mod-redefined "Rebuild Xref information for a given package.")
293 (mod-files "Find the file defining a package.")
294 (guess-module-file "Guess file corresponding to module.")
295 (file-modules "List the modules defined in a file.")))
296 (apply #'define-xref-function "Sepia::Xref" x)))
297 (add-hook 'cperl-mode-hook 'sepia-install-eldoc)
298 (add-hook 'cperl-mode-hook 'sepia-doc-update)
299 (add-hook 'cperl-mode-hook 'sepia-cperl-mode-hook)
300 (when (boundp 'cperl-mode-map)
301 (sepia-install-keys cperl-mode-map))
302 (when (boundp 'perl-mode-map)
303 (sepia-install-keys perl-mode-map))
304 (unless noinit
305 (sepia-interact)))
307 (defun sepia-cperl-mode-hook ()
308 (set (make-local-variable 'beginning-of-defun-function)
309 'sepia-beginning-of-defun)
310 (set (make-local-variable 'end-of-defun-function)
311 'sepia-end-of-defun))
313 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
314 ;;; Xref
316 (defun define-xref-function (package name doc)
317 "Define a lisp mirror for a low-level Sepia function."
318 (let ((lisp-name (intern (format "xref-%s" name)))
319 (pl-name (perl-name name package)))
320 (fmakunbound lisp-name)
321 (eval `(defun ,lisp-name (&rest args)
322 ,doc
323 (apply #'sepia-call ,pl-name 'list-context args)))))
325 (defun define-modinfo-function (name &optional doc)
326 "Define a lisp mirror for a function from Module::Info."
327 (let ((name (intern (format "sepia-module-%s" name)))
328 (pl-func (perl-name name))
329 (full-doc (concat (or doc "") "
331 This function uses Module::Info, so it does not require that the
332 module in question be loaded.")))
333 (when (fboundp name) (fmakunbound name))
334 (eval `(defun ,name (mod)
335 ,full-doc
336 (interactive (list (sepia-interactive-arg 'module)))
337 (sepia-maybe-echo
338 (sepia-call "Sepia::module_info" 'scalar-context
339 mod ,pl-func))))))
341 (defun sepia-thing-at-point (what)
342 "Like ``thing-at-point'', but hacked to avoid REPL prompt."
343 (let ((th (thing-at-point what)))
344 (and th (not (string-match "[ >]$" th)) th)))
346 (defvar sepia-sub-re "^\\s *sub\\s +\\(.+\\_>\\)")
349 (defun sepia-interactive-arg (&optional type)
350 "Default argument for most Sepia functions. TYPE is a symbol --
351 either 'file to look for a file, or anything else to use the
352 symbol at point."
353 (let* ((default (case type
354 (file (or (thing-at-point 'file) (buffer-file-name)))
355 (t (sepia-thing-at-point 'symbol))))
356 (text (capitalize (symbol-name type)))
357 (choices (lambda (str &rest blah)
358 (let ((str (concat "^" str)))
359 (case type
360 (variable (xref-var-apropos str))
361 (function (xref-apropos str))
362 (module (xref-mod-apropos str))
363 (t nil)))))
364 (ret (if sepia-use-completion
365 (completing-read (format "%s [%s]: " text default)
366 choices nil nil nil 'sepia-history
367 default)
368 (read-string (format "%s [%s]: " text default)
369 nil 'sepia-history default))))
370 (push ret sepia-history)
371 ret))
373 (defun sepia-interactive-module ()
374 "Guess which module we should look things up in. Prompting for a
375 module all the time is a PITA, but I don't think this (choosing
376 the current file's module) is a good alternative, either. Best
377 would be to choose the module based on what we know about the
378 symbol at point."
379 (let ((xs (xref-file-modules (buffer-file-name))))
380 (if (= (length xs) 1)
381 (car xs)
382 nil)))
384 (defun sepia-maybe-echo (result)
385 (when (interactive-p)
386 (message "%s" result))
387 result)
389 (defun sepia-module-find (mod)
390 "Find the file defining module MOD."
391 (interactive (list (sepia-interactive-arg 'module)))
392 (let ((fn (or (sepia-module-file mod)
393 (car (xref-guess-module-file mod)))))
394 (when fn
395 (message "Module %s in %s." mod fn)
396 (pop-to-buffer (find-file-noselect (expand-file-name fn))))))
398 (defmacro ifa (test then &rest else)
399 `(let ((it ,test))
400 (if it ,then ,@else)))
402 (defun sepia-show-locations (locs)
403 (when locs
404 (pop-to-buffer (get-buffer-create "*sepia-places*"))
405 (let ((inhibit-read-only t))
406 (erase-buffer)
407 (dolist (loc (sort (remove nil locs) ; XXX where's nil from?
408 (lambda (a b)
409 (or (string< (car a) (car b))
410 (and (string= (car a) (car b))
411 (< (second a) (second b)))))))
412 (destructuring-bind (file line name &rest blah) loc
413 (let ((str (ifa (find-buffer-visiting file)
414 (with-current-buffer it
415 (ifa sepia-found-refiner
416 (funcall it line name)
417 (goto-line line))
418 (message "line for %s was %d, now %d" name line
419 (line-number-at-pos))
420 (setq line (line-number-at-pos))
421 (let ((tmpstr
422 (buffer-substring (my-bol-from (point))
423 (my-eol-from (point)))))
424 (if (> (length tmpstr) 60)
425 (concat "\n " tmpstr)
426 tmpstr)))
427 "...")))
428 (insert (format "%s:%d:%s\n" (abbreviate-file-name file) line str)))))
429 (grep-mode)
430 (goto-char (point-min)))))
432 (defun sepia-filter-by-module (x)
433 "Filter to limit hits by module only."
434 (when (or (not module) (string= module (fourth x)))
435 (list x)))
437 (defun sepia-filter-by-all (x)
438 "Filter to limit hits by module and file."
439 (when (and (or (not module) (string= module (fourth x)))
440 (or (not file) (string= file (first x))))
441 (list x)))
443 (defmacro define-sepia-query (name doc &optional gen test prompt)
444 "Define a sepia querying function."
445 `(defun ,name (ident &optional module file line display-p)
446 ,(concat doc "
448 With prefix arg, list occurences in a ``grep-mode'' buffer.
449 Without, place the occurrences on ``sepia-found'', so that
450 calling ``sepia-next'' will cycle through them.
452 Depending on the query, MODULE, FILE, and LINE may be used to
453 narrow the results, as long as doing so leaves some matches.
454 When called interactively, they are taken from the current
455 buffer.
457 (interactive (list (sepia-interactive-arg ,(or prompt ''function))
458 (sepia-interactive-module)
459 (buffer-file-name)
460 (line-number-at-pos (point))
461 current-prefix-arg
463 (let ((ret
464 ,(if test
465 `(let ((tmp (,gen ident module file line)))
466 (or (mapcan #',test tmp) tmp))
467 `(,gen ident module file line))))
468 ;; Always clear out the last found ring, because it's confusing
469 ;; otherwise.
470 (sepia-set-found nil ',(or prompt 'function))
471 (if display-p
472 (sepia-show-locations ret)
473 (sepia-set-found ret ',(or prompt 'function))
474 (sepia-next)))))
477 (define-sepia-query sepia-defs
478 "Find all definitions of sub."
479 xref-apropos
480 xref-location)
482 (define-sepia-query sepia-callers
483 "Find callers of FUNC."
484 xref-callers
485 xref-location)
487 (define-sepia-query sepia-callees
488 "Find a sub's callees."
489 xref-callees
490 xref-location)
492 (define-sepia-query sepia-var-defs
493 "Find a var's definitions."
494 xref-var-defs
495 (lambda (x) (setf (third x) ident) (list x))
496 'variable)
498 (define-sepia-query sepia-var-uses
499 "Find a var's uses."
500 xref-var-uses
501 (lambda (x) (setf (third x) ident) (list x))
502 'variable)
504 (define-sepia-query sepia-var-assigns
505 "Find/list assignments to a variable."
506 xref-var-assigns
507 (lambda (x) (setf (third x) ident) (list x))
508 'variable)
510 (define-sepia-query sepia-module-describe
511 "Find all subroutines in a package."
512 xref-mod-subs
514 'module)
516 (defalias 'sepia-package-defs 'sepia-module-describe)
518 (define-sepia-query sepia-apropos
519 "Find/list subroutines matching regexp."
520 (lambda (name &rest blah) (xref-apropos name 1))
521 xref-location
522 'function)
524 (define-sepia-query sepia-var-apropos
525 "Find/list variables matching regexp."
526 xref-var-apropos
527 xref-var-defs
528 'variable)
530 (defun sepia-location (name &optional jump-to)
531 "Find the definition of NAME.
533 When called interactively (or with JUMP-TO true), go directly
534 to this location."
535 (interactive (list (or (thing-at-point 'symbol)
536 (completing-read "Function: " 'xref-completions))
538 (let* ((fl (or (car (xref-location name))
539 (car (remove-if #'null
540 (apply #'xref-location (xref-apropos name)))))))
541 (when (and fl (string-match "^(eval " (car fl)))
542 (message "Can't find definition of %s in %s." name (car fl))
543 (setq fl nil))
544 (if jump-to
545 (if fl (progn
546 (sepia-set-found (list fl) 'function)
547 (sepia-next))
548 (message "No definition for %s." name))
549 fl)))
551 ;;;###autoload
552 (defun sepia-dwim (&optional display-p)
553 "Try to do the right thing with identifier at point.
554 * Find all definitions, if thing-at-point is a function
555 * Find all uses, if thing-at-point is a variable
556 * Find all definitions, if thing-at-point is a module
557 * Prompt otherwise
559 (interactive "P")
560 (multiple-value-bind (type obj) (sepia-ident-at-point)
561 (setq type (if type (string type) ""))
562 (message "%s %S" type obj)
563 (if type
564 (progn
565 ;; (sepia-set-found nil 'variable)
566 (let ((ret (if type
567 (function (list (sepia-location raw)))
568 (variable (xref-var-uses raw))
569 (module `((,(car (xref-mod-files mod)) 1 nil nil))))))
570 (if display-p
571 (sepia-show-locations ret)
572 (sepia-set-found ret type)
573 (sepia-next))))
574 (call-interactively 'sepia-defs))))
576 (defun sepia-rebuild ()
577 "Rebuild the Xref database."
578 (interactive)
579 (xref-rebuild))
581 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
582 ;;; Perl motion commands.
584 ;;; XXX -- these are a hack to prevent infinite recursion calling
585 ;;; e.g. beginning-of-defun from beginning-of-defun-function.
586 ;;; `beginning-of-defun' should handle this.
587 (defmacro sepia-safe-bodf (&optional n)
588 `(let ((beginning-of-defun-function
589 (if (and (boundp 'beginning-of-defun-function)
590 (eq beginning-of-defun-function 'sepia-beginning-of-defun))
592 beginning-of-defun-function)))
593 (beginning-of-defun ,n)))
595 (defmacro sepia-safe-eodf (&optional n)
596 `(let ((end-of-defun-function
597 (if (and (boundp 'end-of-defun-function)
598 (eq end-of-defun-function 'sepia-end-of-defun))
600 end-of-defun-function)))
601 (end-of-defun ,n)))
603 (defun sepia-beginning-of-defun (&optional n)
604 "Move to beginning of current function.
606 If prefix argument given, move N functions backward."
607 (interactive "p")
608 (let ((here (point)))
609 (beginning-of-line)
610 (if (and (not (= here (point)))
611 (looking-at sepia-sub-re))
612 (point)
613 (sepia-safe-bodf n)
614 (let* ((end (point))
615 (beg (progn (forward-line -3) (point))))
616 (goto-char end)
617 (re-search-backward sepia-sub-re beg t)))))
619 (defun sepia-end-of-defun (&optional n)
620 "Move to end of current function.
622 If prefix argument given, move N functions forward."
623 (interactive "p")
624 (let ((here (point)))
625 ;; (sepia-safe-bodf)
626 (when (looking-at sepia-sub-re)
627 (forward-line 1))
628 (sepia-safe-eodf n)
629 (when (and (>= here (point))
630 (re-search-forward sepia-sub-re nil t))
631 (sepia-safe-eodf))
632 (point)))
634 (defun sepia-defun-around-point (&optional where)
635 "Return the text of function around point."
636 (interactive "d")
637 (unless where
638 (setq where (point)))
639 (save-excursion
640 (goto-char where)
641 (and (sepia-beginning-of-defun)
642 (match-string-no-properties 1))))
644 (defun sepia-lexicals-at-point (&optional where)
645 "Find lexicals in scope at point."
646 (interactive "d")
647 (unless where
648 (setq where (point)))
649 (let ((subname (sepia-defun-around-point where))
650 (mod (sepia-buffer-package)))
651 (xref-lexicals (perl-name subname mod))))
653 ;;;###autoload
654 (defun sepia-load-file (file &optional rebuild-p collect-warnings)
655 "Reload a file (interactively, the current buffer's file).
657 With REBUILD-P (or a prefix argument when called interactively),
658 also rebuild the xref database."
659 (interactive (list (expand-file-name (buffer-file-name))
660 prefix-arg
661 (format "*%s errors*" (buffer-file-name))))
662 (save-buffer)
663 (let* ((tmp (sepia-eval (format "do '%s' ? 1 : $@" file) 'scalar-context t))
664 (res (car tmp))
665 (errs (cdr tmp)))
666 (message "sepia: %s returned %s" (abbreviate-file-name file) res)
667 (when (and collect-warnings
668 (> (length errs) 1))
669 (with-current-buffer (get-buffer-create collect-warnings)
670 (delete-region (point-min) (point-max))
671 (insert errs)
672 (sepia-display-errors (point-min) (point-max))
673 (pop-to-buffer (current-buffer)))))
674 (when rebuild-p
675 (xref-rebuild)))
677 (defvar sepia-found)
678 (defvar sepia-found-head)
679 (defvar sepia-found-refiner)
680 (defvar sepia-history nil)
682 (defun sepia-set-found (list &optional type)
683 (setq list
684 (remove-if (lambda (x)
685 (or (not x)
686 (and (not (car x)) (string= (fourth x) "main"))))
687 list))
688 (setq sepia-found list
689 sepia-found-head list)
690 (setq sepia-found-refiner (sepia-refiner type)))
692 (defun sepia-refiner (type)
693 (case type
694 (function
695 (lambda (line ident)
696 (let ((sub-re (concat "^\\s *sub\\s +.*" ident "\\_>")))
697 ;; Test this because sometimes we get lucky and get the line
698 ;; just right, in which case beginning-of-defun goes to the
699 ;; previous defun.
700 (unless (looking-at sub-re)
701 (or (and line
702 (progn
703 (goto-line line)
704 (beginning-of-defun)
705 (looking-at sub-re)))
706 (progn (goto-char (point-min))
707 (re-search-forward sub-re nil t)))
708 (beginning-of-line)))))
709 ;; Old version -- this may actually work better if
710 ;; beginning-of-defun goes flaky on us.
711 ;; (or (re-search-backward sub-re
712 ;; (my-bol-from (point) -20) t)
713 ;; (re-search-forward sub-re
714 ;; (my-bol-from (point) 10) t))
715 ;; (beginning-of-line)
716 (variable
717 (lambda (line ident)
718 (let ((var-re (concat "\\_<" ident "\\_>")))
719 (cond
720 (line (goto-line line)
721 (or (re-search-backward var-re (my-bol-from (point) -5) t)
722 (re-search-forward var-re (my-bol-from (point) 5) t)))
723 (t (goto-char (point-min))
724 (re-search-forward var-re nil t))))))
725 (t (lambda (line ident) (and line (goto-line line))))))
727 (defun sepia-next ()
728 "Go to the next thing (e.g. def, use) found by sepia."
729 (interactive)
730 (if sepia-found
731 (destructuring-bind (file line short &optional mod &rest blah)
732 (car sepia-found)
733 (unless file
734 (setq file (and mod (sepia-module-file mod)))
735 (if file
736 (setf (caar sepia-found) file)
737 (error "No file for %s." (car sepia-found))))
738 (message "%s at %s:%s" short file line)
739 (when (file-exists-p file)
740 (find-file (or file (car (xref-mod-files mod))))
741 (when sepia-found-refiner
742 (funcall sepia-found-refiner line short))
743 (beginning-of-line)
744 (recenter)
745 (setq sepia-found (or (cdr sepia-found)
746 sepia-found-head))))
747 (message "No more definitions.")))
749 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
750 ;; Completion
752 (defun sepia-ident-at-point ()
753 "Find the Perl identifier at point."
754 (save-excursion
755 (when (looking-at "[%$@*&]")
756 (forward-char 1))
757 (let* ((beg (progn
758 (when (re-search-backward "[^A-Za-z_0-9:]" nil 'mu)
759 (forward-char 1))
760 (point)))
761 (sigil (if (= beg (point-min))
763 (char-before (point))))
764 (end (progn
765 (when (re-search-forward "[^A-Za-z_0-9:]" nil 'mu)
766 (forward-char -1))
767 (point))))
768 (list (when (member sigil '(?$ ?@ ?% ?* ?&)) sigil)
769 (buffer-substring-no-properties beg end)))))
771 (defun sepia-function-at-point ()
772 "Find the Perl function called at point."
773 (condition-case nil
774 (save-excursion
775 (let ((pt (point))
776 bof)
777 (sepia-beginning-of-defun)
778 (setq bof (point))
779 (goto-char pt)
780 (sepia-end-of-defun)
781 (when (and (>= pt bof) (< pt (point)))
782 (goto-char bof)
783 (looking-at "\\s *sub\\s +")
784 (forward-char (length (match-string 0)))
785 (concat (or (sepia-buffer-package) "")
786 "::"
787 (cadr (sepia-ident-at-point))))))
788 (error nil)))
790 (defun sepia-complete-symbol ()
791 "Try to complete the word at point.
792 The word may be either a global variable if it has a
793 sigil (sorry, no lexicals), a module, or a function. The
794 function currently ignores module qualifiers, which may be
795 annoying in larger programs.
797 The function is intended to be bound to \\M-TAB, like
798 ``lisp-complete-symbol''."
799 (interactive)
800 (multiple-value-bind (type name) (sepia-ident-at-point)
801 (let ((len (+ (if type 1 0) (length name)))
802 (completions (xref-completions
803 name
804 (case type
805 (?$ "SCALAR")
806 (?@ "ARRAY")
807 (?% "HASH")
808 (?& "CODE")
809 (?* "IO")
810 (t ""))
811 (and (not (eq major-mode 'comint-mode))
812 (sepia-function-at-point)))))
813 (when (and (not completions)
814 (or (not type) (eq type ?&)))
815 (when (string-match ".*::([^:]+)$" name)
816 (setq name (match-string 1 name)))
817 (setq completions (all-completions name sepia-perl-builtins)))
818 (case (length completions)
819 (0 (message "No completions for %s." name) nil)
820 (1 ;; (delete-ident-at-point)
821 (delete-region (- (point) len) (point))
822 (insert (if type (string type) "") (car completions))
824 (t (let ((old name)
825 (new (try-completion "" completions)))
826 (if (string= new old)
827 (with-output-to-temp-buffer "*Completions*"
828 (display-completion-list completions))
829 (delete-region (- (point) len) (point))
830 (insert (if type (string type) "") new)))
831 t)))
834 (defun sepia-indent-or-complete ()
835 "Indent the current line or complete the symbol around point.
837 Specifically, try completion when indentation doesn't move point.
838 This function is intended to be bound to TAB."
839 (interactive)
840 (let ((pos (point)))
841 (let (beginning-of-defun-function
842 end-of-defun-function)
843 (cperl-indent-command))
844 (when (and (= pos (point))
845 (not (bolp))
846 (or (eq last-command 'sepia-indent-or-complete)
847 (looking-at "\\_>")))
848 (sepia-complete-symbol))))
850 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
851 ;;; scratchpad code
853 ;;;###autoload
854 (defun sepia-scratch ()
855 "Create a buffer to interact with a Perl interpreter.
857 The buffer is placed in cperl-mode; calling
858 ``sepia-scratch-send-line'' will evaluate the current line and
859 display the result."
860 (interactive)
861 (switch-to-buffer (get-buffer-create "*perl-scratch*"))
862 (cperl-mode)
863 (local-set-key "\C-j" 'sepia-scratch-send-line))
865 (defun sepia-scratch-send-line (&optional scalarp)
866 "Send the current line to perl, and display the result."
867 (interactive "P")
868 (insert
869 (sepia-eval (concat "do{"
870 (buffer-substring (my-bol-from (point))
871 (my-eol-from (point)))
872 "}") 'scalar-context)))
874 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
875 ;; Miscellany
877 (defun my-perl-frob-region (pre post beg end replace-p)
878 "Pass buffer text from BEG to END through a Perl command."
879 (let* ((exp (concat pre "<<'SEPIA_END_REGION';\n"
880 (buffer-substring-no-properties beg end)
881 (if (= (char-before end) ?\n) "" "\n")
882 "SEPIA_END_REGION\n" post))
883 (new-str (sepia-eval exp 'scalar-context)))
884 (if replace-p
885 (progn (delete-region beg end)
886 (goto-char beg)
887 (insert new-str))
888 (message new-str))))
890 (defun my-eol-from (pt &optional n)
891 (save-excursion
892 (goto-char pt)
893 (end-of-line n)
894 (point)))
896 (defun my-bol-from (pt &optional n)
897 (save-excursion
898 (goto-char pt)
899 (beginning-of-line n)
900 (point)))
902 ;; asdf asdf asdf
903 ;; asdf asdf asdf
905 (defun perl-pe-region (expr beg end &optional replace-p)
906 "Do the equivalent of perl -pe on region
908 \(i.e. evaluate an expression on each line of region). With
909 prefix arg, replace the region with the result."
910 (interactive "MExpression: \nr\nP")
911 (my-perl-frob-region
912 "do { my $ret='';my $region = "
913 (concat "; for (split /\n/, $region) { do { " expr
914 ";}; $ret.=\"$_\\n\"}; $ret}")
915 (my-bol-from beg) (my-eol-from end) replace-p))
917 (defun perl-ne-region (expr beg end &optional replace-p)
918 "Do the moral equivalent of perl -ne on region
920 \(i.e. evaluate an expression on each line of region). With
921 prefix arg, replace the region with the result."
922 (interactive "MExpression:\nr\nP")
923 (my-perl-frob-region
924 "do { my $ret='';my $region = "
925 (concat "; for (split /\n/, $region) { $ret .= do { " expr
926 ";} }; ''.$ret}")
927 (my-bol-from beg) (my-eol-from end) replace-p))
929 (defun perl-ize-region (expr beg end &optional replace-p)
930 "Evaluate a Perl expression on the region as a whole.
932 With prefix arg, replace the region with the result."
933 (interactive "MExpression:\nr\nP")
934 (my-perl-frob-region "do { local $_ = "
935 (concat "; do { " expr ";}; $_ }")
936 beg end replace-p))
938 (defun sepia-guess-package (sub &optional file)
939 "Guess which package SUB is defined in."
940 (let ((defs (xref-location (xref-apropos sub))))
941 (or (and (= (length defs) 1)
942 (or (not file) (equal (caar defs) file))
943 (fourth (car defs)))
944 (and file
945 (fourth (find-if (lambda (x) (equal (car x) file)) defs)))
946 (car (xref-file-modules file))
947 (sepia-buffer-package))))
949 ;;;###autoload
950 (defun sepia-eval-defun ()
951 "Re-evaluate the current function and rebuild its Xrefs."
952 (interactive)
953 (save-excursion
954 (let* ((pt (point))
955 (end (progn (end-of-defun) (point)))
956 (beg (progn (goto-char pt) (beginning-of-defun) (point))))
957 (goto-char beg)
958 (when (looking-at "^sub\\s +\\(.+\\_>\\)")
959 (let* ((sub (match-string 1))
960 (sepia-eval-package
961 (sepia-guess-package sub (buffer-file-name)))
962 (body (buffer-substring-no-properties beg end))
963 (sepia-eval-file (buffer-file-name))
964 (sepia-eval-line (line-number-at-pos beg)))
965 (sepia-eval (if sepia-eval-defun-include-decls
966 (concat
967 (apply #'concat (xref-mod-decls sepia-eval-package))
968 body)
969 body))
970 (xref-redefined sub sepia-eval-package)
971 (message "Defined %s" sub))))))
973 (defun sepia-extract-def (file line obj mod)
974 (with-current-buffer (find-file-noselect (expand-file-name file))
975 (save-excursion
976 (funcall (sepia-refiner 'function) line obj)
977 (beginning-of-line)
978 (when (looking-at (concat "^\\s *sub\\_>.*\\_<" obj "\\_>"))
979 (buffer-substring (point)
980 (progn (end-of-defun) (point)))))))
982 (defun sepia-eval-no-run (string &optional discard collect-warnings)
983 (condition-case err
984 (sepia-eval
985 (concat "\nBEGIN { use B; B::minus_c(); $^C=1; } { "
986 string
987 "}\nBEGIN { die \"ok\\n\" }")
988 discard collect-warnings)
989 (perl-error (if (string-match "^ok\n" (cadr err))
991 (cadr err)))
992 (error err)))
994 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
995 ;; REPL
997 (defvar sepia-eval-file nil
998 "File in which ``sepia-eval'' evaluates perl expressions.")
999 (defvar sepia-eval-line nil
1000 "Line at which ``sepia-eval'' evaluates perl expressions.")
1002 ;;;###autoload
1003 (defun sepia-interact ()
1004 "Start or switch to a perl interaction buffer."
1005 (interactive)
1006 (pop-to-buffer (get-buffer "*perl-interaction*")))
1008 (defun sepia-set-cwd (dir)
1009 (sepia-call "Cwd::chdir" dir))
1011 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1012 ;; Doc-scanning
1014 (defvar sepia-doc-map (make-hash-table :test #'equal))
1015 (defvar sepia-var-doc-map (make-hash-table :test #'equal))
1016 (defvar sepia-module-doc-map (make-hash-table :test #'equal))
1018 (defun sepia-doc-scan-buffer ()
1019 (save-excursion
1020 (goto-char (point-min))
1021 (loop while (re-search-forward
1022 "^=\\(item\\|head2\\)\\s +\\([%$&@A-Za-z_].*\\)" nil t)
1023 if (ignore-errors
1024 (let* ((s1 (match-string 2))
1025 (s2 (let ((case-fold-search nil))
1026 (replace-regexp-in-string
1027 "[A-Z]<\\([^>]+\\)>"
1028 (lambda (x) (match-string 1 s1)) s1)))
1029 (longdoc
1030 (let ((beg (progn (forward-line 2) (point)))
1031 (end (1- (re-search-forward "^=" nil t))))
1032 (forward-line -1)
1033 (goto-char beg)
1034 (if (re-search-forward "^\\(.+\\)$" end t)
1035 (concat s2 ": "
1036 (substring-no-properties
1037 (match-string 1)
1038 0 (position ?. (match-string 1))))
1039 s2))))
1040 (cond
1041 ;; e.g. "C<foo(BLAH)>" or "$x = $y->foo()"
1042 ((string-match "\\([A-Za-z0-9_]+\\)\\s *\\($\\|(\\)" s2)
1043 (list 'function (match-string-no-properties 1 s2)
1044 (or (and (equal s2 (match-string 1 s2)) longdoc) s2)))
1045 ;; e.g. "$x -- this is x" (note: this has to come second)
1046 ((string-match "^[%$@]\\([^( ]+\\)" s2)
1047 (list 'variable (match-string-no-properties 1 s2) longdoc)))))
1048 collect it)))
1050 (defun sepia-buffer-package ()
1051 (save-excursion
1052 (or (and (re-search-backward "^\\s *package\\s +\\([^ ;]+\\)\\s *;" nil t)
1053 (match-string-no-properties 1))
1054 "main")))
1056 (defun sepia-doc-update ()
1057 "Update documentation for a file.
1059 This documentation, taken from \"=item\" entries in the POD, is
1060 used for eldoc feedback."
1061 (interactive)
1062 (let ((pack (ifa (sepia-buffer-package) (concat it "::") "")))
1063 (dolist (x (sepia-doc-scan-buffer))
1064 (let ((map (ecase (car x)
1065 (function sepia-doc-map)
1066 (variable sepia-var-doc-map))))
1067 (puthash (second x) (third x) map)
1068 (puthash (concat pack (second x)) (third x) map)))))
1070 (defun sepia-symbol-info ()
1071 "Eldoc function for Sepia-mode.
1073 Looks in ``sepia-doc-map'' and ``sepia-var-doc-map'', then tries
1074 calling ``cperl-describe-perl-symbol''."
1075 (save-excursion
1076 (multiple-value-bind (type obj) (sepia-ident-at-point)
1077 (when (consp obj)
1078 (setq obj (car obj)))
1079 (unless type
1080 (setq type 'function))
1081 (if (and obj (member type '(function variable module)))
1082 (or (gethash obj (ecase (or type 'function)
1083 (function sepia-doc-map)
1084 (variable sepia-var-doc-map)
1085 (module sepia-module-doc-map)))
1086 ;; Loathe cperl a bit.
1088 (flet ((message (&rest blah) (apply #'format blah)))
1089 (let* ((cperl-message-on-help-error nil)
1090 (hlp (car (cperl-describe-perl-symbol obj))))
1091 (when hlp
1092 ;; cperl's docstrings are too long.
1093 (setq hlp (replace-regexp-in-string "\\s \\{2,\\}" " " hlp))
1094 (if (> (length hlp) 75)
1095 (concat (substring hlp 0 72) "...")
1096 hlp)))))
1097 ""))))
1099 (defun sepia-install-eldoc ()
1100 "Install Sepia hooks for eldoc support."
1101 (interactive)
1102 (set (make-variable-buffer-local
1103 'eldoc-documentation-function)
1104 'sepia-symbol-info)
1105 (if cperl-lazy-installed (cperl-lazy-unstall))
1106 (eldoc-mode 1)
1107 (setq eldoc-idle-delay 1.0))
1109 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1110 ;; Error jump:
1112 (defun sepia-extract-next-warning (pos &optional end)
1113 (catch 'foo
1114 (while (re-search-forward "^\\(.+\\) at \\(.+?\\) line \\([0-9]+\\)"
1115 end t)
1116 (unless (string= "(eval " (substring (match-string 2) 0 6))
1117 (throw 'foo (list (match-string 2)
1118 (parse-integer (match-string 3))
1119 (match-string 1)))))))
1121 (defun sepia-goto-error-at (pos)
1122 "Visit the source of the error on line at point."
1123 (interactive "d")
1124 (ifa (sepia-extract-next-warning (my-bol-from pos) (my-eol-from pos))
1125 (destructuring-bind (file line msg) it
1126 (find-file file)
1127 (goto-line line)
1128 (message "%s" msg))
1129 (error "No error to find.")))
1131 (defun sepia-display-errors (beg end)
1132 "Display source causing errors in current buffer from BEG to END."
1133 (interactive "r")
1134 (goto-char beg)
1135 (let ((msgs nil))
1136 (loop for w = (sepia-extract-next-warning (my-bol-from (point)) end)
1137 while w
1138 do (destructuring-bind (file line msg) w
1139 (push (format "%s:%d:%s\n" (abbreviate-file-name file) line msg)
1140 msgs)))
1141 (erase-buffer)
1142 (goto-char (point-min))
1143 (mapcar #'insert (nreverse msgs))
1144 (goto-char (point-min))
1145 (grep-mode)))
1147 (defun sepia-lisp-to-perl (thing)
1148 "Convert elisp data structure to Perl."
1149 (cond
1150 ((null thing) "undef")
1151 ((symbolp thing)
1152 (let ((pname (substitute ?_ ?- (symbol-name thing)))
1153 (type (string-to-char (symbol-name thing))))
1154 (if (member type '(?% ?$ ?@ ?*))
1155 pname
1156 (concat "\\*" pname))))
1157 ((stringp thing) (format "\"%s\"" thing))
1158 ((integerp thing) (format "%d" thing))
1159 ((numberp thing) (format "%g" thing))
1160 ((and (consp thing) (not (consp (cdr thing))))
1161 (concat (sepia-lisp-to-perl (car thing)) " => "
1162 (sepia-lisp-to-perl (cdr thing))))
1163 ;; list
1164 ((or (not (consp (car thing)))
1165 (listp (cdar thing)))
1166 (concat "[" (mapconcat #'sepia-lisp-to-perl thing ", ") "]"))
1167 ;; hash table
1169 (concat "{" (mapconcat #'sepia-lisp-to-perl thing ", ") "}"))))
1171 (defvar sepia-perl-builtins
1172 (eval-when-compile
1173 (let ((h (make-hash-table)))
1174 (dolist (s '("abs"
1175 "accept"
1176 "alarm"
1177 "atan2"
1178 "bind"
1179 "binmode"
1180 "bless"
1181 "caller"
1182 "chdir"
1183 "chmod"
1184 "chomp"
1185 "chop"
1186 "chown"
1187 "chr"
1188 "chroot"
1189 "close"
1190 "closedir"
1191 "connect"
1192 "continue"
1193 "cos"
1194 "crypt"
1195 "dbmclose"
1196 "dbmopen"
1197 "defined"
1198 "delete"
1199 "die"
1200 "dump"
1201 "each"
1202 "endgrent"
1203 "endhostent"
1204 "endnetent"
1205 "endprotoent"
1206 "endpwent"
1207 "endservent"
1208 "eof"
1209 "eval"
1210 "exec"
1211 "exists"
1212 "exit"
1213 "exp"
1214 "fcntl"
1215 "fileno"
1216 "flock"
1217 "fork"
1218 "format"
1219 "formline"
1220 "getc"
1221 "getgrent"
1222 "getgrgid"
1223 "getgrnam"
1224 "gethostbyaddr"
1225 "gethostbyname"
1226 "gethostent"
1227 "getlogin"
1228 "getnetbyaddr"
1229 "getnetbyname"
1230 "getnetent"
1231 "getpeername"
1232 "getpgrp"
1233 "getppid"
1234 "getpriority"
1235 "getprotobyname"
1236 "getprotobynumber"
1237 "getprotoent"
1238 "getpwent"
1239 "getpwnam"
1240 "getpwuid"
1241 "getservbyname"
1242 "getservbyport"
1243 "getservent"
1244 "getsockname"
1245 "getsockopt"
1246 "glob"
1247 "gmtime"
1248 "goto"
1249 "grep"
1250 "hex"
1251 "import"
1252 "index"
1253 "int"
1254 "ioctl"
1255 "join"
1256 "keys"
1257 "kill"
1258 "last"
1259 "lc"
1260 "lcfirst"
1261 "length"
1262 "link"
1263 "listen"
1264 "local"
1265 "localtime"
1266 "log"
1267 "lstat"
1268 "map"
1269 "mkdir"
1270 "msgctl"
1271 "msgget"
1272 "msgrcv"
1273 "msgsnd"
1274 "next"
1275 "oct"
1276 "open"
1277 "opendir"
1278 "ord"
1279 "pack"
1280 "package"
1281 "pipe"
1282 "pop"
1283 "pos"
1284 "print"
1285 "printf"
1286 "prototype"
1287 "push"
1288 "quotemeta"
1289 "rand"
1290 "read"
1291 "readdir"
1292 "readline"
1293 "readlink"
1294 "readpipe"
1295 "recv"
1296 "redo"
1297 "ref"
1298 "rename"
1299 "require"
1300 "reset"
1301 "return"
1302 "reverse"
1303 "rewinddir"
1304 "rindex"
1305 "rmdir"
1306 "scalar"
1307 "seek"
1308 "seekdir"
1309 "select"
1310 "semctl"
1311 "semget"
1312 "semop"
1313 "send"
1314 "setgrent"
1315 "sethostent"
1316 "setnetent"
1317 "setpgrp"
1318 "setpriority"
1319 "setprotoent"
1320 "setpwent"
1321 "setservent"
1322 "setsockopt"
1323 "shift"
1324 "shmctl"
1325 "shmget"
1326 "shmread"
1327 "shmwrite"
1328 "shutdown"
1329 "sin"
1330 "sleep"
1331 "socket"
1332 "socketpair"
1333 "sort"
1334 "splice"
1335 "split"
1336 "sprintf"
1337 "sqrt"
1338 "srand"
1339 "stat"
1340 "study"
1341 "sub"
1342 "sub*"
1343 "substr"
1344 "symlink"
1345 "syscall"
1346 "sysopen"
1347 "sysread"
1348 "sysseek"
1349 "system"
1350 "syswrite"
1351 "tell"
1352 "telldir"
1353 "tie"
1354 "tied"
1355 "time"
1356 "times"
1357 "truncate"
1358 "uc"
1359 "ucfirst"
1360 "umask"
1361 "undef"
1362 "unlink"
1363 "unpack"
1364 "unshift"
1365 "untie"
1366 "utime"
1367 "values"
1368 "vec"
1369 "wait"
1370 "waitpid"
1371 "wantarray"
1372 "warn"
1373 "write"
1375 (puthash s t h))
1376 h)))
1378 (provide 'sepia)
1379 ;;; sepia.el ends here