* copyedit
[sepia.git] / sepia.el
blob881573fe4823c50463a561de0d86ca2069ec2dfd
1 ;;; Sepia -- Simple Emacs-Perl InterAction: ugly, yet effective.
2 ;; (a.k.a. Septik -- Sean's Emacs-Perl Total Integration Kludge.)
4 ;; Author: Sean O'Rourke <seano@cpan.org>
5 ;; Keywords: Perl, languages
7 ;; Copyright (C) 2004-2011 Sean O'Rourke. All rights reserved, some
8 ;; wrongs reversed. This code is distributed under the same terms
9 ;; as Perl itself.
11 ;;; Commentary:
13 ;; Sepia is a set of tools for Perl development in Emacs. Its goal is
14 ;; to extend CPerl mode with two contributions: fast code navigation
15 ;; and interactive development. It is inspired by Emacs' current
16 ;; support for a number of other languages, including Lisp, Python,
17 ;; Ruby, and Emacs Lisp.
19 ;; See sepia.texi, which comes with the distribution.
21 ;;; Code:
23 (require 'cperl-mode)
24 (require 'gud)
25 (require 'cl)
26 ;; try optional modules, but don't bitch if we fail:
27 (ignore-errors (require 'sepia-w3m))
28 (ignore-errors (require 'sepia-tree))
29 (ignore-errors (require 'sepia-ido))
30 (ignore-errors (require 'sepia-snippet))
31 ;; extensions that should always load (autoload later?)
32 (require 'sepia-cpan)
34 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
35 ;;; Comint communication
37 (defvar sepia-perl5lib nil
38 "* List of extra PERL5LIB directories for `sepia-repl'.")
40 (defvar sepia-program-name "perl"
41 "* Perl program name.")
43 (defvar sepia-view-pod-function
44 (if (featurep 'w3m) 'sepia-w3m-view-pod 'sepia-perldoc-buffer)
45 "* Function to view current buffer's documentation.
47 Useful values include `sepia-w3m-view-pod' and `sepia-perldoc-buffer'.")
49 (defvar sepia-module-list-function
50 (if (featurep 'w3m) 'w3m-find-file 'browse-url-of-file)
51 "* Function to view a list of installed modules.
53 Useful values include `w3m-find-file' and `browse-url-of-file'.")
55 (defvar sepia-complete-methods t
56 "* Non-nil if Sepia should try to complete methods for \"$x->\".
58 NOTE: this feature can be problematic, since it evaluates the
59 object in order to find its type. Currently completion is only
60 attempted for objects that are simple scalars.")
62 (defvar sepia-indent-expand-abbrev t
63 "* If non-NIL, `sepia-indent-or-complete' tries `expand-abbrev'.")
65 (defvar sepia-use-completion t
66 "* Use completion based on Xref database.
68 Turning this off may speed up some operations, if you don't mind
69 losing completion.")
71 (defvar sepia-eval-defun-include-decls t
72 "* Generate and use a declaration list for `sepia-eval-defun'.
73 Without this, code often will not parse; with it, evaluation may
74 be a bit less responsive. Note that since this only includes
75 subs from the evaluation package, it may not always work.")
77 (defvar sepia-prefix-key "\M-."
78 "* Prefix for functions in `sepia-keymap'.")
80 ;;; User options end here.
82 (defvar sepia-process nil
83 "The perl process with which we're interacting.")
84 (defvar sepia-output nil
85 "Current perl output for a response to `sepia-eval-raw', appended
86 to by `sepia-collect-output'.")
87 (defvar sepia-passive-output ""
88 "Current perl output for miscellaneous user interaction, used to
89 look for \";;;###\" lisp evaluation markers.")
91 (defvar sepia-perl-builtins nil
92 "List of Perl builtins for completion.")
94 (defun sepia-collect-output (string)
95 "Collect perl output for `sepia-eval-raw' into sepia-output."
96 (setq sepia-output (concat sepia-output string))
97 "")
99 (defun sepia-eval-raw (str)
100 "Evaluate perl code STR, returning a pair (RESULT-STRING . OUTPUT)."
101 (sepia-ensure-process)
102 (let (ocpof)
103 (unwind-protect
104 (let ((sepia-output "")
105 (start 0))
106 (with-current-buffer (process-buffer sepia-process)
107 (setq ocpof comint-preoutput-filter-functions
108 comint-preoutput-filter-functions
109 '(sepia-collect-output)))
110 (setq str (concat "local $Sepia::STOPDIE=0;"
111 "local $Sepia::STOPWARN=0;"
112 "{ package " (sepia-buffer-package) ";"
113 str " }\n"))
114 (comint-send-string sepia-process
115 (concat (format "<<%d\n" (length str)) str))
116 (while (not (and sepia-output
117 (string-match "> $" sepia-output)))
118 (accept-process-output sepia-process))
119 (if (string-match "^;;;[0-9]+\n" sepia-output)
120 (cons
121 (let* ((x (read-from-string sepia-output
122 (+ (match-beginning 0) 3)))
123 (len (car x))
124 (pos (cdr x)))
125 (prog1 (substring sepia-output (1+ pos) (+ len pos 1))
126 (setq start (+ pos len 1))))
127 (and (string-match ";;;[0-9]+\n" sepia-output start)
128 (let* ((x (read-from-string
129 sepia-output
130 (+ (match-beginning 0) 3)))
131 (len (car x))
132 (pos (cdr x)))
133 (substring sepia-output (1+ pos) (+ len pos 1)))))
134 (cons sepia-output nil)))
135 (with-current-buffer (process-buffer sepia-process)
136 (setq comint-preoutput-filter-functions ocpof)))))
138 (defun sepia-eval (str &optional context detailed)
139 "Evaluate STR in CONTEXT (void by default), and return its result
140 as a Lisp object. If DETAILED is specified, return a
141 pair (RESULT . OUTPUT)."
142 (let* ((tmp (sepia-eval-raw
143 (case context
144 (list-context
145 (concat "Sepia::tolisp([" str "])"))
146 (scalar-context
147 (concat "Sepia::tolisp(scalar(" str "))"))
148 (t (concat str ";1")))))
149 (res (car tmp))
150 (errs (cdr tmp)))
151 (setq res (if context
152 (if (string= res "") "" (car (read-from-string res)))
154 (if detailed
155 (cons res errs)
156 res)))
158 (defun sepia-call (fn context &rest args)
159 "Call perl function FN in CONTEXT with arguments ARGS, returning
160 its result as a Lisp value."
161 (sepia-eval (concat fn "(" (mapconcat #'sepia-lisp-to-perl args ", ") ")")
162 context))
164 (defun sepia-watch-for-eval (string)
165 "Monitor inferior Perl output looking for Lisp evaluation
166 requests. The format for these requests is
167 \"\\n;;;###LENGTH\\nDATA\". Only one such request can come from
168 each inferior Perl prompt."
169 (setq sepia-passive-output (concat sepia-passive-output string))
170 (cond
171 ((string-match "^;;;###[0-9]+" sepia-passive-output)
172 (if (string-match "^;;;###\\([0-9]+\\)\n\\(?:.\\|\n\\)*\n\\(.*> \\)"
173 sepia-passive-output)
174 (let* ((len (car (read-from-string
175 (match-string 1 sepia-passive-output))))
176 (pos (1+ (match-end 1)))
177 (res (ignore-errors (eval (car (read-from-string
178 sepia-passive-output pos
179 (+ pos len)))))))
180 (message "%s => %s"
181 (substring sepia-passive-output pos (+ pos len)) res)
182 (goto-char (point-max))
183 (insert (substring sepia-passive-output (+ 1 pos len)))
184 (set-marker (process-mark (get-buffer-process (current-buffer)))
185 (point))
186 (setq sepia-passive-output ""))
187 ""))
188 (t (setq sepia-passive-output "") string)))
191 (defvar sepia-metapoint-map
192 (let ((map (make-sparse-keymap)))
193 (when (featurep 'ido)
194 (define-key map "j" 'sepia-jump-to-symbol))
195 (dolist (kv '(("c" . sepia-callers)
196 ("C" . sepia-callees)
197 ("a" . sepia-apropos)
198 ("A" . sepia-var-apropos)
199 ("v" . sepia-var-uses)
200 ("V" . sepia-var-defs)
201 ;; ("V" . sepia-var-assigns)
202 ("\M-." . sepia-dwim)
203 ;; ("\M-." . sepia-location)
204 ("d" . sepia-location)
205 ("f" . sepia-defs)
206 ("r" . sepia-rebuild)
207 ("m" . sepia-module-find)
208 ("n" . sepia-next)
209 ("t" . find-tag)
210 ("p" . sepia-perldoc-this)
211 ("l" . sepia-pod-follow-link-at-point)
212 ("u" . sepia-describe-object)))
213 (define-key map (car kv) (cdr kv)))
214 map)
215 "Keymap for Sepia functions. This is just an example of how you
216 might want to bind your keys, which works best when bound to
217 `\\M-.'.")
219 (defvar sepia-shared-map
220 (let ((map (make-sparse-keymap)))
221 (define-key map sepia-prefix-key sepia-metapoint-map)
222 (define-key map "\M-," 'sepia-next)
223 (define-key map "\C-\M-x" 'sepia-eval-defun)
224 (define-key map "\C-c\C-l" 'sepia-load-file)
225 (define-key map "\C-cn" 'sepia-perl-ne-region)
226 (define-key map "\C-c\C-p" 'sepia-view-pod) ;was cperl-pod-spell
227 (define-key map "\C-cp" 'sepia-perl-pe-region)
228 (define-key map "\C-c\C-d" 'cperl-perldoc)
229 (define-key map "\C-c\C-t" 'sepia-repl)
230 (define-key map "\C-c\C-r" 'sepia-eval-region)
231 (define-key map "\C-c\C-s" 'sepia-scratch)
232 (define-key map "\C-c\C-e" 'sepia-eval-expression)
233 (define-key map "\C-c!" 'sepia-set-cwd)
234 (define-key map (kbd "TAB") 'sepia-indent-or-complete)
235 map)
236 "Sepia bindings common to all modes.")
238 ;;;###autoload
239 (defun sepia-eval-region (beg end)
240 (interactive "r")
241 (sepia-eval (buffer-substring beg end)))
243 ;;;###autoload
244 (defun sepia-perldoc-this (name)
245 "View perldoc for module at point."
246 (interactive (list (sepia-interactive-arg 'module)))
247 (let ((wc (current-window-configuration))
248 (old-pd (symbol-function 'w3m-about-perldoc))
249 (old-pdb (symbol-function 'w3m-about-perldoc-buffer))
250 buf)
251 (condition-case stuff
252 (flet ((w3m-about-perldoc (&rest args)
253 (let ((res (apply old-pd args)))
254 (or res (error "lose: %s" args))))
255 (w3m-about-perldoc-buffer (&rest args)
256 (let ((res (apply old-pdb args)))
257 (or res (error "lose: %s" args)))))
258 (funcall (if (featurep 'w3m) 'w3m-perldoc 'cperl-perldoc) name)
259 (setq buf (current-buffer)))
260 (error (set-window-configuration wc)))
261 (set-window-configuration wc)
262 (pop-to-buffer buf t)))
264 (defun sepia-view-pod ()
265 "View POD for the current buffer."
266 (interactive)
267 (funcall sepia-view-pod-function))
269 (defun sepia-module-list ()
270 "List installed modules with links to their documentation.
272 This lists not just top-level packages appearing in packlist
273 files, but all documented modules on the system, organized by
274 package."
275 (interactive)
276 (let ((file "/tmp/modlist.html"))
277 ;; (unless (file-exists-p file)
278 (sepia-eval-raw (format "Sepia::html_module_list(\"%s\")" file))
279 (funcall sepia-module-list-function file)))
281 (defun sepia-package-list ()
282 "List installed packages with links to their documentation.
284 This lists only top-level packages appearing in packlist files.
285 For modules within packages, see `sepia-module-list'."
286 (interactive)
287 (let ((file "/tmp/packlist.html"))
288 ;; (unless (file-exists-p file)
289 (sepia-eval-raw (format "Sepia::html_package_list(\"%s\")" file))
290 (funcall sepia-module-list-function file)))
292 (defun sepia-perldoc-buffer ()
293 "View current buffer's POD using pod2html and `browse-url'.
295 Interactive users should call `sepia-view-pod'."
296 (let ((buffer (get-buffer-create "*sepia-pod*"))
297 (errs (get-buffer-create "*sepia-pod-errors*"))
298 (inhibit-read-only t))
299 (with-current-buffer buffer (erase-buffer))
300 (save-window-excursion
301 (shell-command-on-region (point-min) (point-max) "pod2html"
302 buffer nil errs))
303 (with-current-buffer buffer (browse-url-of-buffer))))
305 (defun sepia-perl-name (sym &optional mod)
306 "Convert a Perl name to a Lisp name."
307 (setq sym (substitute ?_ ?- (if (symbolp sym) (symbol-name sym) sym)))
308 (if mod
309 (concat mod "::" sym)
310 sym))
312 (defun sepia-live-p ()
313 (and (processp sepia-process)
314 (eq (process-status sepia-process) 'run)))
316 (defun sepia-ensure-process (&optional remote-host)
317 (unless (sepia-live-p)
318 (with-current-buffer (get-buffer-create "*sepia-repl*")
319 (sepia-repl-mode)
320 (set (make-local-variable 'sepia-passive-output) ""))
321 (if remote-host
322 (comint-exec (get-buffer-create "*sepia-repl*")
323 "attachtty" "attachtty" nil
324 (list remote-host))
325 (let ((stuff (split-string sepia-program-name nil t)))
326 (comint-exec (get-buffer-create "*sepia-repl*")
327 "perl" (car stuff) nil
328 (append
329 (cdr stuff)
330 (mapcar (lambda (x) (concat "-I" x)) sepia-perl5lib)
331 '("-MSepia" "-MSepia::Xref"
332 "-e" "Sepia::repl")))))
333 (setq sepia-process (get-buffer-process "*sepia-repl*"))
334 (accept-process-output sepia-process 1)
335 ;; Steal a bit from gud-common-init:
336 (setq gud-running t)
337 (setq gud-last-last-frame nil)
338 (set-process-filter sepia-process 'gud-filter)
339 (set-process-sentinel sepia-process 'gud-sentinel)))
341 ;;;###autoload
342 (defun sepia-repl (&optional remote-host)
343 "Start the Sepia REPL."
344 (interactive (list (and current-prefix-arg
345 (read-string "Host: "))))
346 (sepia-init) ;; set up keymaps, etc.
347 (sepia-ensure-process remote-host)
348 (pop-to-buffer (get-buffer "*sepia-repl*")))
350 (defun sepia-cont-or-restart ()
351 (interactive)
352 (if (get-buffer-process (current-buffer))
353 (gud-cont current-prefix-arg)
354 (sepia-repl)))
356 (defvar sepia-repl-mode-map
357 (let ((map (copy-keymap sepia-shared-map)))
358 (set-keymap-parent map gud-mode-map)
359 (define-key map (kbd "<tab>") 'comint-dynamic-complete)
360 (define-key map "\C-a" 'comint-bol)
361 (define-key map "\C-c\C-r" 'sepia-cont-or-restart)
362 map)
364 "Keymap for Sepia interactive mode.")
366 (define-derived-mode sepia-repl-mode gud-mode "Sepia REPL"
367 "Major mode for the Sepia REPL.
369 \\{sepia-repl-mode-map}"
370 ;; (set (make-local-variable 'comint-use-prompt-regexp) t)
371 (modify-syntax-entry ?: "_")
372 (modify-syntax-entry ?> ".")
373 (set (make-local-variable 'comint-prompt-regexp) "^[^>\n]*> *")
374 (set (make-local-variable 'gud-target-name) "sepia")
375 (set (make-local-variable 'gud-marker-filter) 'sepia-gud-marker-filter)
376 (set (make-local-variable 'gud-minor-mode) 'sepia)
377 (sepia-install-eldoc)
379 (setq gud-comint-buffer (current-buffer))
380 (setq gud-last-last-frame nil)
381 (setq gud-sepia-acc nil)
383 (gud-def gud-break ",break %f:%l" "\C-b" "Set breakpoint at current line.")
384 (gud-def gud-step ",step %p" "\C-s" "Step one line.")
385 (gud-def gud-next ",next %p" "\C-n" "Step one line, skipping calls.")
386 (gud-def gud-cont ",continue" "\C-r" "Continue.")
387 (gud-def gud-print "%e" "\C-p" "Evaluate something.")
388 (gud-def gud-remove ",delete %l %f" "\C-d" "Delete current breakpoint.")
389 ;; Sadly, this hoses our keybindings.
390 (compilation-shell-minor-mode 1)
391 (set (make-local-variable 'comint-dynamic-complete-functions)
392 '(sepia-complete-symbol comint-dynamic-complete-filename))
393 (set (make-local-variable 'comint-preoutput-filter-functions)
394 '(sepia-watch-for-eval))
395 (run-hooks 'sepia-repl-mode-hook)
398 (defvar gud-sepia-acc nil
399 "Accumulator for `sepia-gud-marker-filter'.")
401 (defun sepia-gud-marker-filter (str)
402 (setq gud-sepia-acc
403 (if gud-sepia-acc
404 (concat gud-sepia-acc str)
405 str))
406 (while (string-match "_<\\([^:>]+\\):\\([0-9]+\\)>\\(.*\\)" gud-sepia-acc)
407 (setq gud-last-last-frame gud-last-frame
408 gud-last-frame (cons
409 (match-string 1 gud-sepia-acc)
410 (string-to-number (match-string 2 gud-sepia-acc)))
411 gud-sepia-acc (match-string 3 gud-sepia-acc)))
412 (setq gud-sepia-acc
413 (if (string-match "\\(_<.*\\)" gud-sepia-acc)
414 (match-string 1 gud-sepia-acc)
415 nil))
416 str)
418 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
419 ;;; Xref
421 (defun define-xref-function (package name doc)
422 "Define a lisp mirror for a low-level Sepia function."
423 (let ((lisp-name (intern (format "xref-%s" name)))
424 (pl-name (sepia-perl-name name package)))
425 (fmakunbound lisp-name)
426 (eval `(defun ,lisp-name (&rest args)
427 ,doc
428 (apply #'sepia-call ,pl-name 'list-context args)))))
430 (defun define-modinfo-function (name &optional doc context)
431 "Define a lisp mirror for a function from Module::Info."
432 (let ((name (intern (format "sepia-module-%s" name)))
433 (pl-func (sepia-perl-name name))
434 (full-doc (concat (or doc "") "
436 This function uses Module::Info, so it does not require that the
437 module in question be loaded.")))
438 (when (fboundp name) (fmakunbound name))
439 (eval `(defun ,name (mod)
440 ,full-doc
441 (interactive (list (sepia-interactive-arg 'module)))
442 (sepia-maybe-echo
443 (sepia-call "Sepia::module_info" ',(or context 'scalar-context)
444 mod ,pl-func)
445 (interactive-p))))))
447 (defun sepia-thing-at-point (what)
448 "Like `thing-at-point', but hacked to avoid REPL prompt."
449 (let ((th (thing-at-point what)))
450 (and th (not (string-match "[ >]$" th)) th)))
452 (defvar sepia-sub-re "^ *sub\\s +\\(.+\\_>\\)")
454 (defvar sepia-history nil)
456 (defun sepia-interactive-arg (&optional sepia-arg-type)
457 "Default argument for most Sepia functions. TYPE is a symbol --
458 either 'file to look for a file, or anything else to use the
459 symbol at point."
460 (let* ((default (case sepia-arg-type
461 (file (or (thing-at-point 'file) (buffer-file-name)))
462 (t (sepia-thing-at-point 'symbol))))
463 (text (capitalize (symbol-name sepia-arg-type)))
464 (choices
465 (lambda (str &rest blah)
466 (let ((completions (xref-completions
467 (case sepia-arg-type
468 (module nil)
469 (variable "VARIABLE")
470 (function "CODE")
471 (t nil))
472 str)))
473 (when (eq sepia-arg-type 'module)
474 (setq completions
475 (remove-if (lambda (x) (string-match "::$" x)) completions)))
476 completions)))
477 (prompt (if default
478 (format "%s [%s]: " text default)
479 (format "%s: " text)))
480 (ret (if sepia-use-completion
481 (completing-read prompt 'blah-choices nil nil nil 'sepia-history
482 default)
483 (read-string prompt nil 'sepia-history default))))
484 (push ret sepia-history)
485 ret))
487 (defun sepia-interactive-module ()
488 "Guess which module we should look things up in. Prompting for a
489 module all the time is a PITA, but I don't think this (choosing
490 the current file's module) is a good alternative, either. Best
491 would be to choose the module based on what we know about the
492 symbol at point."
493 (let ((xs (xref-file-modules (buffer-file-name))))
494 (if (= (length xs) 1)
495 (car xs)
496 nil)))
498 (defun sepia-maybe-echo (result &optional print-message)
499 (when print-message
500 (message "%s" result))
501 result)
503 (defun sepia-find-module-file (mod)
504 (or (sepia-module-file mod)
505 (car (xref-guess-module-file mod))))
507 (defun sepia-module-find (mod)
508 "Find the file defining module MOD."
509 (interactive (list (sepia-interactive-arg 'module)))
510 (let ((fn (sepia-find-module-file mod)))
511 (if fn
512 (progn
513 (message "Module %s in %s." mod fn)
514 (pop-to-buffer (find-file-noselect (expand-file-name fn))))
515 (message "Can't find module %s." mod))))
517 (defmacro ifa (test then &rest else)
518 `(let ((it ,test))
519 (if it ,then ,@else)))
521 (defvar sepia-found-refiner nil)
523 (defun sepia-show-locations (locs &optional unobtrusive)
524 (setq locs (remove nil locs)) ; XXX where's nil from?
525 (if locs
526 (with-current-buffer (get-buffer-create "*sepia-places*")
527 (let ((inhibit-read-only t))
528 (erase-buffer)
529 (insert (format "-*- mode: grep; default-directory: %S -*-\n\n"
530 default-directory))
531 (dolist (loc (sort locs
532 (lambda (a b)
533 (or (string< (car a) (car b))
534 (and (string= (car a) (car b))
535 (< (second a) (second b)))))))
536 (destructuring-bind (file line name &rest blah) loc
537 (let ((str (ifa (find-buffer-visiting file)
538 (with-current-buffer it
539 (ifa sepia-found-refiner
540 (funcall it line name)
541 (goto-line line))
542 (unless (= (line-number-at-pos) line)
543 (message "line for %s was %d, now %d" name line
544 (line-number-at-pos)))
545 (setq line (line-number-at-pos))
546 (let ((tmpstr
547 (buffer-substring (sepia-bol-from (point))
548 (sepia-eol-from (point)))))
549 (if (> (length tmpstr) 60)
550 (concat "\n " tmpstr)
551 tmpstr)))
552 "...")))
553 (insert (format "%s:%d:%s\n" (abbreviate-file-name file) line str)))))
554 (insert "\nGrep finished (matches found).\n")
555 (grep-mode))
556 (if unobtrusive
557 (save-window-excursion (next-error nil t))
558 (next-error nil t)))
559 (message "No matches found.")))
561 (defmacro define-sepia-query (name doc &optional gen test prompt)
562 "Define a sepia querying function."
563 `(defun ,name (ident &optional module file line display-p)
564 ,(concat doc "
566 With prefix arg, display matches in a `grep-mode' buffer.
567 Without, go to the first match; calling `sepia-next' will cycle
568 through subsequent matches.
570 Depending on the query, MODULE, FILE, and LINE may be used to
571 narrow the results, as long as doing so leaves some matches.
572 When called interactively, they are taken from the current
573 buffer.
575 (interactive (list (sepia-interactive-arg ,(or prompt ''function))
576 (sepia-interactive-module)
577 (buffer-file-name)
578 (line-number-at-pos (point))
579 current-prefix-arg
581 (let ((ret
582 ,(if test
583 `(let ((tmp (,gen ident module file line)))
584 (or (mapcan #',test tmp) tmp))
585 `(,gen ident module file line))))
586 (sepia-show-locations ret (not display-p)))))
588 (define-sepia-query sepia-defs
589 "Find all definitions of sub."
590 xref-apropos
591 xref-location)
593 (define-sepia-query sepia-callers
594 "Find callers of FUNC."
595 xref-callers
596 xref-location)
598 (define-sepia-query sepia-callees
599 "Find a sub's callees."
600 xref-callees
601 xref-location)
603 (define-sepia-query sepia-var-defs
604 "Find a var's definitions."
605 xref-var-defs
606 (lambda (x) (setf (third x) ident) (list x))
607 'variable)
609 (define-sepia-query sepia-var-uses
610 "Find a var's uses."
611 xref-var-uses
612 (lambda (x) (setf (third x) ident) (list x))
613 'variable)
615 (define-sepia-query sepia-var-assigns
616 "Find/list assignments to a variable."
617 xref-var-assigns
618 (lambda (x) (setf (third x) ident) (list x))
619 'variable)
621 (defalias 'sepia-package-defs 'sepia-module-describe)
623 (define-sepia-query sepia-apropos
624 "Find/list subroutines matching regexp."
625 (lambda (name &rest blah) (xref-apropos name 1))
626 xref-location
627 'function)
629 (define-sepia-query sepia-var-apropos
630 "Find/list variables matching regexp."
631 xref-var-apropos
632 xref-var-defs
633 'variable)
635 (defun sepia-location (name &optional jump-to)
636 "Find the definition of NAME.
638 When called interactively (or with JUMP-TO true), go directly
639 to this location."
640 (interactive (list (sepia-interactive-arg 'function) t))
641 (let* ((fl (or (car (xref-location name))
642 (car (remove-if #'null
643 (apply #'xref-location (xref-apropos name)))))))
644 (when (and (car fl) (string-match "^(eval " (car fl)))
645 (message "Can't find definition of %s in %s." name (car fl))
646 (setq fl nil))
647 (if jump-to
648 (if fl (progn
649 (sepia-set-found (list fl) 'function)
650 (sepia-next))
651 (message "No definition for %s." name))
652 fl)))
654 ;;;###autoload
655 (defun sepia-dwim (&optional display-p)
656 "Try to do the right thing with identifier at point.
657 * Find all definitions, if thing-at-point is a function
658 * Find all uses, if thing-at-point is a variable
659 * Find documentation, if thing-at-point is a module
660 * Prompt otherwise
662 (interactive "P")
663 (multiple-value-bind (type obj) (sepia-ident-at-point)
664 (let* ((module-doc-p nil)
665 (ret
666 (cond
667 ((member type '(?% ?$ ?@)) (xref-var-defs obj))
668 ((or (equal type ?&)
669 (let (case-fold-search)
670 (string-match "^[^A-Z]" obj)))
671 (list (sepia-location obj)))
672 ((sepia-looks-like-module obj)
673 (setq module-doc-p t)
674 `((,(sepia-perldoc-this obj) 1 nil nil)))
675 (t (setq module-doc-p t)
676 (call-interactively 'sepia-defs)))))
677 (unless module-doc-p
678 (sepia-show-locations ret (not display-p))))))
680 (defun sepia-rebuild ()
681 "Rebuild the Xref database."
682 (interactive)
683 (xref-rebuild))
685 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
686 ;;; Perl motion commands.
688 ;;; XXX -- these are a hack to prevent infinite recursion calling
689 ;;; e.g. beginning-of-defun from beginning-of-defun-function.
690 ;;; `beginning-of-defun' should handle this.
691 (defmacro sepia-safe-bodf (&optional n)
692 `(let ((beginning-of-defun-function
693 (if (and (boundp 'beginning-of-defun-function)
694 (eq beginning-of-defun-function 'sepia-beginning-of-defun))
696 beginning-of-defun-function)))
697 (beginning-of-defun ,n)))
699 (defmacro sepia-safe-eodf (&optional n)
700 `(let ((end-of-defun-function
701 (if (and (boundp 'end-of-defun-function)
702 (eq end-of-defun-function 'sepia-end-of-defun))
704 end-of-defun-function)))
705 (end-of-defun ,n)))
707 (defun sepia-beginning-of-defun (&optional n)
708 "Move to beginning of current function.
710 The prefix argument is the same as for `beginning-of-defun'."
711 (interactive "p")
712 (setq n (or n 1))
713 (ignore-errors
714 (when (< n 0)
715 (sepia-end-of-defun (- n))
716 (setq n 1))
717 (re-search-backward sepia-sub-re nil nil n)))
719 (defun sepia-inside-defun ()
720 "True if point is inside a sub."
721 (condition-case nil
722 (save-excursion
723 (let ((cur (point)))
724 (re-search-backward sepia-sub-re)
725 (when (< (point) cur)
726 (search-forward "{")
727 (backward-char 1)
728 (forward-sexp)
729 (> (point) cur))))
730 (error nil)))
732 (defun sepia-end-of-defun (&optional n)
733 "Move to end of current function.
735 The prefix argument is the same as for `end-of-defun'."
736 (interactive "p")
737 (setq n (or n 1))
738 (when (< n 0)
739 (sepia-beginning-of-defun (- n))
740 (setq n 1))
741 ;; If we're outside a defun, skip to the next
742 (ignore-errors
743 (unless (sepia-inside-defun)
744 (re-search-forward sepia-sub-re)
745 (forward-char 1))
746 (dotimes (i n)
747 (re-search-backward sepia-sub-re)
748 (search-forward "{")
749 (backward-char 1)
750 (forward-sexp))
751 (point)))
753 (defun sepia-rename-lexical (old new &optional prompt)
754 "Replace lexical variable OLD with NEW in the current function.
756 With prefix argument, query for each replacement. It is an error
757 to call this outside a function."
758 (interactive
759 (let ((old (sepia-thing-at-point 'symbol)))
760 (list (read-string "Old name: " old nil old)
761 (read-string "New name: ")
762 current-prefix-arg)))
763 (message "(%s %s)" old new)
764 (unless (sepia-inside-defun)
765 (error "Can't rename %s outside a defun." old))
766 (setq old (concat "\\([$%@]\\)\\_<" (regexp-quote old) "\\_>")
767 new
768 (concat "\\1" new))
769 (let ((bod (sepia-beginning-of-defun))
770 (eod (sepia-end-of-defun)))
771 (if prompt
772 (query-replace-regexp old new nil bod eod)
773 ;; (replace-regexp old new nil bod eod)
774 (goto-char bod)
775 (while (re-search-forward old eod t)
776 (replace-match new)))))
778 (defun sepia-defun-around-point (&optional where)
779 "Return the text of function around point."
780 (unless where
781 (setq where (point)))
782 (save-excursion
783 (goto-char where)
784 (and (sepia-beginning-of-defun)
785 (match-string-no-properties 1))))
787 (defun sepia-lexicals-at-point (&optional where)
788 "Find lexicals in scope at point."
789 (interactive "d")
790 (unless where
791 (setq where (point)))
792 (let ((subname (sepia-defun-around-point where))
793 (mod (sepia-buffer-package)))
794 (xref-lexicals (sepia-perl-name subname mod))))
796 ;;;###autoload
797 (defun sepia-load-file (file &optional rebuild-p collect-warnings)
798 "Reload a file (interactively, the current buffer's file).
800 With REBUILD-P (or a prefix argument when called interactively),
801 also rebuild the xref database."
802 (interactive (list (expand-file-name (buffer-file-name))
803 prefix-arg
804 (format "*%s errors*" (buffer-file-name))))
805 (save-buffer)
806 (when collect-warnings
807 (let (kill-buffer-query-functions)
808 (ignore-errors
809 (kill-buffer collect-warnings))))
810 (let* ((tmp (sepia-eval (format "do '%s' || ($@ && do { local $Sepia::Debug::STOPDIE; die $@ })" file)
811 'scalar-context t))
812 (res (car tmp))
813 (errs (cdr tmp)))
814 (message "sepia: %s returned %s" (abbreviate-file-name file)
815 (if (equal res "") "undef" res))
816 (when (and collect-warnings
817 (> (length errs) 1))
818 (with-current-buffer (get-buffer-create collect-warnings)
819 (let ((inhibit-read-only t))
820 (delete-region (point-min) (point-max))
821 (insert errs)
822 (sepia-display-errors (point-min) (point-max))
823 (pop-to-buffer (current-buffer))))))
824 (when rebuild-p
825 (xref-rebuild)))
827 (defvar sepia-found)
829 (defun sepia-set-found (list &optional type)
830 (setq list
831 (remove-if (lambda (x)
832 (or (not x)
833 (and (not (car x)) (string= (fourth x) "main"))))
834 list))
835 (setq sepia-found (cons -1 list))
836 (setq sepia-found-refiner (sepia-refiner type)))
838 (defun sepia-refiner (type)
839 (case type
840 (function
841 (lambda (line ident)
842 (let ((sub-re (concat "^\\s *sub\\s +.*" ident "\\_>")))
843 ;; Test this because sometimes we get lucky and get the line
844 ;; just right, in which case beginning-of-defun goes to the
845 ;; previous defun.
846 (or (and line
847 (progn
848 (goto-line line)
849 (beginning-of-defun)
850 (looking-at sub-re)))
851 (progn (goto-char (point-min))
852 (re-search-forward sub-re nil t)))
853 (beginning-of-line))))
854 ;; Old version -- this may actually work better if
855 ;; beginning-of-defun goes flaky on us.
856 ;; (or (re-search-backward sub-re
857 ;; (sepia-bol-from (point) -20) t)
858 ;; (re-search-forward sub-re
859 ;; (sepia-bol-from (point) 10) t))
860 ;; (beginning-of-line)
861 (variable
862 (lambda (line ident)
863 (let ((var-re (concat "\\_<" ident "\\_>")))
864 (cond
865 (line (goto-line line)
866 (or (re-search-backward var-re (sepia-bol-from (point) -5) t)
867 (re-search-forward var-re (sepia-bol-from (point) 5) t)))
868 (t (goto-char (point-min))
869 (re-search-forward var-re nil t))))))
870 (t (lambda (line ident) (and line (goto-line line))))))
872 (defun sepia-next (&optional arg)
873 "Go to the next thing (e.g. def, use) found by sepia."
874 (interactive "p")
875 (save-window-excursion (next-error arg)))
877 (defun sepia-previous (&optional arg)
878 "Go to the previous thing (e.g. def, use) found by sepia."
879 (interactive "p")
880 (or arg (setq arg 1))
881 (sepia-next (- arg)))
883 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
884 ;; Completion
886 (defun sepia-ident-before-point ()
887 "Find the Perl identifier at or preceding point."
888 (save-excursion
889 (skip-syntax-backward " ")
890 (backward-char 1)
891 (sepia-ident-at-point)))
893 (defun sepia-simple-method-before-point ()
894 "Find the \"simple\" method call before point.
896 Looks for a simple method called on a variable before point and
897 returns the list (OBJECT METHOD). For example, \"$x->blah\"
898 returns '(\"$x\" \"blah\"). Only simple methods are recognized,
899 because completing anything evaluates it, so completing complex
900 expressions would lead to disaster."
901 (when sepia-complete-methods
902 (let ((end (point))
903 (bound (max (- (point) 100) (point-min)))
904 arrow beg)
905 (save-excursion
906 ;; XXX - can't do this because COMINT's syntax table is weird.
907 ;; (skip-syntax-backward "_w")
908 (skip-chars-backward "a-zA-Z0-9_")
909 (when (looking-back "->\\s *" bound)
910 (setq arrow (search-backward "->" bound))
911 (skip-chars-backward "a-zA-Z0-9_:")
912 (cond
913 ;; $x->method
914 ((char-equal (char-before (point)) ?$)
915 (setq beg (1- (point))))
916 ;; X::Class->method
917 ((multiple-value-bind (type obj) (sepia-ident-at-point)
918 (and (not type)
919 (sepia-looks-like-module obj)))
920 (setq beg (point))))
921 (when beg
922 (list (buffer-substring-no-properties beg arrow)
923 (buffer-substring-no-properties (+ 2 arrow) end)
924 (buffer-substring-no-properties beg end))))))))
926 (defun sepia-ident-at-point ()
927 "Find the Perl identifier at point."
928 (save-excursion
929 (let ((orig (point)))
930 (when (looking-at "[%$@*&]")
931 (forward-char 1))
932 (let* ((beg (progn
933 (when (re-search-backward "[^A-Za-z_0-9:]" nil 'mu)
934 (forward-char 1))
935 (point)))
936 (sigil (if (= beg (point-min))
938 (char-before (point))))
939 (end (progn
940 (when (re-search-forward "[^A-Za-z_0-9:]" nil 'mu)
941 (forward-char -1))
942 (point))))
943 (if (= beg end)
944 ;; try special variables
945 (if (and (member (char-before orig) '(?$ ?@ ?%))
946 (member (car (syntax-after orig)) '(1 4 5 7 9)))
947 (list (char-before orig)
948 (buffer-substring-no-properties orig (1+ orig)))
949 '(nil ""))
950 ;; actual thing
951 (list (when (member sigil '(?$ ?@ ?% ?* ?&)) sigil)
952 (buffer-substring-no-properties beg end)))))))
954 (defun sepia-function-at-point ()
955 "Find the Perl function called at point."
956 (condition-case nil
957 (save-excursion
958 (let ((pt (point))
959 bof)
960 (sepia-beginning-of-defun)
961 (setq bof (point))
962 (goto-char pt)
963 (sepia-end-of-defun)
964 (when (and (>= pt bof) (< pt (point)))
965 (sepia-beginning-of-defun)
966 (when (and (= (point) bof) (looking-at "\\s *sub\\s +"))
967 (forward-char (length (match-string 0)))
968 (concat (or (sepia-buffer-package) "")
969 "::"
970 (cadr (sepia-ident-at-point)))))))
971 (error nil)))
973 (defun sepia-repl-complete ()
974 "Try to complete the word at point in the REPL.
975 Just like `sepia-complete-symbol', except that it also completes
976 REPL shortcuts."
977 (interactive)
978 (error "TODO"))
980 (defvar sepia-shortcuts
982 "break" "eval" "lsbreak" "quit" "size" "wantarray"
983 "cd" "format" "methods" "reload" "strict" "who"
984 "debug" "freload" "package" "restart" "test"
985 "define" "help" "pdl" "save" "time"
986 "delete" "load" "pwd" "shell" "undef"
988 "List of currently-defined REPL shortcuts.
990 XXX: this needs to be updated whenever you add one on the Perl side.")
992 (defun sepia-complete-symbol ()
993 "Try to complete the word at point.
994 The word may be either a global or lexical variable if it has a
995 sigil, a module, or a function. The function currently ignores
996 module qualifiers, which may be annoying in larger programs.
998 The function is intended to be bound to \\M-TAB, like
999 `lisp-complete-symbol'."
1000 (interactive)
1001 (let ((win (get-buffer-window "*Completions*" 0))
1003 completions
1004 type
1005 meth)
1006 (if (and (eq last-command this-command)
1007 win (window-live-p win) (window-buffer win)
1008 (buffer-name (window-buffer win)))
1010 ;; If this command was repeated, and
1011 ;; there's a fresh completion window with a live buffer,
1012 ;; and this command is repeated, scroll that window.
1013 (with-current-buffer (window-buffer win)
1014 (if (pos-visible-in-window-p (point-max) win)
1015 (set-window-start win (point-min))
1016 (save-selected-window
1017 (select-window win)
1018 (scroll-up))))
1020 ;; Otherwise actually do completion:
1021 ;; 0 - try a shortcut
1022 (when (eq major-mode 'sepia-repl-mode)
1023 (save-excursion
1024 (comint-bol)
1025 (when (looking-at ",\\([a-z]+\\)$")
1026 (let ((str (match-string 1)))
1027 (setq len (length str)
1028 completions (all-completions str sepia-shortcuts))))))
1029 ;; 1 - Look for a method call:
1030 (unless completions
1031 (setq meth (sepia-simple-method-before-point))
1032 (when meth
1033 (setq len (length (caddr meth))
1034 completions (xref-method-completions
1035 (cons 'expr (format "'%s'" (car meth)))
1036 (cadr meth)
1037 "Sepia::repl_eval")
1038 type (format "%s->" (car meth)))))
1039 ;; 1.x - look for a module
1040 (unless completions
1041 (setq completions
1042 (and (looking-back " *\\(?:use\\|require\\|package\\|no\\)\\s +[^ ]*" (sepia-bol-from (point)))
1043 (xref-apropos-module
1044 (multiple-value-bind (typ name)
1045 (sepia-ident-before-point)
1046 (setq len (length name))
1047 name))
1050 (multiple-value-bind (typ name) (sepia-ident-before-point)
1051 (unless completions
1052 ;; 2 - look for a regular function/variable/whatever
1053 (setq type typ
1054 len (+ (if type 1 0) (length name))
1055 completions
1056 (mapcar (lambda (x)
1057 (if (or (not type)
1058 (eq type ?&))
1060 (format "%c%s" type x)))
1061 (xref-completions
1062 (case type
1063 (?$ "VARIABLE")
1064 (?@ "ARRAY")
1065 (?% "HASH")
1066 (?& "CODE")
1067 (?* "IO")
1068 (t ""))
1069 name
1070 (and (eq major-mode 'sepia-mode)
1071 (sepia-function-at-point))))))
1072 ;; 3 - try a Perl built-in
1073 (when (and (not completions)
1074 (or (not type) (eq type ?&)))
1075 (when (string-match ".*::([^:]+)$" name)
1076 (setq name (match-string 1 name)))
1077 (setq completions (all-completions name sepia-perl-builtins)))
1078 (case (length completions)
1079 (0 (message "No completions.") nil)
1080 (1 ;; XXX - skip sigil to match s-i-before-point
1081 (delete-region (- (point) len) (point))
1082 (insert (car completions))
1083 ;; Hide stale completions buffer (stolen from lisp.el).
1084 (if win (with-selected-window win (bury-buffer))) t)
1085 (t (let ((old name)
1086 (new (try-completion "" completions)))
1087 (if (<= (length new) (+ (length old) (if type 1 0)))
1088 (with-output-to-temp-buffer "*Completions*"
1089 (display-completion-list completions))
1090 (let ((win (get-buffer-window "*Completions*" 0)))
1091 (if win (with-selected-window win (bury-buffer))))
1092 (delete-region (- (point) len) (point))
1093 (insert new))))))
1094 t)))
1096 (defun sepia-indent-or-complete ()
1097 "Indent the current line or complete the symbol around point.
1099 Specifically, try completion when indentation doesn't move point.
1100 This function is intended to be bound to TAB."
1101 (interactive)
1102 (let ((pos (point)))
1103 (let (beginning-of-defun-function
1104 end-of-defun-function)
1105 (cperl-indent-command))
1106 (when (and (= pos (point))
1107 (not (bolp))
1108 (or (eq last-command 'sepia-indent-or-complete)
1109 (looking-at "\\_>")))
1110 (when (or (not sepia-indent-expand-abbrev)
1111 (and (not (expand-abbrev))
1112 ;; XXX this shouldn't be necessary, but
1113 ;; expand-abbrev returns NIL for e.g. the "else"
1114 ;; snippet.
1115 (= pos (point))))
1116 (sepia-complete-symbol)))))
1118 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1119 ;;; scratchpad code
1121 (defvar sepia-mode-map
1122 (let ((map (copy-keymap sepia-shared-map)))
1123 (set-keymap-parent map cperl-mode-map)
1124 (define-key map "\C-c\C-h" nil)
1125 map)
1126 "Keymap for Sepia mode.")
1128 ;;;###autoload
1129 (define-derived-mode sepia-mode cperl-mode "Sepia"
1130 "Major mode for Perl editing, derived from cperl mode.
1131 \\{sepia-mode-map}"
1132 (sepia-init)
1133 (sepia-install-eldoc)
1134 (sepia-doc-update)
1135 (set (make-local-variable 'beginning-of-defun-function)
1136 'sepia-beginning-of-defun)
1137 (set (make-local-variable 'end-of-defun-function)
1138 'sepia-end-of-defun)
1139 (setq indent-line-function 'sepia-indent-line))
1141 (defun sepia-init ()
1142 "Perform the initialization necessary to start Sepia."
1143 ;; Load perl defs:
1144 ;; Create glue wrappers for Module::Info funcs.
1145 (unless (fboundp 'xref-completions)
1146 (dolist (x '((name "Find module name.\n\nDoes not require loading.")
1147 (version "Find module version.\n\nDoes not require loading.")
1148 (inc-dir "Find directory in which this module was found.\n\nDoes not require loading.")
1149 (file "Absolute path of file defining this module.\n\nDoes not require loading.")
1150 (is-core "Guess whether or not a module is part of the core distribution.
1151 Does not require loading.")
1152 (modules-used "List modules used by this module.\n\nRequires loading." list-context)
1153 (packages-inside "List sub-packages in this module.\n\nRequires loading." list-context)
1154 (superclasses "List module's superclasses.\n\nRequires loading." list-context)))
1155 (apply #'define-modinfo-function x))
1156 ;; Create low-level wrappers for Sepia
1157 (dolist (x '((completions "Find completions in the symbol table.")
1158 (method-completions "Complete on an object's methods.")
1159 (location "Find an identifier's location.")
1160 (mod-subs "Find all subs defined in a package.")
1161 (mod-decls "Generate declarations for subs in a package.")
1162 (mod-file "Find the file defining a package.")
1163 (apropos "Find subnames matching RE.")
1164 (lexicals "Find lexicals for a sub.")
1165 (apropos-module "Find installed modules matching RE.")
1167 (apply #'define-xref-function "Sepia" x))
1169 (dolist (x '((rebuild "Build Xref database for current Perl process.")
1170 (redefined "Rebuild Xref information for a given sub.")
1172 (callers "Find all callers of a function.")
1173 (callees "Find all functions called by a function.")
1175 (var-apropos "Find varnames matching RE.")
1176 (mod-apropos "Find modules matching RE.")
1177 (file-apropos "Find files matching RE.")
1179 (var-defs "Find all definitions of a variable.")
1180 (var-assigns "Find all assignments to a variable.")
1181 (var-uses "Find all uses of a variable.")
1183 (mod-redefined "Rebuild Xref information for a given package.")
1184 (guess-module-file "Guess file corresponding to module.")
1185 (file-modules "List the modules defined in a file.")))
1186 (apply #'define-xref-function "Sepia::Xref" x))
1187 ;; Initialize built hash
1188 (sepia-init-perl-builtins)))
1190 (defvar sepia-scratchpad-mode-map
1191 (let ((map (make-sparse-keymap)))
1192 (set-keymap-parent map sepia-mode-map)
1193 (define-key map "\C-j" 'sepia-scratch-send-line)
1194 map))
1196 ;;;###autoload
1197 (define-derived-mode sepia-scratchpad-mode sepia-mode "Sepia-Scratch"
1198 "Major mode for the Perl scratchpad, derived from Sepia mode."
1199 (sepia-init))
1201 ;;;###autoload
1202 (defun sepia-scratch ()
1203 "Switch to the sepia scratchpad."
1204 (interactive)
1205 (pop-to-buffer
1206 (or (get-buffer "*sepia-scratch*")
1207 (with-current-buffer (get-buffer-create "*sepia-scratch*")
1208 (sepia-scratchpad-mode)
1209 (current-buffer)))))
1211 (defun sepia-scratch-send-line (&optional scalarp)
1212 "Send the current line to perl, and display the result."
1213 (interactive "P")
1214 (insert
1215 (format "\n%s\n"
1216 (car
1217 (sepia-eval-raw
1218 (concat "$Sepia::REPL{eval}->(q#"
1219 (buffer-substring (sepia-bol-from (point))
1220 (sepia-eol-from (point))) "#)"))))))
1222 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1223 ;; Miscellany
1225 (defun sepia-indent-line (&rest args)
1226 "Unbind `beginning-of-defun-function' to not confuse `cperl-indent-line'."
1227 (let (beginning-of-defun-function)
1228 (apply #'cperl-indent-line args)))
1230 (defun sepia-string-count-matches (reg str)
1231 (let ((n 0)
1232 (pos -1))
1233 (while (setq pos (string-match reg str (1+ pos)))
1234 (incf n))
1237 (defun sepia-perlize-region-internal (pre post beg end replace-p)
1238 "Pass buffer text from BEG to END through a Perl command."
1239 (let* ((exp (concat pre "<<'SEPIA_END_REGION';\n"
1240 (buffer-substring-no-properties beg end)
1241 (if (= (char-before end) ?\n) "" "\n")
1242 "SEPIA_END_REGION\n" post))
1243 (new-str (car (sepia-eval-raw exp))))
1244 (if replace-p
1245 (progn (delete-region beg end)
1246 (goto-char beg)
1247 (insert new-str))
1248 (if (> (sepia-string-count-matches "\n" new-str) 2)
1249 (with-current-buffer (get-buffer-create "*sepia-filter*")
1250 (let ((inhibit-read-only t))
1251 (erase-buffer)
1252 (insert new-str)
1253 (goto-char (point-min))
1254 (pop-to-buffer (current-buffer))))
1255 (message "%s" new-str)))))
1257 (defun sepia-eol-from (pt &optional n)
1258 (save-excursion
1259 (goto-char pt)
1260 (end-of-line n)
1261 (point)))
1263 (defun sepia-bol-from (pt &optional n)
1264 (save-excursion
1265 (goto-char pt)
1266 (beginning-of-line n)
1267 (point)))
1269 (defun sepia-perl-pe-region (expr beg end &optional replace-p)
1270 "Do the equivalent of perl -pe on region
1272 \(i.e. evaluate an expression on each line of region). With
1273 prefix arg, replace the region with the result."
1274 (interactive "MExpression: \nr\nP")
1275 (sepia-perlize-region-internal
1276 "do { my $ret=''; local $_; local $/ = \"\\n\"; my $region = "
1277 (concat "; for (split /(?<=\\n)/, $region, -1) { " expr
1278 "} continue { $ret.=$_}; $ret}")
1279 (sepia-bol-from beg) (sepia-eol-from end) replace-p))
1281 (defun sepia-perl-ne-region (expr beg end &optional replace-p)
1282 "Do the moral equivalent of perl -ne on region
1284 \(i.e. evaluate an expression on each line of region). With
1285 prefix arg, replace the region with the result."
1286 (interactive "MExpression: \nr\nP")
1287 (sepia-perlize-region-internal
1288 "do { my $ret='';my $region = "
1289 (concat "; for (split /(?<=\\n)/, $region, -1) { $ret .= do { " expr
1290 ";} }; ''.$ret}")
1291 (sepia-bol-from beg) (sepia-eol-from end) replace-p))
1293 (defun sepia-perlize-region (expr beg end &optional replace-p)
1294 "Evaluate a Perl expression on the region as a whole.
1296 With prefix arg, replace the region with the result."
1297 (interactive "MExpression: \nr\nP")
1298 (sepia-perlize-region-internal
1299 "do { local $_ = " (concat "; do { " expr ";}; $_ }") beg end replace-p))
1301 (defun sepia-core-version (module &optional message)
1302 "Report the first version of Perl shipping with MODULE."
1303 (interactive (list (sepia-interactive-arg 'module) t))
1304 (let* ((version
1305 (sepia-eval
1306 (format "eval { Sepia::core_version('%s') }" module)
1307 'scalar-context))
1308 (res (if version
1309 (format "%s was first released in %s." module version)
1310 (format "%s is not in core." module))))
1311 (when message (message "%s" res))
1312 res))
1314 (defun sepia-guess-package (sub &optional file)
1315 "Guess which package SUB is defined in."
1316 (let ((defs (xref-location (xref-apropos sub))))
1317 (or (and (= (length defs) 1)
1318 (or (not file) (equal (caar defs) file))
1319 (fourth (car defs)))
1320 (and file
1321 (fourth (find-if (lambda (x) (equal (car x) file)) defs)))
1322 ;; (car (xref-file-modules file))
1323 (sepia-buffer-package))))
1325 ;;;###autoload
1326 (defun sepia-apropos-module (name)
1327 "List installed modules matching a regexp."
1328 (interactive "MList modules matching regexp: ")
1329 (let ((res (xref-apropos-module name)))
1330 (if res
1331 (with-output-to-temp-buffer "*Modules*"
1332 (display-completion-list res))
1333 (message "No modules matching %s." name))))
1335 ;;;###autoload
1336 (defun sepia-eval-defun ()
1337 "Re-evaluate the current function and rebuild its Xrefs."
1338 (interactive)
1339 (let (pt end beg sub res
1340 sepia-eval-package
1341 sepia-eval-file
1342 sepia-eval-line)
1343 (save-excursion
1344 (setq pt (point)
1345 end (progn (end-of-defun) (point))
1346 beg (progn (beginning-of-defun) (point)))
1347 (goto-char beg)
1348 (when (looking-at "^sub\\s +\\(.+\\_>\\)")
1349 (setq sub (match-string 1))
1350 (let ((body (buffer-substring-no-properties beg end)))
1352 (setq sepia-eval-package (sepia-guess-package sub (buffer-file-name))
1353 sepia-eval-file (buffer-file-name)
1354 sepia-eval-line (line-number-at-pos beg)
1356 (sepia-eval-raw
1357 (if sepia-eval-defun-include-decls
1358 (concat
1359 (apply #'concat (xref-mod-decls sepia-eval-package))
1360 body)
1361 body))))))
1362 (if (cdr res)
1363 (progn
1364 (when (string-match " line \\([0-9]+\\), near \"\\([^\"]*\\)\""
1365 (cdr res))
1366 (goto-char beg)
1367 (beginning-of-line (string-to-number (match-string 1 (cdr res))))
1368 (search-forward (match-string 2 (cdr res))
1369 (sepia-eol-from (point)) t))
1370 (message "Error: %s" (cdr res)))
1371 (xref-redefined sub sepia-eval-package)
1372 (message "Defined %s" sub))))
1374 ;;;###autoload
1375 (defun sepia-eval-expression (expr &optional list-p message-p)
1376 "Evaluate EXPR in scalar context."
1377 (interactive (list (read-string "Expression: ") current-prefix-arg t))
1378 (let ((res (sepia-eval expr (if list-p 'list-context 'scalar-context))))
1379 (when message-p (message "%s" res))
1380 res))
1382 (defun sepia-extract-def (file line obj)
1383 (with-current-buffer (find-file-noselect (expand-file-name file))
1384 (save-excursion
1385 (funcall (sepia-refiner 'function) line obj)
1386 (beginning-of-line)
1387 (when (looking-at (concat "^\\s *sub\\_>.*\\_<" obj "\\_>"))
1388 (buffer-substring (point)
1389 (progn (end-of-defun) (point)))))))
1391 (defun sepia-eval-no-run (string)
1392 (let ((res (sepia-eval-raw
1393 (concat "eval q#{ BEGIN { use B; B::minus_c(); $^C=1; } do { "
1394 string
1395 " };BEGIN { die \"ok\\n\" }#, $@"))))
1396 (if (string-match "^ok\n" (car res))
1398 (car res))))
1400 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1401 ;; REPL
1403 (defvar sepia-eval-file nil
1404 "File in which `sepia-eval' evaluates perl expressions.")
1405 (defvar sepia-eval-line nil
1406 "Line at which `sepia-eval' evaluates perl expressions.")
1408 (defun sepia-set-cwd (dir)
1409 "Set the inferior Perl process's working directory to DIR.
1411 When called interactively, the current buffer's
1412 `default-directory' is used."
1413 (interactive (list (expand-file-name default-directory)))
1414 (sepia-call "Cwd::chdir" 'list-context dir))
1416 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1417 ;; Doc-scanning
1419 (defvar sepia-doc-map (make-hash-table :test #'equal))
1420 (defvar sepia-var-doc-map (make-hash-table :test #'equal))
1421 (defvar sepia-module-doc-map (make-hash-table :test #'equal))
1422 (defvar sepia-skip-doc-scan nil)
1424 (defun sepia-doc-scan-buffer ()
1425 ;; too many confusing things in perldiag, so just give up.
1426 (when (or sepia-skip-doc-scan
1427 (and (buffer-file-name)
1428 (string-match "perldiag\\.pod$" (buffer-file-name))))
1429 (return nil))
1430 (save-excursion
1431 (goto-char (point-min))
1432 (loop
1433 while (re-search-forward
1434 "^=\\(item\\|head[2-9]\\)\\s +\\([%$&@A-Za-z_].*\\)" nil t)
1436 (ignore-errors
1437 (let ((short (match-string 2)) longdoc)
1438 (setq short
1439 (let ((case-fold-search nil))
1440 (replace-regexp-in-string
1441 "E<lt>" "<"
1442 (replace-regexp-in-string
1443 "E<gt>" ">"
1444 (replace-regexp-in-string
1445 "[A-DF-Z]<\\([^<>]+\\)>" "\\1" short)))))
1446 (while (string-match "^\\s *[A-Z]<\\(.*\\)>\\s *$" short)
1447 (setq short (match-string 1 short)))
1448 (setq longdoc
1449 (let ((beg (progn (forward-line 2) (point)))
1450 (end (1- (re-search-forward "^=" nil t))))
1451 (forward-line -1)
1452 (goto-char beg)
1453 (if (re-search-forward "^\\(.+\\)$" end t)
1454 (concat short ": "
1455 (substring-no-properties
1456 (match-string 1)
1457 0 (position ?. (match-string 1))))
1458 short)))
1459 (cond
1460 ;; e.g. "$x -- this is x"
1461 ((string-match "^[%$@]\\([A-Za-z0-9_:]+\\)\\s *--\\s *\\(.*\\)"
1462 short)
1463 (list 'variable (match-string-no-properties 1 short)
1464 (or (and (equal short (match-string 1 short)) longdoc)
1465 short)))
1466 ;; e.g. "C<foo(BLAH)>" or "$x = $y->foo()"
1467 ((string-match "^\\([A-Za-z0-9_:]+\\)\\s *\\(\\$\\|(\\)" short)
1468 (list 'function (match-string-no-properties 1 short)
1469 (or (and (equal short (match-string 1 short)) longdoc)
1470 short)))
1471 ;; e.g. "C<$result = foo $args...>"
1472 ((string-match "^[%@$*][A-Za-z0-9_:]+\\s *=\\s *\\([A-Za-z0-9_:]+\\)" short)
1473 (list 'function (match-string-no-properties 1 short)
1474 (or (and (equal short (match-string 1 short)) longdoc)
1475 short)))
1476 ;; e.g. "$x this is x" (note: this has to come last)
1477 ((string-match "^[%$@]\\([^( ]+\\)" short)
1478 (list 'variable (match-string-no-properties 1 short) longdoc)))))
1479 collect it)))
1481 (defun sepia-buffer-package ()
1482 (save-excursion
1483 (or (and (re-search-backward "^\\s *package\\s +\\([^ ;]+\\)\\s *;" nil t)
1484 (match-string-no-properties 1))
1485 "main")))
1487 (defun sepia-doc-update ()
1488 "Update documentation for a file.
1490 This documentation, taken from \"=item\" entries in the POD, is
1491 used for eldoc feedback. Set the file variable
1492 `sepia-skip-doc-scan' to non-nil to skip scanning this buffer.
1493 This can be used to avoid generating bogus documentation from
1494 files like perldiag.pod."
1495 (interactive)
1496 (let ((pack (ifa (sepia-buffer-package) (concat it "::") "")))
1497 (dolist (x (sepia-doc-scan-buffer))
1498 (let ((map (ecase (car x)
1499 (function sepia-doc-map)
1500 (variable sepia-var-doc-map))))
1501 (puthash (second x) (third x) map)
1502 (puthash (concat pack (second x)) (third x) map)))))
1504 (defun sepia-looks-like-module (obj)
1505 (let (case-fold-search)
1506 (or (string-match
1507 (eval-when-compile (regexp-opt '("strict" "vars" "warnings" "lib")))
1508 obj)
1509 (and
1510 (string-match "^\\([A-Z][A-Za-z0-9]*::\\)*[A-Z]+[A-Za-z0-9]+\\sw*$" obj)))))
1512 (defun sepia-describe-object (thing)
1513 "Display documentation for `thing', like ``describe-function'' for elisp."
1514 (interactive
1515 (let ((id (sepia-ident-at-point)))
1516 (when (string= (cadr id) "")
1517 (setq id (sepia-ident-before-point)))
1518 (if (car id)
1519 (list id)
1520 (cdr id))))
1521 (cond
1522 ((listp thing)
1523 (setq thing (format "%c%s" (car thing) (cadr thing)))
1524 (with-current-buffer (get-buffer-create "*sepia-help*")
1525 (let ((inhibit-read-only t))
1526 (erase-buffer)
1527 (shell-command (concat "perldoc -v " (shell-quote-argument thing))
1528 (current-buffer))
1529 (view-mode 1)
1530 (goto-char (point-min)))
1531 (unless (looking-at "No documentation for")
1532 (pop-to-buffer "*sepia-help*" t))))
1533 ((gethash thing sepia-perl-builtins)
1534 (with-current-buffer (get-buffer-create "*sepia-help*")
1535 (let ((inhibit-read-only t))
1536 (erase-buffer)
1537 (shell-command (concat "perldoc -f " thing) (current-buffer))
1538 (view-mode 1)
1539 (goto-char (point-min))))
1540 (pop-to-buffer "*sepia-help*" t))))
1542 (defun sepia-symbol-info (&optional obj type)
1543 "Eldoc function for `sepia-mode'.
1545 Looks in `sepia-doc-map' and `sepia-var-doc-map', then tries
1546 calling `cperl-describe-perl-symbol'."
1547 (unless obj
1548 (multiple-value-bind (ty ob) (sepia-ident-at-point)
1549 (setq obj (if (consp ob) (car ob) ob)
1550 type ty)))
1551 (if obj
1552 (or (gethash obj (ecase (or type ?&)
1553 (?& sepia-doc-map)
1554 ((?$ ?@ ?%) sepia-var-doc-map)
1555 (nil sepia-module-doc-map)
1556 (?* sepia-module-doc-map)
1557 (t (error "sepia-symbol-info: %s" type))))
1558 ;; Loathe cperl a bit.
1559 (flet ((message (&rest blah) (apply #'format blah)))
1560 (let* (case-fold-search
1561 (cperl-message-on-help-error nil)
1562 (hlp (car (save-excursion
1563 (cperl-describe-perl-symbol
1564 (if (member type '(?$ ?@ ?%))
1565 (format "%c%s" type obj)
1566 obj))))))
1567 (if hlp
1568 (progn
1569 ;; cperl's docstrings are too long.
1570 (setq hlp (replace-regexp-in-string "\\s \\{2,\\}\\|\t" " " hlp))
1571 (if (> (length hlp) 75)
1572 (concat (substring hlp 0 72) "...")
1573 hlp))
1574 ;; Try to see if it's a module
1575 (if (and
1576 (let ((bol (save-excursion (beginning-of-line)
1577 (point))))
1578 (looking-back " *\\(?:use\\|require\\|package\\|no\\)\\s +[^ ]*" bol))
1579 (sepia-looks-like-module obj))
1580 (sepia-core-version obj)
1581 ""))))
1582 "")))
1584 (defun sepia-install-eldoc ()
1585 "Install Sepia hooks for eldoc support.
1587 This automatically disables `cperl-lazy-installed', the
1588 `cperl-mode' reimplementation of eldoc."
1589 (interactive)
1590 (require 'eldoc)
1591 (set-variable 'eldoc-documentation-function 'sepia-symbol-info t)
1592 (if cperl-lazy-installed (cperl-lazy-unstall))
1593 (eldoc-mode 1)
1594 (set-variable 'eldoc-idle-delay 1.0 t))
1596 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1597 ;; Error jump:
1599 (defun sepia-extract-next-warning (pos &optional end)
1600 (catch 'foo
1601 (while (re-search-forward "^\\(.+\\) at \\(.+?\\) line \\([0-9]+\\)"
1602 end t)
1603 (unless (string= "(eval " (substring (match-string 2) 0 6))
1604 (throw 'foo (list (match-string 2)
1605 (string-to-number (match-string 3))
1606 (match-string 1)))))))
1608 (defun sepia-goto-error-at (pos)
1609 "Visit the source of the error on line at point."
1610 (interactive "d")
1611 (ifa (sepia-extract-next-warning (sepia-bol-from pos) (sepia-eol-from pos))
1612 (destructuring-bind (file line msg) it
1613 (find-file file)
1614 (goto-line line)
1615 (message "%s" msg))
1616 (error "No error to find.")))
1618 (defun sepia-display-errors (beg end)
1619 "Display source causing errors in current buffer from BEG to END."
1620 (interactive "r")
1621 (goto-char beg)
1622 (let ((msgs nil))
1623 (loop for w = (sepia-extract-next-warning (sepia-bol-from (point)) end)
1624 while w
1625 do (destructuring-bind (file line msg) w
1626 (push (format "%s:%d:%s\n" (abbreviate-file-name file) line msg)
1627 msgs)))
1628 (erase-buffer)
1629 (goto-char (point-min))
1630 (mapc #'insert (nreverse msgs))
1631 (goto-char (point-min))
1632 (grep-mode)))
1634 (defun sepia-lisp-to-perl (thing)
1635 "Convert elisp data structure to Perl."
1636 (cond
1637 ((null thing) "undef")
1638 ((symbolp thing)
1639 (let ((pname (substitute ?_ ?- (symbol-name thing)))
1640 (type (string-to-char (symbol-name thing))))
1641 (if (member type '(?% ?$ ?@ ?*))
1642 pname
1643 (concat "\\*" pname))))
1644 ((stringp thing) (format "%S" (substring-no-properties thing 0)))
1645 ((integerp thing) (format "%d" thing))
1646 ((numberp thing) (format "%g" thing))
1647 ;; Perl expression
1648 ((and (consp thing) (eq (car thing) 'expr))
1649 (cdr thing)) ; XXX -- need quoting??
1650 ((and (consp thing) (not (consp (cdr thing))))
1651 (concat (sepia-lisp-to-perl (car thing)) " => "
1652 (sepia-lisp-to-perl (cdr thing))))
1653 ;; list
1654 ((or (not (consp (car thing)))
1655 (listp (cdar thing)))
1656 (concat "[" (mapconcat #'sepia-lisp-to-perl thing ", ") "]"))
1657 ;; hash table
1659 (concat "{" (mapconcat #'sepia-lisp-to-perl thing ", ") "}"))))
1661 (defun sepia-find-loaded-modules ()
1662 (interactive)
1663 "Visit all source files loaded by the currently-running Perl.
1665 Currently, this means any value of %INC matching /.p[lm]$/."
1666 (dolist (file (sepia-eval "values %INC" 'list-context))
1667 (when (string-match "\\.p[lm]$" file)
1668 (find-file-noselect file t))))
1670 (defun sepia-dired-package (package)
1671 (interactive "sPackage: ")
1672 "Browse files installed by `package'.
1674 Create a `dired-mode' buffer listing all flies installed by `package'."
1675 ;; XXX group by common prefix and use /^ DIRECTORY:$/ format
1676 (let ((ls (sort #'string<
1677 (sepia-call "Sepia::file_list" 'list-context package)))
1679 maxlen)
1680 (setq maxlen (apply #'max (mapcar #'length ls)))
1681 (with-current-buffer (get-buffer-create (format "*Package %s*" package))
1682 (let ((inhibit-read-only t)
1683 marker)
1684 ;; Start with a clean slate
1685 (erase-buffer)
1686 (setq marker (point-min-marker))
1687 (set (make-local-variable 'dired-subdir-alist) nil)
1688 ;; Build up the contents
1689 (while ls
1690 ;; Find a decent prefix
1691 (setq pfx (try-completion "" ls))
1692 (unless (file-exists-p pfx)
1693 (string-match "^\\(.*/\\)" pfx)
1694 (setq pfx (match-string 1 pfx)))
1695 ;; If we found a lousy prefix, chew off the first few paths and
1696 ;; try again. XXX not done.
1697 (insert (format " %s:\n" pfx))
1698 (setq default-directory pfx)
1699 (apply 'call-process "/bin/ls" nil (current-buffer) t
1700 (cons "-lR" (mapcar
1701 (lambda (x)
1702 (replace-regexp-in-string
1703 (concat pfx "?") "" x))
1704 ls)))
1705 (push `((,default-directory . ,marker)) dired-subdir-alist)
1706 (setq ls nil))
1707 (dired-mode pfx)
1708 (pop-to-buffer (current-buffer))))))
1710 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1711 ;;; Follow POD links from source
1713 (defun sepia-pod-follow-link-at-point (str src)
1714 "Follow a POD-style link.
1716 If called interactively, follow link at point, or prompt if no
1717 such link exists. With prefix argument, view formatted
1718 documentation with `sepia-perldoc-this'; otherwise, view raw
1719 documentation source."
1720 (interactive (list
1721 (or (sepia-pod-link-at-point (point))
1722 (read-string "Link: "))
1723 (not current-prefix-arg)))
1724 (sepia-pod-follow-link str src))
1726 (defun sepia-pod-follow-link (str &optional src)
1727 "Follow link STR to documentation, or to source of documentation if SRC.
1729 For URL links (e.g. L<http://www.emacs.org/>), always follow the
1730 link using `browse-url'."
1731 ;; strip off L<...>
1732 (when (string-match "^L<\\(.*\\)>$" str)
1733 (setq str (match-string 1 str)))
1734 ;; strip out text|...
1735 (when (string-match "[^/\"|]+|\\(.*\\)" str)
1736 (setq str (match-string 1 str)))
1737 (cond
1738 ;; URL -- no way to "jump to source"
1739 ((string-match "^[a-z]+:.+" str)
1740 ;; view the URL -- there's no "source"
1741 (browse-url str))
1743 ;; name/sec
1744 ((string-match "^\\([^/\"]+\\)/\"?\\([^\"]+\\)\"?$" str)
1745 ;; open the POD, then go to the section
1746 ;; -- `M-. d' or `M-. m', plus jump
1747 (let ((page (match-string 1 str))
1748 (sec (match-string 2 str)))
1749 (sepia-perldoc-this page)
1750 (if src
1751 (let (target)
1752 (sepia-module-find page)
1753 (save-excursion
1754 (goto-char (point-min))
1755 (if (search-forward (concat "^=.*" sec) nil t)
1756 (goto-char target)
1757 (message "Can't find anchor for %s." str))))
1758 (w3m-search-name-anchor sec))))
1760 ;; /"sec" or /sec or "sec"
1761 ((or (string-match "^/\"?\\([^\"]+\\)\"?$" str)
1762 (string-match "^\"\\([^\"]+\\)\"$" str))
1763 ;; jump to POD header in current file or in displayed POD
1764 (let ((sec (match-string 1 str)))
1765 (if src
1766 (let (target)
1767 (save-excursion
1768 (goto-char (point-min))
1769 (unless (search-forward (concat "^=.*" sec) nil t)
1770 (error "Can't find anchor for %s." str))
1771 (setq target (match-beginning)))
1772 (and target (goto-char target)))
1773 (sepia-view-pod)
1774 (w3m-search-name-anchor (match-string 1 str)))))
1776 ;; name
1777 ((string-match "^[^/\"]+$" str)
1778 ;; view the pod
1779 ;; -- `M-. d' or `M-. m'
1780 (if src
1781 (sepia-module-find str)
1782 (sepia-perldoc-this str)))
1783 (t (error "Can't understand POD link %s." str))))
1785 (defun sepia-pod-link-at-point (p)
1786 "Extract POD link at point, or nil."
1787 (let* ((bol (save-excursion (forward-line 0) (point)))
1788 (eol (save-excursion (forward-line 1) (backward-char 1) (point)))
1789 (beg (or (save-excursion
1790 (forward-char 1) ;in case we're on < of L<
1791 (search-backward "L<" bol t)) p))
1792 (end (save-excursion (search-forward ">" eol t))))
1793 (if (and beg end) (buffer-substring-no-properties (+ beg 2) (1- end))
1794 nil)))
1796 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1797 ;;; Fight CPerl a bit -- it can be opinionated
1799 (defadvice cperl-imenu--create-perl-index (after simplify compile activate)
1800 "Make cperl's imenu index simpler."
1801 (flet ((annoying (x)
1802 (dolist (y '("Rescan" "^\\+Unsorted" "^\\+Packages"))
1803 (when (string-match y (car x))
1804 (return-from annoying t)))
1805 nil))
1806 (setq ad-return-value (remove-if #'annoying ad-return-value))))
1808 ;; (defun sepia-view-mode-hook ()
1809 ;; "Let backspace scroll again.
1811 ;; XXX Unused, yet."
1812 ;; (local-unset-key (kbd "<backspace>")))
1814 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1815 ;;; __DATA__
1817 (defun sepia-init-perl-builtins ()
1818 (setq sepia-perl-builtins (make-hash-table :test #'equal))
1819 (dolist (s '(
1820 "abs"
1821 "accept"
1822 "alarm"
1823 "atan2"
1824 "bind"
1825 "binmode"
1826 "bless"
1827 "caller"
1828 "chdir"
1829 "chmod"
1830 "chomp"
1831 "chop"
1832 "chown"
1833 "chr"
1834 "chroot"
1835 "close"
1836 "closedir"
1837 "connect"
1838 "continue"
1839 "cos"
1840 "crypt"
1841 "dbmclose"
1842 "dbmopen"
1843 "defined"
1844 "delete"
1845 "die"
1846 "dump"
1847 "each"
1848 "endgrent"
1849 "endhostent"
1850 "endnetent"
1851 "endprotoent"
1852 "endpwent"
1853 "endservent"
1854 "eof"
1855 "eval"
1856 "exec"
1857 "exists"
1858 "exit"
1859 "exp"
1860 "fcntl"
1861 "fileno"
1862 "flock"
1863 "fork"
1864 "format"
1865 "formline"
1866 "getc"
1867 "getgrent"
1868 "getgrgid"
1869 "getgrnam"
1870 "gethostbyaddr"
1871 "gethostbyname"
1872 "gethostent"
1873 "getlogin"
1874 "getnetbyaddr"
1875 "getnetbyname"
1876 "getnetent"
1877 "getpeername"
1878 "getpgrp"
1879 "getppid"
1880 "getpriority"
1881 "getprotobyname"
1882 "getprotobynumber"
1883 "getprotoent"
1884 "getpwent"
1885 "getpwnam"
1886 "getpwuid"
1887 "getservbyname"
1888 "getservbyport"
1889 "getservent"
1890 "getsockname"
1891 "getsockopt"
1892 "glob"
1893 "gmtime"
1894 "goto"
1895 "grep"
1896 "hex"
1897 "import"
1898 "index"
1899 "int"
1900 "ioctl"
1901 "join"
1902 "keys"
1903 "kill"
1904 "last"
1905 "lc"
1906 "lcfirst"
1907 "length"
1908 "link"
1909 "listen"
1910 "local"
1911 "localtime"
1912 "log"
1913 "lstat"
1914 "map"
1915 "mkdir"
1916 "msgctl"
1917 "msgget"
1918 "msgrcv"
1919 "msgsnd"
1920 "next"
1921 "oct"
1922 "open"
1923 "opendir"
1924 "ord"
1925 "pack"
1926 "package"
1927 "pipe"
1928 "pop"
1929 "pos"
1930 "print"
1931 "printf"
1932 "prototype"
1933 "push"
1934 "quotemeta"
1935 "rand"
1936 "read"
1937 "readdir"
1938 "readline"
1939 "readlink"
1940 "readpipe"
1941 "recv"
1942 "redo"
1943 "ref"
1944 "rename"
1945 "require"
1946 "reset"
1947 "return"
1948 "reverse"
1949 "rewinddir"
1950 "rindex"
1951 "rmdir"
1952 "scalar"
1953 "seek"
1954 "seekdir"
1955 "select"
1956 "semctl"
1957 "semget"
1958 "semop"
1959 "send"
1960 "setgrent"
1961 "sethostent"
1962 "setnetent"
1963 "setpgrp"
1964 "setpriority"
1965 "setprotoent"
1966 "setpwent"
1967 "setservent"
1968 "setsockopt"
1969 "shift"
1970 "shmctl"
1971 "shmget"
1972 "shmread"
1973 "shmwrite"
1974 "shutdown"
1975 "sin"
1976 "sleep"
1977 "socket"
1978 "socketpair"
1979 "sort"
1980 "splice"
1981 "split"
1982 "sprintf"
1983 "sqrt"
1984 "srand"
1985 "stat"
1986 "study"
1987 "sub"
1988 "sub*"
1989 "substr"
1990 "symlink"
1991 "syscall"
1992 "sysopen"
1993 "sysread"
1994 "sysseek"
1995 "system"
1996 "syswrite"
1997 "tell"
1998 "telldir"
1999 "tie"
2000 "tied"
2001 "time"
2002 "times"
2003 "truncate"
2004 "uc"
2005 "ucfirst"
2006 "umask"
2007 "undef"
2008 "unlink"
2009 "unpack"
2010 "unshift"
2011 "untie"
2012 "utime"
2013 "values"
2014 "vec"
2015 "wait"
2016 "waitpid"
2017 "wantarray"
2018 "warn"
2019 "write"
2021 (puthash s t sepia-perl-builtins)))
2023 (provide 'sepia)
2024 ;;; sepia.el ends here