Sepia-0.992/000755 000765 000765 00000000000 11661034124 013062 5ustar00seanoseano000000 000000 Sepia-0.992/ChangeLog000644 000765 000765 00000074020 11661033657 014651 0ustar00seanoseano000000 000000 2011-11-16 Sean O'Rourke * VERSION: 0.992 2011-11-14 Sean O'Rourke * sepl: add some docs. 2011-11-10 Sean O'Rourke * lib/Sepia.pm (repl_who): list lexicals in strict-mode. (repl_eval,repl_strict,call_strict): eliminate Lexical::Persistence, which is more trouble than it's worth. (repl_size): list lexical sizes in strict-mode. 2011-11-02 Sean O'Rourke * lib/Sepia/ReadLine.pm (rl_complete): Unify T:R:{Perl,GNU} 2011-10-24 Sean O'Rourke * sepia.el (sepia-[be]ol-from): use line-{beginning,end}-position. (sepia-shared-map): remap C-c C-t to cperl-invert-if-unless. 2011-10-23 Sean O'Rourke * lib/Sepia/ReadLine.pm (repl): support Term::ReadLine::Perl. 2011-10-07 Sean O'Rourke * sepia.texi (Navigation): add sepia-pod-follow-link-at-point and associated key-reshuffling. * sepia.el (sepia-pod-follow-link-at-point): new function to follow POD links from source. (sepia-metapoint-map): shuffle keys for sepia-pod-follow-link-at-point. 2011-03-20 Sean O'Rourke * lib/Sepia/Xref.pm: POD fix. * Makefile.PL: don't install .elc files, since that breaks Debian. Patches from Hilko Bengen. 2011-03-14 Sean O'Rourke * VERSION: 0.991_05 (testing). * sepl: add to MANIFEST 2011-03-14 Sean O'Rourke * VERSION: 0.991_04 (testing). * Makefile.PL (prompt_for_infodir): filter out Emacs-spam. 2010-11-05 Sean O'Rourke * sepia.el (sepia-next, sepia-show-locations,sepia-set-found): Always use next-error. * sepia-w3m.el (w3m-about-perldoc-buffer): let user know when there are POD errors. 2010-10-04 Sean O'Rourke * sepia.el (sepia-perldoc-this): Display documentation in a less annoying way. (cperl-imenu--create-perl-index): Advise it to strip out some entries. * Sepia.pm: dumpvar.pl and Devel::Peek format options. 2010-09-21 Sean O'Rourke * lib/Sepia.pm (track_requires): New function. (file_list): New function. Add 'dumpvar' flavor of output. (repl_lsmod): New function. (requires,users): Use track_requires. * sepia.el (sepia-dired-package): New function. (sepia-skip-doc-scan): New variable. (sepia-doc-update): Use previous to skip confusing files. (sepia-find-loaded-modules): New function. (cperl-imenu--create-perl-index): Filter cruft. 2010-09-13 Sean O'Rourke * sepia.el (sepia-doc-scan-buffer): Avoid spurious matches. (sepia-find-loaded-modules): New function. 2010-09-12 Sean O'Rourke * lib/Sepia.pm (repl_strict): Disable Lexical::Persistence's stupid treatment of '_'. 2010-08-18 Sean O'Rourke * lib/Sepia.pm: remove useless @REPL_RESULT. Fix _() to use @res. 2010-08-16 Sean O'Rourke * sepia.el (sepia-shared-map, sepia-eval-region): new function bound to `C-c C-r', moving sepia-repl to `C-c C-t'. * lib/Sepia.pm: disable deprecation warnings to avoid 5.12 lameness. 2010-02-08 Sean O'Rourke * sepia.el (sepia-looks-like-module): remove apropos-module check. * lib/Sepia.pm (_apropos_re): make start anchor optional. (inc_re): factor out @INC-removal. (module_list): use inc_re(). (modules_matching): new function. (apropos_module): rewrite. 2010-01-24 Sean O'Rourke * lib/Sepia.pm (repl_setup): load ~/.sepiarc in $Sepia::PACKAGE. 2010-01-23 Sean O'Rourke * README: add development information. * lib/Sepia.pm (apropos_module): use "_apropos_re" 2009-12-15 Sean O'Rourke * lib/Sepia.pm (repl_package): always change packages, even if empty. 2009-12-14 Sean O'Rourke * lib/Sepia/ReadLine.pm: readline interface. * lib/Sepia.pm ($READLINE): next-input hook. 2009-12-08 Sean O'Rourke * lib/Sepia.pm (methods): uniquify. * lib/Sepia.pm, lib/Sepia/Debug.pm: avoid deprecated "defined %hash" in 5.11.x. 2009-12-02 Sean O'Rourke * lib/Sepia/Xref.pm (load_pad): work around pad weirdness with threads. * VERSION: 0.991_01 2009-11-29 Sean O'Rourke * Makefile.PL: make LWP::Simple optional. It didn't do much. * sepia-snippet.el (sepia-snippet-abbrev): de-dup, sort, add given/when. * sepia.el (sepia-shortcuts): update. (sepia-complete-symbol): fix sigil duplication bug. (sepia-symbol-info): use cperl's variable short-docs. 2009-11-26 Sean O'Rourke * lib/Sepia.pm: reorganize, add docs. * sepia.texi (Shortcuts): document ,time * Makefile.PL: optional BSD::Resource and Time::HiRes. * lib/Sepia.pm (run_hook,add_hook,remove_hook): new functions. (repl_time,time_pre_prompt*): print CPU times. 2009-11-25 Sean O'Rourke * sepia.el (sepia-ident-before-point): use s-i-at-point. (sepia-ident-at-point): Handle punctuation variables. (sepia-describe-object): add "perldoc -v" support. 2009-11-22 Sean O'Rourke * lib/Sepia.pm (location): handle special @INC entries. * sepia.el (sepia-describe-object): Guess identifier-at-point in the right order. 2009-11-18 Sean O'Rourke * sepia.el (sepia-describe-object): new function like describe-function and friends. Currently only "perldoc -f." (sepia-init-perl-builtins): bugfix. (sepia-repl-mode): turn on eldoc. 2009-11-02 Sean O'Rourke * lib/Sepia.pm (location): change to work on only one location, since that's how it's used. (define_shortcuts): tweak. (repl_setup): fix $REPL_LEVEL bug. (repl,repl_quit): make quitting from restarted REPLs. 2009-10-28 Sean O'Rourke * sepia.el (sepia-indent-or-complete): work around bug where expand-abbrev returns nil even though it expanded. (sepia-looks-like-module): use xref-apropos-module. 2009-10-19 Sean O'Rourke * sepia-cpan.el (sepia-cpan-mode-map): initialize in definition; oops! * VERSION: 0.991 2009-10-18 Sean O'Rourke * lib/Sepia/CPAN.pm (group_by_dist): better heuristic. * lib/Sepia.pm (repl_reload, repl_full_reload, full_reload): support "reload" and "freload" shortcuts. * lib/Sepia/Debug.pm (xreturn, repl_xreturn): return-from-context, not yet used. * VERSION: 0.99 2009-10-12 Sean O'Rourke * sepia.el (sepia-symbol-info): tweak on module names. (sepia-apropos-module): new function. (sepia-perlize-region,sepia-perl-ne-region): interactive prompt fix 2009-07-22 Sean O'Rourke * sepia-cpan.el (sepia-cpan-doc): make browser pop up in other window, like README. 2009-07-18 Sean O'Rourke * lib/Sepia.pm (filter_exact_prefix): new function to improve completion behavior. 2009-07-07 Sean O'Rourke * lib/Sepia.pm (save,load,repl_save,repl_load): Persist variables to a file. * VERSION: 0.99_01 2009-07-05 Sean O'Rourke * sepia.el (sepia-rename-lexical): New function; a small wrapper around query-replace(-regexp). 2009-05-03 Sean O'Rourke * t/02completion.t (ok_comp): adjust for completion changes. * sepia.texi: Variable index. 2009-03-18 Sean O'Rourke * lib/Sepia.pm (repl_help): fix formatting with "help CMD" (repl_size): sort by size 2008-12-17 Sean O'Rourke * sepia.texi (Completion): we do lexicals. * lib/Sepia.pm (lexical_completions): new function. (completions): use it. * sepia.el (sepia-function-at-point): return nil outside subs. (sepia-interactive-arg): fix call to xref-completions. 2008-07-22 Sean O'Rourke * sepia.el (sepia-scratch-send-line): change to use REPL printer. 2008-07-09 Sean O'Rourke * sepia.el (sepia-indent-line): new function. Let-bind beginning-of-defun-function for cperl-indent-line. 2008-06-29 Sean O'Rourke * sepia.el (sepia-cont-or-restart): new function to restart quitted REPL. * sepia-cpan.el (sepia-cpan-do-{desc,recommend}): oops. (sepia-cpan-make-buffer): better column widths * lib/Sepia.pm (repl_size): skip %SIG to avoid segfaults. * lib/sepia/CPAN.pm (group_by_dist): only list "main" module in each distribution, and sort them. 2008-06-20 Sean O'Rourke * VERSION: 0.97 * lib/Sepia.pm: fix use of defined(). 2008-06-17 Sean O'Rourke * lib/Sepia.pm (repl_who,repl_size): turn off added 5.10 strictures. 2008-05-11 Sean O'Rourke * sepia.texi (Mutilation): updated CPAN documentation. * sepia-cpan.el (sepia-cpan-desc): add search-by-description (sepia-cpan-mode-map): fix keybindings. * lib/Sepia/CPAN.pm: have ls/_ls, etc call interesting_parts 2008-05-10 Sean O'Rourke * VERSION: 0.96_02 * sepia-cpan.el (sepia-cpan-list, sepia-cpan-make-buffer) (sepia-cpan-search): added list-by-author, refactored. (sepia-cpan-readme): insert temp file rather than passing as string. * lib/Sepia/CPAN.pm (ls): new function to list author's modules. * lib/Sepia/Debug.pm (repl_finish): mostly-working, by adding 0x10 to $^P and looking at sub's last line. 2008-01-10 Sean O'Rourke * lib/Sepia.pm (columnate): true -> defined * VERSION: 0.96_01 * sepia-cpan.el: new file, experimental CPAN interface. * lib/Sepia/CPAN.pm: new file. 2008-01-05 Sean O'Rourke * README: remove redundant/obsolete documentation 2008-01-02 Sean O'Rourke * lib/Sepia.pm (flow): get closer to margin. 2007-12-22 Sean O'Rourke * t/50expect.t: mysterious change to placate expect. * sepia.el (sepia-shared-map): adjust bindings. (sepia-complete-symbol): Fix shortcut completion. * sepia-snippet.el (sepia-snippet-abbrev): make snippet optional, but mention it. 2007-12-20 Sean O'Rourke * lib/Sepia.pm (who): don't apply regex to sigil. (completions): fix multi-arg version (used by Emacs). (html_module_list,html_package_list): return string if asked. 2007-12-17 Sean O'Rourke * sepia.el (sepia-shared-map): bind cperl-perldoc. 2007-12-16 Sean O'Rourke * Makefile.PL (test_for): use MakeMaker's prompt(). 2007-12-13 Sean O'Rourke * sepia.el (sepia-complete-symbol): add shortcut completion. improve XEmacs compatibility. * sepia-w3m.el (sepia-w3m-create-imenu): new function, disabled by default. * lib/Sepia.pm (repl_*): don't look at return values; use "last repl" to get out. 2007-11-29 Sean O'Rourke * t/02completion.t: new completion tests. * lib/Sepia.pm (completions): rewrote to simplify. 2007-11-28 Sean O'Rourke * lib/Sepia.pm (printer): Don't sort arrays when printing. * VERSION: 0.95_02 * lib/sepia/Debug.pm (warn,die): use Carp for 5.10 compatibility. * Makefile.PL (test_for): $|=1 if prompting. 2007-11-27 Sean O'Rourke * sepia.el (sepia-perldoc-this): test for w3m when called. * VERSION: 0.95_01 * t/01basic.t (Sepia): fix tests w/o Module::Info. 2007-11-26 Sean O'Rourke * VERSION: 0.95 * lib/sepia/Debug.pm (add_repl_commands): use define_shortcut. (warn,die): same. (add_debug_repl_commands): new function. (repl): use it. * lib/Sepia.pm (define_shortcut): new function. (define_shortcut): new function. (repl_help): auto-format help text; add arg. (repl_reload): decrement $REPL_LEVEL. (completions): fix abbrev completion. (repl): read ~/.sepiarc; use define_shortcuts. (repl_format): show current if no argument. (module_info): optional dependency. 2007-11-08 Sean O'Rourke * VERSION: 0.94_01 * lib/Sepia/Xref.pm: POD fixup. * sepia.el (sepia-ensure-process): fix stupid attachtty mistake. 2007-11-05 Sean O'Rourke * lib/sepia/Debug.pm (repl_break): allow "0" as a break condition. 2007-10-31 Sean O'Rourke * lib/Sepia.pm (repl_size): ",size" command to list variable sizes, like Matlab's "whos". 2007-10-16 Sean O'Rourke * VERSION: 0.93 * lib/Sepia.pm (repl_pwd): add ",pwd" shortcut. (repl_who): use current package when only regex given. * sepia.el (sepia-repl,sepia-ensure-process): add remote connection with attachtty. (sepia-shared-map): bind \C-c\C-e to eval-expression. (sepia-symbol-info): be more selective about "core version". 2007-09-25 Sean O'Rourke * lib/Sepia.pm (printer): remove "=>" -- it's annoying. 2007-09-21 Sean O'Rourke * sepia.el (sepia-load-file): disable debugger. (sepia-symbol-info): be pickier about module core versions. 2007-09-20 Sean O'Rourke * lib/Sepia.pm (repl_who): use current package if only one arg given, and it's not an existing package. 2007-09-18 Sean O'Rourke * sepia.el (sepia-watch-for-eval): fix hang with recursive sepia-eval. 2007-07-25 Sean O'Rourke * sepia.el (sepia-interactive-arg): use xref-completions rather than xref-apropos for working completion. 2007-07-25 Ye Wenbin * sepia.el (sepia-defun-around-point): change the command to a function, because as a command it does nothing. (define-modinfo-function, sepia-maybe-echo): the interactive-p is not true when call as function. (define-modinfo-function, sepia-init): some modinfo-function should eval in a list-context. (sepia-mode): use cperl-mode-abbrev-table as current local-abbrev-table 2007-07-24 Ye Wenbin * sepia.el (sepia-set-found): Use (OFFSET . LIST) to represent things that found. (sepia-next, sepia-previous): more generic move commands (sepia-refiner): remove the test, because sometimes use the same declaration, but found in difference place. * sepia-tree.el (sepia-tree-button-cb): widget => pw and xref-location return a list of posible locations. (sepia-tree-tidy-buffer, sepia-tree-use-image): Let user to choose whether use image or not. Set it to a buffer-local variable, so that it didn't interference global values. * sepia.el (sepia-extract-def): seem an argument is excessive * sepia-tree.el (sepia-build-tree-buffer): In my emacs, it doesn't work. The :dynargs didn't become the tree-widget :expander. The tree-widget-convert-widget only receive the 'tree-widget, not the total list. sepia-install-keys not defined. * lib/Sepia/Xref.pm (file_modules): seem it is a typo error to use Module::Include rather than Module::Info. Module::Info::packages_inside return an array, the operator || will force in a scalar context. * sepia.el (sepia-lisp-to-perl): use "'" to quote string is not enough, because the string may also contain "'" inside. use (format "%S" string) instead. (define-sepia-query): `sepia-set-found' accept a symbol as argument, not (quote symbol). 2007-06-09 Sean O'Rourke * VERSION: 0.92 * sepia.el (sepia-shared-map, etc.): fix keymap initialization. 2007-06-06 Sean O'Rourke * lib/Sepia/Debug.pm: eval in lexical env when in debugger. * t/50expect.t: REPL tests if you have Test::Expect. * lib/Sepia/Debug.pm: use correct level when none given. * lib/Sepia.pm: No longer bring in exporter (why did we?). * sepia.el (sepia-init): always reinitialize sepia-mode-map. * Makefile.PL: require 5.006 for warnings to quiet stupid "make test". 2007-06-05 Sean O'Rourke * Sepia.html: generate single-page manual instead of split. * VERSION: 0.90 * sepia.el: docstring cleanup. * lib/sepia/Debug.pm: misc usability improvements 2007-06-04 Sean O'Rourke * VERSION 0.90_02 * test.pl: disable Module::Info tests to avoid Module::Info bug. 2007-06-02 Sean O'Rourke * VERSION 0.90_01 * Major: replaced comint- with gud-based REPL, use real debugger. * lib/Sepia/Debug.pm: "perl -d" support. * lib/Sepia.pm (repl_shell): new command. * sepia.el (sepia-eval-defun): detect errors, jump to first. (sepia-comint-setup): don't set comint-use-prompt-regexp (sepia-eval-defun,sepia-beginning-of-defun,sepia-end-of-defun): fix 2007-06-01 Sean O'Rourke * sepia.el (sepia-perldoc-this): don't mess up window configuration when the page isn't found. (sepia-location): use sepia-interactive-arg. (sepia-perl-[np]e-region): fix. * lib/Sepia.pm: fix. (print_dumper): switch format based on size. 2007-05-30 Sean O'Rourke * sepia.texi: shiny new manual. * lib/Sepia.pm (completions): add special 'VARIABLE' type. (methods): add second $qualified arg. (repl_reload): new function. (sig_warn,repl): override __WARN__ (and __DIE__) cautiously. (repl): nicer warning format. * sepia.el (sepia-eval-raw): stopwarn -> STOPWARN. (sepia-load-file): Fix pop-up error buffer. (sepia-lisp-to-perl): fix quoting of strings. Good citizenship: (sepia-mode): make a real major mode. (sepia-scratchpad-mode): ditto. 2007-05-29 Sean O'Rourke * lib/sepia/Xref.pm (pp_method_named): warn -> dprint. * sepia.el (sepia-simple-method-before-point): new function. (sepia-complete-symbol): use it to complete methods. make w3m optional: (sepia-perldoc-function,sepia-view-pod-function, sepia-module-list-function): new variables. (sepia-perldoc-this,sepia-view-pod): new functions. * lib/Sepia.pm (repl): trim leading spaces. (tolisp): escape metacharacters. (repl): don't override "die" if someone has installed a $SIG{__DIE__} handler 2007-05-28 Sean O'Rourke * VERSION: 0.75+ * sepia.el (sepia-core-version): new function. (sepia-indent-or-complete): fix abbrev expansion. (sepia-symbol-info): report core version in eldoc. (sepia-ident-before-point): new function. (sepia-complete-symbol): use it instead of *-at-point. (sepia-complete-symbol): complete arrays and hashes when '$' starts a word. * lib/Sepia.pm (printer): Use @::__; distinguish "last as scalar" $__ from printed representation. ($PRINT_PRETTY): columnate lists if this is on. (columnate): fixed. (repl_methods): add regex argument. (repl_who): fix. (completions): Add in package names. 2007-05-27 Sean O'Rourke * lib/Sepia.pm (repl_methods): fixed. 2007-05-26 Sean O'Rourke * VERSION: 0.74 * sepia.el (sepia-doc-scan-buffer): Better doc regex for variables. (sepia-indent-or-complete): try to expand abbrevs before completion (try with snippet.el). (sepia-indent-expand-abbrev): control the above feature. (sepia-complete-symbol): scroll completion buffer; suggested by Hilko Bengen. * lib/Sepia.pm (html_package_list,html_module_list): new functions. (completions): '$'-completion only generates scalars. * sepia-w3m.el: remove spurious sepia-module-list, improve documentation. (sepia-module-list,sepia-package-list): better output. (sepia-package-list,sepia-module-list): move Perl code to Sepia.pm, generate list in inferior perl instead of shelling out. 2007-05-23 Sean O'Rourke * lib/Sepia.pm (_apropos_re): handle empty completions. (columnate): pretty-print ",who" output. * sepia.el (sepia-complete-symbol): bury stale completions buffer; suggested by Hilko Bengen. 2007-05-17 Sean O'Rourke * lib/Sepia.pm (_completions1): Fix infinite recursion. (repl): typo; clarify ambiguous vs. unrecognized shortcuts. 2007-05-15 Sean O'Rourke * sepia.el (sepia-dwim): don't try to jump to location when looking up module docs. * lib/Sepia.pm: use $::__ instead of $Sepia::__ (repl_quit): new command. (repl): add banner. 2007-05-12 Sean O'Rourke * VERSION: 0.72 * Makefile.PL: add license. 2007-05-09 Sean O'Rourke * VERSION: 0.71 * sepia.el (sepia-load-file): set inhibit-read-only when displaying errors. * lib/Sepia.pm (repl_methods): walk ISA hierarchy looking for functions (XXX: this is much too coarse). (repl_help): use %REPL_DOC to hold command documentation for easier extension. (repl): display error on canceled continued statement. 2007-05-07 Sean O'Rourke * lib/Sepia.pm (repl_strict): add 'strict mode' (thanks to Lexical::Persistence) for those who swing that way (I don't), inspired by Devel::REPL. (repl_wantarray): Fix logic. 2007-04-25 Sean O'Rourke * VERSION: 0.70 * README: add license. * Makefile.PL: remove dependency on Sub::Uplevel, make PadWalker optional. * lib/Sepia.pm (who): add optional regex filter. (debug_inspect): fix non-scalar printing. * sepia.el (sepia-dwim): fix staleness; change to find documentation for modules. (sepia-find-module-file): new function to try sepia- and xref- module file-finding functions. (sepia-next): use it. (sepia-filter-by-module,sepia-filter-by-all): remove. (sepia-keymap): use `sepia-dwim' for M-. 2007-04-15 Sean O'Rourke * lib/Sepia.pm (who): add optional regex argument. 2007-03-30 Sean O'Rourke * sepia-w3m.el (sepia-module-list, sepia-package-list): added detailed index of installed modules. * VERSION: 0.68 2007-03-16 Sean O'Rourke * sepia.el (sepia-set-found): filter spurious nils (XXX: this really needs a fix). (sepia-symbol-info): avoid eldoc errors in ecase. 2007-03-15 Sean O'Rourke * sepia.el (sepia-complete-symbol): fallback completion of builtins. * set COPY_EXTENDED_ATTRIBUTES_DISABLE=true to avoid creating ._* files (RT #25490). 2007-03-15 Sean O'Rourke * VERSION: 0.67 * sepia-ido.el: clean up bitrot. * lib/Sepia.pm (apropos): don't create new stashes during completion. * sepia.el (sepia-show-locations): bind inhibit-read-only; filter out mysterious NILs. * Makefile.PL: require PadWalker 1.0 (RT #25463) 2007-03-13 Sean O'Rourke * VERSION: 0.66 * README (TODO): user-defined REPL abbrevs. * lib/Sepia.pm (print_*): optional printing via YAML and Data::Dump (from Shell::Perl). (repl_wantarray): change eval context (same). (repl_format): set formatter (same). 2007-03-09 Sean O'Rourke * VERSION: 0.65 * sepia.el (sepia-keymap): add *-apropos, find-tag bindings. * README: add organized function index. * sepia.el (sepia-beginning-of-defun, sepia-end-of-defun): fix argument to be prefix instead of point. * sepia.el: documentation. * sepia-ido.el: documentation. * README: cleanup; note limitation of sepia-bodf and -eodf. 2007-02-25 Sean O'Rourke * Makefile.PL: add Scalar::Util as prereq. * sepia.el (sepia-perl5lib): new variable holding extra PERL5LIB entry. * sepia.el (sepia-init): use it. * sepia.el (sepia-comint-setup): don't clobber keymap. * sepia.el (sepia-indent-or-complete): complete first time if at end of word. * Sepia.pm (completions): enhanced completion -- e.g. "wtf" matches "want_to_feed". * Sepia.pm (printer): special-case PDL to use its stringification (XXX: should test for overloaded ""). * Sepia.pm (who,repl_who): new functions. 2006-09-29 Sean O'Rourke * Sepia.pm (Dump): wrap with eval to prevent unexpected exits. * Sepia.pm (repl_chdir): expand '~' and '$HOME' 2006-07-01 Sean O'Rourke * Sepia.pm (tolisp): undef -> nil * sepia.el (sepia-eval-raw): guess package. * sepia.el (sepia-init): don't pop-to-buffer with prefix argument. * sepia.el (sepia-beginning-of-defun,sepia-end-of-defun): avoid recursion. * sepia.el (sepia-buffer-package): look backward from point instead of forward from point-min. 2006-05-24 Sean O'Rourke * Makefile.PL: added missing dependencies on PadWalker, Sub::Uplevel. * Sepia.pm: improved ",command" * sepia-w3m.el (sepia-w3m-perldoc-this): simplify. * sepia.el (perl-*): rename to sepia-*. * sepia.el: reorg and cleanup. * VERSION: 0.63 2006-05-19 Sean O'Rourke * sepia.el: fixed eldoc support. This only works with CVS Emacs, relying on `eldoc-documentation-function'. Also fixed pod scanning for eldoc. 2006-05-18 Sean O'Rourke * sepia.el, Sepia.pm: improved bulk-transfer protocol. * Sepia.pm: override die with simple inspector/debugger. * Sepia.pm: $__ and @__ now contain results of the last expression. * sepia.el, Sepia.pm: primitive support for evaluating elisp sent from Perl. Turn on comint-use-prompt-regexp because the fields stuff is flaky with this. * sepia.el, Sepia.pm: ",cd" shortcut coordinates directory with Emacs. * VERSION 0.61, 0.62 2006-04-14 Sean O'Rourke * generic-repl.el: replaced by comint. * all: removed EPL dependency. * VERSION 0.59 2005-07-12 Sean O'Rourke * sepia-w3m.el: fix function name so it's found. * Xref.pm, Sepia.pm: cleanup and numerous bugfixes. * Buffer.pm: new, but not ready for prime-time * sepia.el: delete-thing-at-point removed; misc bugfixes. * test.pl: disabled a bunch of location stuff. * VERSION 0.58 2004-09-10 Sean O'Rourke * test.pl: some real tests. * Sepia.pm, Xref.pm: Separate simple symbol-table searching from Xref, making the former more reliable. * Xref.pm: More reliable detection of (class) method calls. * sepia.el: results are not displayed for expressions ending in ';' (c.f. Octave). 2004-04-12 Sean O'Rourke * sepia.el (sepia-doc-scan-buffer): Make regular expressions a bit better. (sepia-ident-at-point): handle upper-case function and variable names for completion (a bit hacky...). (sepia-install-keys): fix keymap installation. 2004-04-11 Sean O'Rourke * Xref.pm (guess_module_file): do like Module::Info and trust %INC more than our Xref info. But don't be _too_ smart about this -- we were picking up lots of bogus exports. (pp_method_named): add support for constant-named methods (cribbed from B::Concise). 2004-04-10 Sean O'Rourke * Xref.pm: update $VERSION to track Sepia release. * sepia.el (sepia-indent-or-complete): only complete on the second TAB. 2004-04-09 Sean O'Rourke * sepia.el (sepia-refiner): tweak refining function a bit more. I'm still not entirely happy with this, but it's getting better. Time and experimentation are required. * sepia-tree.el (sepia-calle[er]-tree): New file. Use caller/callee information to generate tree-view using David Ponce's wonderful tree-widget. * Xref.pm (_apropos_re): Add that Emacs-style multipart-word completion, so e.g. D:v_d -> Devel::Xref::var_defs. It's groovy, man. (%firstline): gone. Just getting a line within the sub is good enough -- we can fix it on the Emacs side of the fence later. 2004-04-08 Sean O'Rourke * sepia-w3m.el (sepia-w3m-perldoc-this): work for functions as well as modules, and try to go to correct position in manpage. * sepia.el (sepia-eval-buffer): use 'BEGIN{ die }' to do Xrefs for scripts without loading them. * Xref.pm: Localize a bunch of things instead of stomping on package lexicals. This makes the module better handle repeated use, for which it wasn't designed. * Xref.pm (mod_subs): Rename package_subs for consistency. (mod_decls): New function to generate decls for evaluation. * sepia.el: misc bug-fixes, and better support for redefining functions with sepia-eval-defun, especially preserving files and line numbers. (sepia-eval): remove newlines to make line-numbers make more sense to user. (sepia-interactive-arg): delay reading completions to speed up \M-. functions. (sepia-refiner): search both forward and backward, to adjust for e.g. adding comments. Still not so good, but better. 2004-04-06 Sean O'Rourke * sepia-w3m.el: moved w3m-perldoc support here. * README: added description, removed disclaimer * sepia.el (sepia-symbol-info, sepia-doc-update): POD scanning and cperl hackage for eldoc support. 2004-04-05 Sean O'Rourke * Xref.pm (redefined,forget): make them take a single sub at a time, and pay attention to packages. (_apropos): use package info to narrow choices. * sepia.el (sepia-eval-defun,sepia-eval-buffer): new functions. * test.pl: satisfy the cpants Fascists. * Xref.pm (use_type): try to be smarter about when something's being assigned to, vs. merely used as a reference. * sepia.el (sepia-repl-header): keep up with generic-repl by doing header line, working dir. (sepia-complete-symbol): stupid bug with modules. (sepia-install-keys): new function. (sepia-var-assigns): assignments are more useful than defs. (sepia-init): start REPL by default. * generic-repl.el (repl-cd,repl-set-header): "new" function from Slime to track working dir, update header line. 2004-04-04 Sean O'Rourke * Sepia.jpg: don't ask -- just look. * sepia.el (sepia-ident-at-point): fixed bug with sigils. (sepia-complete-symbol): fixed bug with undefined function sepia-end-of-word. Always use Data::Dumper. * any-repl.el: new file implementing REPL, basically stolen from Slime. * pscope.el: renamed to sepia.el to go with name change. 2004-04-03 Sean O'Rourke * pscope.el (pscope-set-found): remove locations with no file in package "main", which were causing errors before. (pscope-dwim): new function. New functions pscope-complete-symbol and pscope-indent-or-complete for symbol completion. Not well-tested, but they seem to work. The most annoying thing is that since the Xref db isn't automatically updated, it won't always know as much as you expect. (pscope-load-file): new function. * Xref.pm: update export lists to reflect new functions. 2004-04-02 Sean O'Rourke * Xref.pm: minor cleanup. * pscope.el: pass module, file, line to Perl side (where it's ignored for now); fix line number refinement to be a little less over-eager; fix pscope-callees to go to sub definitions instead of call sites. * README: added TODO section. Sepia-0.992/lib/000755 000765 000765 00000000000 11661034124 013630 5ustar00seanoseano000000 000000 Sepia-0.992/Makefile.PL000644 000765 000765 00000014654 11656773647 015076 0ustar00seanoseano000000 000000 use warnings; use strict; use Pod::Usage; use Getopt::Long; use ExtUtils::MakeMaker qw(WriteMakefile prompt); use 5.006; # for "no warnings" -- sorry! # See lib/ExtUtils/MakeMaker.pm for details of how to influence # the contents of the Makefile that is written. my %prereq = ( 'Data::Dumper' => 0, 'Scalar::Util' => 0, ); ## Poor man's optional deps. sub test_for { my $mod = shift; eval "require $mod"; if ($@) { my $resp = prompt("@_. Install $mod (y/n)? ", 'n'); $prereq{$mod} = 0 if $resp =~ /^y/i; } } my $ELISP_FIND_SITELISP = <<'END_ELISP'; (dolist (x load-path) (princ x) (terpri)) END_ELISP my $ELISP_FIND_INFODIR = <<'END_ELISP'; (progn (require (quote info)) (princ (car Info-default-directory-list))) END_ELISP my ($EMACS, $SITE_LISP, $INSTALL_INFO, $INFO_DIR, $HELP); sub escape_path { my ($path) = @_; $path =~ s/([$?* ])/\\$1/g; # escape special characters $path =~ s{/+$}{}; # remove trailing forward-slashes return $path; } sub prompt_for_emacs { # try to compile and install Elisp files, but don't die if we can't. my ($sysemacs) = grep { defined && -x } $ENV{EMACS}, glob '/usr/bin{/local,}/emacs'; $sysemacs ||= q{emacs}; my $emacs = prompt("Where is your emacs? ", $sysemacs); # Make sure emacs is a valid string/program path... return undef unless $emacs; # Make sure -x is passed an absolute path... unless ( $emacs =~ m{^/} && -x $emacs ) { warn "$emacs is not executable! Undefined.\n"; return undef; } return escape_path( $emacs ); } # Runs some elisp code with emacs via the command line. # We must set $EMACS before running this... if it is an untrue value # then we return an empty list or string, depending on what caller wants. sub run_elisp { my ($elisp) = @_; return wantarray ? qw// : q{} unless $EMACS; return `$EMACS --batch --eval '$elisp' 2>/dev/null`; } sub prompt_for_sitelisp { my @lp = run_elisp( $ELISP_FIND_SITELISP ); chomp @lp; my $site_lisp; if ( scalar @lp ) { ($site_lisp) = grep { /site-lisp$/ && -d $_ } @lp; } $site_lisp = prompt("Elisp install directory?", $site_lisp); # We don't check if the directory exists, because we can create it... return escape_path( $site_lisp ); } sub prompt_for_infodir { chomp(my @info_dir = grep { m!/info/?$! } run_elisp( $ELISP_FIND_INFODIR )); # pass prompt undef so it will not display brackets if $info_dir is "" my $info_dir = prompt("Info directory?", $info_dir[0] || undef); return escape_path( $info_dir ); } # Append info page and elisp installation to the end of the install # section in the Makefile... sub MY::postamble { # Make an entry for Sepia.html as a target to make things easier... my $maketxt = <<'END_MAKETXT'; all :: Sepia.html sepia.info Sepia.html : sepia.texi makeinfo --no-split --no-headers --html sepia.texi -o Sepia.html sepia.info : sepia.texi makeinfo --no-split -o sepia.info sepia.texi END_MAKETXT $maketxt .= <<"END_MAKETXT"; install :: END_MAKETXT if ( $INFO_DIR ) { $maketxt .= <<"END_MAKETXT" } install -d -m755 \$(DESTDIR)$INFO_DIR install -m644 sepia.info \$(DESTDIR)$INFO_DIR $INSTALL_INFO \$(DESTDIR)$INFO_DIR/sepia.info \$(DESTDIR)$INFO_DIR/dir END_MAKETXT if ( $SITE_LISP ) { $maketxt .= <<"END_MAKETXT"; install -d -m755 \$(DESTDIR)$SITE_LISP install -m644 *.el \$(DESTDIR)$SITE_LISP END_MAKETXT if ( $EMACS ) { $maketxt .= <<"END_MAKETXT"; install -m644 *.elc \$(DESTDIR)$SITE_LISP END_MAKETXT } } else { print <<'END_MSG' ====================================================================== To actually use this package, you need to move the Emacs Lisp files somewhere Emacs will find them. You may also want to install the HTML documentation somewhere appropriate to your system. ====================================================================== END_MSG } # Create a new target for compiled elisp (.elc) files... # Allow the compilation to fail (it is prefixed with "-")... if ( $EMACS ) { $maketxt .= <<"EOS"; \%.elc : \%.el - $EMACS -L '$ENV{PWD}' --batch -f batch-byte-compile \$? 2>/dev/null all :: sepia-snippet.elc sepia.elc sepia-cpan.elc sepia-tree.elc \\ sepia-w3m.elc sepia-ido.elc EOS } return $maketxt; } GetOptions( 'emacs=s' => \$EMACS, 'lisp=s' => \$SITE_LISP, 'info=s' => \$INFO_DIR, 'help' => \$HELP, ); exit pod2usage( '-verbose' => 1 ) if $HELP; test_for 'Devel::Peek', 'Printing internals requires Devel::Peek'; test_for 'Devel::Size', 'Printing variable sizes requires Devel::Size'; test_for 'IO::Scalar', 'Printing internals requires IO::Scalar because Devel::Peek sucks'; test_for 'PadWalker', 'Strict mode requires PadWalker'; test_for 'Devel::LexAlias', 'Strict mode requires Devel::LexAlias'; test_for 'LWP::Simple', 'CPAN documentation browsing requires LWP::Simple'; test_for 'Module::CoreList', 'sepia-core-version requires Module::CoreList'; test_for 'Module::Info', 'Required for some Emacs functions'; test_for 'BSD::Resource', 'Detailed command timing'; test_for 'Time::HiRes', 'Basic command timing'; # test_for 'Pod::Webserver', 'Pod::Webserver creates nice documentation.'; # test_for 'Scope::Upper', 'Required for return-from-context'; $INSTALL_INFO = 'install-info'; if ( !defined $EMACS ) { $EMACS = prompt_for_emacs() or warn "Disabling elisp compilation and dir detection.\n"; } $SITE_LISP ||= prompt_for_sitelisp(); $INFO_DIR ||= prompt_for_infodir(); $INSTALL_INFO ||= prompt("install-info program?", 'install-info') if $INFO_DIR; WriteMakefile( NAME => 'Sepia', VERSION_FROM => 'lib/Sepia.pm', # finds $VERSION PREREQ_PM => \%prereq, EXE_FILES => ['sepl'], AUTHOR => "Sean O'Rourke ", ABSTRACT => 'Simple Emacs-Perl InterAction', clean => { FILES => '*.elc' }, ); __END__ =head1 SYNOPSIS # prompts for paths perl Makefile.PL # doesn't prompt for paths perl Makefile.PL --emacs /usr/bin/emacs \ --lisp /usr/share/emacs/site-lisp/sepia \ --info /usr/share/info =head1 OPTIONS =over 4 =item B<--emacs> Specifies the path to emacs. =item B<--lisp> Specifies the directory to install the elisp files to. =item B<--info> Specifies the directory to install the texinfo files to. =item B<--help> Display this help information. =back Sepia-0.992/MANIFEST000644 000765 000765 00000000622 11661034124 014213 0ustar00seanoseano000000 000000 ChangeLog MANIFEST Makefile.PL README Sepia.html Sepia.jpg lib/Sepia.pm lib/Sepia/CPAN.pm lib/Sepia/Debug.pm lib/Sepia/ReadLine.pm lib/Sepia/Xref.pm sepia-cpan.el sepia-ido.el sepia-snippet.el sepia-tree.el sepia-w3m.el sepia.el sepia.info sepia.texi sepl t/01basic.t t/02completion.t t/03without.t t/50expect.t t/testy.pl META.yml Module meta-data (added by MakeMaker) Sepia-0.992/META.yml000644 000765 000765 00000001063 11661034124 014333 0ustar00seanoseano000000 000000 --- #YAML:1.0 name: Sepia version: 0.992 abstract: Simple Emacs-Perl InterAction author: - Sean O'Rourke license: unknown distribution_type: module configure_requires: ExtUtils::MakeMaker: 0 build_requires: ExtUtils::MakeMaker: 0 requires: Data::Dumper: 0 Scalar::Util: 0 no_index: directory: - t - inc generated_by: ExtUtils::MakeMaker version 6.56 meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 Sepia-0.992/README000644 000765 000765 00000012715 11657062742 013764 0ustar00seanoseano000000 000000 * DESCRIPTION (-*- org -*-) Sepia is a set of features to make Emacs a better tool for Perl development, including: * an interactive prompt (REPL) for evaluating code; * cross-referencing to find and navigate between function and variable definitions and uses; * variable- and function-name completion. * eldoc support to echo function arguments in the minibuffer * functions to simplify POD browsing with Emacs-w3m Please see the Sepia.html or sepia.info for documentation. * INSTALLATION The basic installation procedure is: 1) run "perl Makefile.PL; make; make install" 2) optionally, install w3m and Emacs-w3m 3) put the elisp files somewhere Emacs will find them. Sepia is developed on the latest version of GNU Emacs, which can be obtained from CVS or as a prebuilt package on some platforms. It can run on other versions of Emacs, but may require additional packages. ** Requirements for GNU Emacs 22 *** (optional) emacs-w3m from http://emacs-w3m.namazu.org/ *** (optional) w3m from http://w3m.sourceforge.net/ *** (optional) snippet.el from http://www.kazmier.com/computer/snippet.el ** Additional requirements GNU Emacs 21 *** ido.el http://cvs.savannah.gnu.org/viewcvs/*checkout*/emacs/lisp/ido.el?root=emacs *** FreeBSD may require the following packages: tree-widget-emacs21-2.0 emacs-w3m-emacs21-1.4.4_2 mule-ucs-emacs21-0.85.r3 semi-emacs21-1.14.6_1 wv-1.2.4 xlhtml-0.5_1,1 libgsf-1.14.3 flim-emacs21-1.14.8 apel-emacs21-10.7 ja-nkf-2.05 * DEVELOPMENT The "official" source code repository mirror is at http://repo.or.cz/w/sepia.git To get a copy, install Git, then git clone git://repo.or.cz/sepia.git To submit a patch, please send a diff to the author, including an Emacs-style ChangeLog entry. * TODO ** (Medium) Get the variable def/use analysis working again. ** (Hard) return from anything in the debugger Make it possible to return from intermediate calls in the debugger. Returning from die() is not often useful. This can be done with a clever DB::sub, but that dramatically slows down execution. ** (Medium) fix `sepia-beginning-of-defun' and `sepia-end-of-defun'. While they work for "normal" sub definitions, they fail on definitions that are all on one line, e.g. sub foo { ... } sub bar { ... } ** (Medium) Fix string escaping when passing between Perl and Emacs IO::Scalar's README tickles a bug. ** (Hard) Make the debugger's "next" work "next" (as opposed to "step") assumes that the next statement after line $n is line $n+1, which isn't true for loops, blank lines, multi-line statements, etc. Fix this somehow. One way might be to temporary regain control on a op_next/op_nextstate, or whatever those are called, but this would be hard and/or require XS. If we set $^P to populate @dbline, we can use that to find breakable lines, but that still doesn't fix backward branches in loops. ** (Medium) Make "finish" more reliable It currently assumes that the last breakable statement in a sub is one line before its end. The "right" solution would be like above: to hook op_leave temporarily. This would similarly require XS trickery. ** (Medium) Enable partial-word completion of lexicals ** (Hard) Rewrite completion code, which is pretty ugly now. This wouldn't seem "hard" but, having hacked on two completion codebases (Sepia's and complete.el's), I know there are always a lot of subtle cases to get right, and what acts "naturally" by human standards is extremely complicated to specify in code. ** (Easy) Document existing hooks and add_hook()/remove_hook() @PRE_PROMPT, @PRE_EVAL, @POST_EVAL ** (Hard) Add appropriate hooks Possibly update existing functions to make use of hooks for better modularity. * KNOWN BUGS The following is a list of bugs that are difficult to automatically reproduce, with the dates they were first observed. ** (2006-05-19) Function definition lines occasionally all go wrong. Rebuilding the Xref database fixes this. ** (2006-05-19) The cursor misses by several lines jumping to a definition. This is hard to fix -- Perl doesn't give exact line numbers for sub defs, so we have to do some minor regex-searching. ** (2006-05-19) `sepia-var-assigns' doesn't work yet -- don't use it. ** (2006-05-19) named method calls (mostly?) detected, but naively. Nothing smart is done about packages, so e.g. "new Foo" will result in listings for every instance of "new" in your program. ** (2008-01-18) the first value printed in the debugger is undef. why?! ** (2009-12-13) completion deletes things it shouldn't e.g. $x->method => method. I need to rewrite this code to not suck. ** (2010-09-30) broken in view-mode should scroll up if you enable view-mode, but for whatever reason it stays bound to hungry-delete. I'm not sure if this is my fault, or cperl's. ** (2011-02-22) Sepia::Xref::load_pad segfaults While traversing inside File::Find::contract_name. Backtrace: #0 0x00000001001afa30 in XS_B__COP_hints_hash () #1 0x00000001001b12ba in XS_B__GV_STASH () #2 0x0000000100075708 in Perl_pp_entersub () #3 0x000000010006e6cc in Perl_runops_standard () #4 0x000000010006e43a in perl_run () * COPYRIGHT AND LICENCE Copyright (C) 2004-2011 Sean O'Rourke This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, at the time at which this version of Sepia was released. Sepia-0.992/sepia-cpan.el000644 000765 000765 00000014266 11267165330 015443 0ustar00seanoseano000000 000000 (require 'cl) (require 'button) (defvar sepia-cpan-actions '(("r" . sepia-cpan-readme) ("d" . sepia-cpan-doc) ("i" . sepia-cpan-install) ("q" . bury-buffer))) ;;;###autoload (defun sepia-cpan-doc (mod) "Browse the online Perldoc for MOD." (interactive "sModule: ") (let ((buf (save-window-excursion (and (browse-url (concat "http://search.cpan.org/perldoc?" mod)) (current-buffer))))) (when buf (pop-to-buffer buf)))) ;;;###autoload (defun sepia-cpan-readme (mod) "Display the README file for MOD." (interactive "sModule: ") (with-current-buffer (get-buffer-create "*sepia-cpan-readme*") (let ((inhibit-read-only t)) (erase-buffer) (insert-file-contents (sepia-call "Sepia::CPAN::readme" 'scalar-context mod 1))) (view-mode 1) (pop-to-buffer (current-buffer)))) ;;;###autoload (defun sepia-cpan-install (mod) "Install MOD and its prerequisites." (interactive "sModule: ") (when (y-or-n-p (format "Install %s? " mod)) (sepia-eval "require Sepia::CPAN") (sepia-call "Sepia::CPAN::install" 'void-context mod))) (defun sepia-cpan-do-search (pattern) "Return a list modules whose names match PATTERN." (sepia-eval "require Sepia::CPAN") (sepia-call "Sepia::CPAN::list" 'list-context (format "/%s/" pattern))) (defun sepia-cpan-do-desc (pattern) "Return a list modules whose descriptions match PATTERN." (sepia-eval "require Sepia::CPAN") (sepia-call "Sepia::CPAN::desc" 'list-context pattern)) (defun sepia-cpan-do-recommend (pattern) "Return a list modules whose descriptions match PATTERN." (sepia-eval "require Sepia::CPAN") (sepia-call "Sepia::CPAN::recommend" 'list-context pattern)) (defun sepia-cpan-do-list (pattern) "Return a list modules matching PATTERN." ;; (interactive "sPattern (regexp): ") (sepia-eval "require Sepia::CPAN") (sepia-call "Sepia::CPAN::ls" 'list-context (upcase pattern))) (defvar sepia-cpan-button) (defun sepia-cpan-button (button) (funcall (cdr (assoc sepia-cpan-button sepia-cpan-actions)) (button-label button))) (defun sepia-cpan-button-press () (interactive) (let ((sepia-cpan-button (this-command-keys))) (push-button))) (defvar sepia-cpan-mode-map (let ((km (make-sparse-keymap))) (set-keymap-parent km button-map) ;; (define-key km "q" 'bury-buffer) (define-key km "/" 'sepia-cpan-desc) (define-key km "S" 'sepia-cpan-desc) (define-key km "s" 'sepia-cpan-search) (define-key km "l" 'sepia-cpan-list) (define-key km "R" 'sepia-cpan-recommend) (define-key km " " 'scroll-up) (define-key km (kbd "DEL") 'scroll-down) (dolist (k (mapcar #'car sepia-cpan-actions)) (define-key km k 'sepia-cpan-button-press)) km)) (define-button-type 'sepia-cpan 'follow-link nil 'action 'sepia-cpan-button 'help-echo "[r]eadme, [d]ocumentation, [i]nstall" 'keymap sepia-cpan-mode-map) (define-derived-mode sepia-cpan-mode fundamental-mode "CPAN" "Major mode for CPAN browsing." (setq buffer-read-only t truncate-lines t)) (defun string-repeat (s n) "Repeat S N times." (let ((ret "")) (dotimes (i n) (setq ret (concat ret s))) ret)) (defun sepia-cpan-make-buffer (title mods fields names) (switch-to-buffer "*sepia-cpan*") (sepia-cpan-mode) (setq buffer-read-only nil) (let ((inhibit-read-only t)) (erase-buffer)) (remove-overlays) (insert title " [r]eadme, [d]ocumentation, [i]nstall, [q]uit, [s]earch-by-name, [/][S]earch-by-description, [l]ist-for-author ") (when (consp mods) (let (lengths) (dolist (mod mods) (setcdr (assoc "cpan_file" mod) (replace-regexp-in-string "^.*/" "" (cdr (assoc "cpan_file" mod))))) (setq lengths (mapcar* #'max (mapcar (lambda (x) (+ 2 (length x))) names) (mapcar (lambda (f) (+ 2 (apply #'max (mapcar (lambda (x) (length (format "%s" (cdr (assoc f x))))) mods)))) fields))) (setq fmt (concat (mapconcat (lambda (x) (format "%%-%ds" x)) lengths "") "\n")) (insert (apply 'format fmt names)) (insert (apply 'format fmt (mapcar (lambda (x) (string-repeat "-" (length x))) names))) (dolist (mod mods) (let ((beg (point))) (insert (apply #'format fmt (mapcar (lambda (x) (or (cdr (assoc x mod)) "-")) fields))) (make-button beg (+ beg (length (cdr (assoc "id" mod)))) :type 'sepia-cpan))))) (goto-char (point-min))) ;;;###autoload (defun sepia-cpan-list (name) "List modules by author NAME." (interactive "sAuthor: ") (sepia-cpan-make-buffer (concat "CPAN modules by " name) (sepia-cpan-do-list name) '("id" "inst_version" "cpan_version" "cpan_file") '("Module" "Inst." "CPAN" "Distribution"))) ;;;###autoload (defun sepia-cpan-search (pat) "List modules whose names match PAT." (interactive "sPattern (regexp): ") (setq pat (if (string= pat "") "." pat)) (sepia-cpan-make-buffer (concat "CPAN modules matching /" pat "/") (sepia-cpan-do-search pat) '("id" "fullname" "inst_version" "cpan_version" "cpan_file") '("Module" "Author" "Inst." "CPAN" "Distribution"))) ;;;###autoload (defun sepia-cpan-desc (pat) "List modules whose descriptions match PAT." (interactive "sPattern (regexp): ") (sepia-cpan-make-buffer (concat "CPAN modules with descriptions matching /" pat "/") (sepia-cpan-do-desc pat) '("id" "fullname" "inst_version" "cpan_version" "cpan_file") '("Module" "Author" "Inst." "CPAN" "Distribution"))) ;;;###autoload (defun sepia-cpan-recommend (pat) "List out-of-date modules." (interactive "sPattern (regexp): ") (setq pat (if (string= pat "") "." pat)) (sepia-cpan-make-buffer (concat "Out-of-date CPAN modules matching /" pat "/") (sepia-cpan-do-recommend pat) '("id" "fullname" "inst_version" "cpan_version" "cpan_file") '("Module" "Author" "Inst." "CPAN" "Distribution"))) (provide 'sepia-cpan) Sepia-0.992/sepia-ido.el000644 000765 000765 00000024361 10732630143 015265 0ustar00seanoseano000000 000000 (eval-when-compile (require 'ido) (require 'cl)) (defun* sepia-icompleting-recursive-read (prompt dir &key list-fn parent-fn chdir-fn rootp-fn slashp-fn) "Like `ido-read-file-name', but without all the file-specific bells-and-whistles. Arguments are: list-fn list current dir parent-fn get parent dir chdir-fn change to dir rootp-fn is dir root? slashp-fn does dir end in slash? " (flet ((ido-make-file-list (prefix) (setq ido-temp-list (funcall list-fn (or prefix "")))) (ido-exhibit () (sepia-ido-exhibit)) (ido-is-root-directory (&optional dir) (funcall rootp-fn (or dir ido-current-directory))) (ido-set-current-directory (dir &optional subdir foo) (funcall chdir-fn dir subdir foo)) (ido-final-slash (str &rest blah) (funcall slashp-fn str)) (ido-file-name-directory (x) (funcall parent-fn x)) ;; And stub out these two suckers... (ido-is-tramp-root (&rest blah) nil) (ido-nonreadable-directory-p (dir) nil)) (setq ido-current-directory dir) (let ((ido-saved-vc-hb nil) (ido-directory-nonreadable nil) (ido-context-switch-command 'ignore) (ido-directory-too-big nil)) (sepia-ido-read-internal 'file prompt nil nil t)))) (defun sepia-rootp-fn (dir) (member dir '("" "::"))) (defun sepia-chdir-fn (dir sub blah) (setq dir (cond (sub (concat dir (car ido-matches))) ((member dir (list ido-current-directory "::")) dir) ((string-match (concat "^" dir) ido-current-directory) dir) (t (concat ido-current-directory (car ido-matches))))) ;; XXX what's that doing?!? ;; (unless ido-matches ;; (error "help! dir = %s" dir)) ;; (setq dir (concat ido-current-directory (car ido-matches))) (if (string-equal ido-current-directory dir) nil ;; XXX: concat? (setq ido-current-directory (ido-final-slash dir)) (when (get-buffer ido-completion-buffer) (kill-buffer ido-completion-buffer)) t)) (defun sepia-list-fn (str) (let ((listing-dir ido-current-directory)) (when (or (not ido-current-directory) (string-match "^\\(?:::\\)?$" ido-current-directory)) (setq ido-current-directory "" listing-dir "::")) (mapcar (lambda (x) (substring x (length listing-dir))) (xref-apropos (concat listing-dir str ".*") t "CODE" "STASH")))) (defun sepia-dir-fn (str) (if (string-match "^\\(.*::\\)[^:]+:*$" str) (match-string 1 str) "")) (defun sepia-slashp-fn (str) (cond ((string-match "::$" str) str) ((string-match ":$" str) (concat str ":")) (t nil))) (defun sepia-jump-to-symbol () "Jump to a symbol's definition using ido-like completion." (interactive) (let ((pack (concat (sepia-buffer-package) "::")) ido-case-fold) (sepia-location (sepia-icompleting-recursive-read "Jump to: " pack :list-fn 'sepia-list-fn :parent-fn 'sepia-dir-fn :chdir-fn 'sepia-chdir-fn :rootp-fn 'sepia-rootp-fn :slashp-fn 'sepia-slashp-fn) t))) (defun sepia-ido-exhibit () "Post command hook for `sepia-icompleting-recursive-read'. Like `ido-exhibit', but without weird file-specific bells and whistles. Since ido is controlled through a bunch of dynamic variables, it's hard to figure out what can be safely cut." (when (= ido-use-mycompletion-depth (minibuffer-depth)) (let ((contents (buffer-substring-no-properties (minibuffer-prompt-end) (point-max))) (buffer-undo-list t) try-single-dir-match) (save-excursion (goto-char (point-max)) ;; Register the end of input, so we know where the extra stuff ;; (match-status info) begins: (unless (boundp 'ido-eoinput) ;; In case it got wiped out by major mode business: (make-local-variable 'ido-eoinput)) (setq ido-eoinput (point)) ;; Handle explicit directory changes (when (ido-final-slash contents) (ido-set-current-directory contents) (setq ido-exit 'refresh) (exit-minibuffer) (setq ido-text-init "")) ;; Update the list of matches (setq ido-text contents) (ido-set-matches) ;; Enter something ending in a "slash" (when (and ido-matches (null (cdr ido-matches)) (ido-final-slash (car ido-matches)) try-single-dir-match) (ido-set-current-directory (concat ido-current-directory (car ido-matches))) (setq ido-exit 'refresh) (exit-minibuffer)) (setq ido-rescan t) (ido-set-common-completion) (let ((inf (ido-completions contents minibuffer-completion-table minibuffer-completion-predicate (not minibuffer-completion-confirm)))) (insert inf)))))) (defun sepia-ido-complete () "Try to complete the current pattern amongst the file names." (interactive) (let (res) (cond ((not ido-matches) (when ido-completion-buffer (call-interactively (setq this-command ido-cannot-complete-command)))) ((= 1 (length ido-matches)) ;; only one choice, so select it. (if (not ido-confirm-unique-completion) (exit-minibuffer) (setq ido-rescan (not ido-enable-prefix)) (delete-region (minibuffer-prompt-end) (point)) (insert (car ido-matches)))) (t ;; else there could be some completions (setq res ido-common-match-string) (if (and (not (memq res '(t nil))) (not (equal res ido-text))) ;; found something to complete, so put it in the minibuffer. (progn ;; move exact match to front if not in prefix mode (setq ido-rescan (not ido-enable-prefix)) (delete-region (minibuffer-prompt-end) (point)) (insert res)) ;; else nothing to complete (call-interactively (setq this-command ido-cannot-complete-command))))))) (defun sepia-ido-read-internal (item prompt history &optional default require-match initial) "Perform the ido-read-buffer and ido-read-file-name functions. Return the name of a buffer or file selected. PROMPT is the prompt to give to the user. DEFAULT if given is the default directory to start with. If REQUIRE-MATCH is non-nil, an existing file must be selected. If INITIAL is non-nil, it specifies the initial input string." (let ((ido-cur-item item) (ido-entry-buffer (current-buffer)) (ido-process-ignore-lists t) (ido-process-ignore-lists-inhibit nil) (ido-set-default-item t) ido-default-item ido-selected ido-final-text (done nil) (icomplete-mode nil) ;; prevent icomplete starting up ;; Exported dynamic variables: ido-cur-list ido-ignored-list (ido-rotate-temp nil) (ido-keep-item-list nil) (ido-use-merged-list nil) (ido-try-merged-list t) (ido-pre-merge-state nil) (ido-case-fold ido-case-fold) (ido-enable-prefix ido-enable-prefix) (ido-enable-regexp ido-enable-regexp) ) ;; (ido-define-mode-map) (ido-setup-completion-map) (setq ido-text-init initial) (while (not done) (ido-trace "\n_LOOP_" ido-text-init) (setq ido-exit nil) (setq ido-rescan t) (setq ido-rotate nil) (setq ido-text "") ;; XXX: set ido-default-item? (if ido-keep-item-list (setq ido-keep-item-list nil ido-rescan nil) (setq ido-ignored-list nil ido-cur-list (ido-make-file-list ido-default-item))) (setq ido-rotate-temp nil) (ido-set-matches) (if (and ido-matches (eq ido-try-merged-list 'auto)) (setq ido-try-merged-list t)) (let ((minibuffer-local-completion-map ido-completion-map) (max-mini-window-height (or ido-max-window-height (and (boundp 'max-mini-window-height) max-mini-window-height))) (ido-completing-read t) (ido-require-match require-match) (ido-use-mycompletion-depth (1+ (minibuffer-depth))) (show-paren-mode nil)) ;; prompt the user for the file name (setq ido-exit nil) (setq ido-final-text (catch 'ido (completing-read (ido-make-prompt item prompt) '(("dummy" . 1)) nil nil ; table predicate require-match (prog1 ido-text-init (setq ido-text-init nil)) ;initial-contents history)))) (if (get-buffer ido-completion-buffer) (kill-buffer ido-completion-buffer)) (cond ((eq ido-exit 'refresh) (if (and (eq ido-use-merged-list 'auto) (or (input-pending-p))) (setq ido-use-merged-list nil ido-keep-item-list t)) nil) ((eq ido-exit 'done) (setq done t ido-selected ido-text ido-exit nil) (setq ido-text-init (read-string (concat prompt "[EDIT] ") ido-final-text))) ((eq ido-exit 'keep) (setq ido-keep-item-list t)) ((memq ido-exit '(dired fallback findfile findbuffer)) (setq done t)) ((eq ido-exit 'updir) ;; cannot go up if already at the root-dir (Unix) or at the ;; root-dir of a certain drive (Windows or MS-DOS). (unless (ido-is-root-directory) (ido-set-current-directory (ido-file-name-directory (substring ido-current-directory 0 -2))) (setq ido-set-default-item t))) ;; Handling the require-match must be done in a better way. ((and require-match (not (ido-existing-item-p))) (error "must specify valid item")) (t (setq ido-selected (if (or (eq ido-exit 'takeprompt) (null ido-matches)) ido-final-text ;; else take head of list (ido-name (car ido-matches)))) (cond ((ido-final-slash ido-selected) (ido-set-current-directory ido-current-directory ido-selected) (setq ido-set-default-item t)) (t (setq done t)))))) ido-selected)) (provide 'sepia-ido) Sepia-0.992/sepia-snippet.el000644 000765 000765 00000001600 11462212503 016160 0ustar00seanoseano000000 000000 (eval-when-compile (require 'snippet)) (defun sepia-snippet-abbrev () (require 'snippet nil t) (when (featurep 'snippet) (snippet-with-abbrev-table 'sepia-mode-abbrev-table ("else" . "else {\n$>$.\n}$>") ("elsif" . "elsif ($${TEST}) {\n$>$.\n}$>") ("for" . "for ($${LIST}) {\n$>$.\n}$>") ("foreach" . "foreach my $${VAR} ($${LIST}) {\n$>$.\n}$>") ("formy" . "for my $${VAR} ($${LIST}) {\n$>$.\n}$>") ("given" . "given ($${VAR}) {\n$>$.\n}$>") ("when" . "when ($${TEST}) {\n$>$.\n}$>") ("if" . "if ($${TEST}) {\n$>$.\n}$>") ("sub" . "sub $${NAME}\n{\n$>$.\n}$>") ("unless" . "unless ($${TEST}) {\n$>$.\n}$>") ("until" . "until ($${TEST}) {\n$>$.\n}$>") ("while" . "while ($${TEST}) {\n$>$.\n}$>") ("whilekv" . "while (my ($k, $v) = each $${HASH}) {\n$>$.\n}$>")))) (add-hook 'sepia-mode-hook 'sepia-snippet-abbrev) Sepia-0.992/sepia-tree.el000644 000765 000765 00000011363 11530765553 015462 0ustar00seanoseano000000 000000 ;;; sepia-tree.el -- tree-widget-based calle[re] navigation ;; Copyright (C) 2004-2008 Sean O'Rourke. All rights reserved, some ;; wrongs reversed. This code is distributed under the same terms as ;; Perl itself. ;;; Commentary: ;; See the README file that comes with the distribution. ;;; Code: (require 'tree-widget) (require 'cl) (defvar sepia-tree-use-image nil "*If non-nil, show tree-widget with icons.") (defun sepia-tree-button-cb (widget &rest blah) (let* ((pw (widget-get widget :parent)) (wid-name (widget-get pw :sepia-name)) (location (and wid-name (car (xref-location wid-name))))) (cond ((not location) (error "Can't find %s." wid-name)) (current-prefix-arg (find-file-other-window (car location)) (sepia-set-found (list location) 'function) (sepia-next)) ((widget-get widget :sepia-shown-p) (save-excursion (end-of-line) (let ((inhibit-read-only t)) (delete-region (point) (+ 1 (point) (widget-get widget :sepia-shown-p)))) (widget-put widget :sepia-shown-p nil))) (t (let ((str (apply #'sepia-extract-def location))) (if str (save-excursion (end-of-line) (widget-put widget :sepia-shown-p (length str)) (widget-insert "\n" str)) (message "(not found)"))))))) (defun sepia-tree-node-cb (widget &rest blah) (let ((func (widget-get widget :sepia-func))) (or (widget-get widget :args) (let ((children (funcall func widget))) (if children (mapcar (lambda (x) (sepia-tree-node func x)) children) (widget-put widget :has-children nil)))))) (defun sepia-tree-node (func name) "Make a tree node for the object specified by FILE, LINE, OBJ, and MOD. The new node will have a property :sepia-X corresponding to each of these values. FUNC is a function that will, given a widget, generate its children." `(tree-widget :node (push-button :tag ,name :format "%[%t%]\n" :notify sepia-tree-button-cb) :dynargs sepia-tree-node-cb :has-children t :sepia-name ,name :sepia-func ,func)) (defun sepia-tree-tidy-buffer (name) "Get/create a new, tidy buffer for the tree widget." (switch-to-buffer name) (kill-all-local-variables) ;; because the widget images are ugly. (set (make-local-variable 'widget-image-enable) sepia-tree-use-image) (let ((inhibit-read-only t)) (erase-buffer)) (let ((all (overlay-lists))) (mapcar #'delete-overlay (car all)) (mapcar #'delete-overlay (cdr all))) (toggle-read-only 1) (view-mode -1)) (defun sepia-build-tree-buffer (func defs bufname) (if defs (lexical-let ((func func)) (sepia-tree-tidy-buffer bufname) (with-current-buffer bufname (dolist (x defs) (widget-create (sepia-tree-node (lambda (widget) (funcall func (widget-get widget :sepia-name))) x))) (use-local-map (copy-keymap widget-keymap)) ;; (local-set-key "\M-." sepia-keymap) ;; (sepia-install-keys) (let ((view-read-only nil)) (toggle-read-only 1)) (goto-char (point-min)) (message "Type C-h m for usage information"))) (message "No items for %s" bufname))) ;;;###autoload (defun sepia-callee-tree (name) "Create a tree view of a function's callees. Pressing RET on a function's name displays its definition. With prefix argument, RET instead visits in another window." (interactive (let ((func (sepia-interactive-arg 'function)) (mod (sepia-interactive-module))) (list (if mod (format "%s::%s" mod func) func)))) (let* ((defs (xref-apropos name))) (sepia-build-tree-buffer #'xref-callees defs (format "*%s callees*" name)))) (defun sepia-caller-tree (name) "Create a tree view of a function's callers. Pressing RET on a function's name displays its definition. With prefix argument, RET instead visits in another window." (interactive (let ((func (sepia-interactive-arg 'function)) (mod (sepia-interactive-module))) (list (if mod (format "%s::%s" mod func) func)))) (let* ((defs (xref-apropos name))) (sepia-build-tree-buffer #'xref-callers defs (format "*%s callers*" name)))) ;;;###autoload (defun sepia-module-callee-tree (mod) "Display a callee tree for each of MOD's subroutines. Pressing RET on a function's name displays its definition. With prefix argument, RET instead visits in another window." (interactive (list (sepia-interactive-arg 'module))) (let ((defs (xref-mod-subs mod))) (sepia-build-tree-buffer #'xref-callees defs (format "*%s subs*" mod)))) (provide 'sepia-tree) ;;; sepia.el ends here Sepia-0.992/sepia-w3m.el000644 000765 000765 00000011554 11461174202 015217 0ustar00seanoseano000000 000000 ;;; sepia-w3m.el --- The add-on program to view Perl documents. ;; Copyright (C) 2001 TSUCHIYA Masatoshi ;; Modified 2004-2008 by Sean O'Rourke to work with Sepia and operate ;; on buffer. ;; Author: TSUCHIYA Masatoshi ;; Keywords: w3m, perldoc ;; This file is a part of emacs-w3m. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, you can either send email to this ;; program's maintainer or write to: The Free Software Foundation, ;; Inc.; 59 Temple Place, Suite 330; Boston, MA 02111-1307, USA. ;;; Commentary: ;; w3m-perldoc.el is the add-on program of emacs-w3m to view Perl ;; documents. For more detail about emacs-w3m, see: ;; ;; http://emacs-w3m.namazu.org/ ;;; Code: (eval-when-compile (require 'w3m-perldoc)) ;;;###autoload (defun w3m-about-perldoc-buffer (url &optional no-decode no-cache &rest args) "Handle about://perldoc-buffer/ links." (when (string-match "\\`about://perldoc-buffer/" url) (let ((buf (get-buffer (w3m-url-decode-string (substring url (match-end 0))))) (default-directory w3m-profile-directory) (process-environment (copy-sequence process-environment))) ;; To specify the place in which pod2html generates its cache files. (setenv "HOME" (expand-file-name w3m-profile-directory)) (insert-buffer-substring buf) (if (zerop (apply #'call-process-region (point-min) (point-max) w3m-perldoc-pod2html-command t '(t nil) nil (append w3m-perldoc-pod2html-arguments '("--index" "--htmlroot=about://perldoc-buffer")))) (let ((case-fold-search t)) (goto-char (point-min)) (while (re-search-forward "" nil t) (delete-region (match-beginning 3) (match-end 3)) (save-restriction (narrow-to-region (match-beginning 2) (match-end 2)) (while (search-backward "/" nil t) (delete-char 1) (insert "::")) (goto-char (point-max)))) "text/html") ;; something went wrong (message "POD errors in %s" buf) (display-buffer (current-buffer)))))) ;;;###autoload (defun sepia-w3m-view-pod (&optional buffer) (require 'w3m) (w3m-goto-url (concat "about://perldoc-buffer/" (w3m-url-encode-string (buffer-name buffer))))) ;;;###autoload (defun sepia-module-list () "List installed modules with links to their documentation. This lists not just top-level packages appearing in packlist files, but all documented modules on the system, organized by package." (interactive) (let ((file "/tmp/modlist.html")) (unless (file-exists-p file) (sepia-eval (format "Sepia::html_module_list(\"%s\")" file))) (w3m-find-file file))) ;;;###autoload (defun sepia-package-list () "List installed packages with links to their documentation. This lists only top-level packages appearing in packlist files. For modules within packages, see `sepia-module-list'." (interactive) (let ((file "/tmp/packlist.html")) (unless (file-exists-p file) (sepia-eval (format "Sepia::html_package_list(\"%s\")" file))) (w3m-find-file file))) (defun sepia-w3m-create-imenu () "Create imenu index from pod2html output." (save-excursion (goto-char (point-min)) (when (looking-at "Location: \\(about://perldoc/[^#]+\\)") (let ((base (match-string 1)) beg end list) (w3m-view-source) (search-forward "") (setq beg (point)) (search-forward "") (setq end (point)) (goto-char beg) (while (re-search-forward "\\([^<]+\\)" end t) (push (cons (match-string 2) (match-string 1)) list)) (w3m-view-source) (nreverse list))))) (defun sepia-w3m-goto-function (name anchor) (if (string-match "^about://perldoc/" w3m-current-url) (w3m-goto-url (concat w3m-current-url anchor)) (imenu-default-goto-function name anchor))) (defun sepia-w3m-install-imenu () (setq imenu-create-index-function 'sepia-w3m-create-imenu imenu-default-goto-function 'sepia-w3m-goto-function)) (provide 'sepia-w3m) ;;; sepia-w3m.el ends here. Sepia-0.992/sepia.el000644 000765 000765 00000213132 11651225542 014514 0ustar00seanoseano000000 000000 ;;; Sepia -- Simple Emacs-Perl InterAction: ugly, yet effective. ;; (a.k.a. Septik -- Sean's Emacs-Perl Total Integration Kludge.) ;; Author: Sean O'Rourke ;; Keywords: Perl, languages ;; Copyright (C) 2004-2011 Sean O'Rourke. All rights reserved, some ;; wrongs reversed. This code is distributed under the same terms ;; as Perl itself. ;;; Commentary: ;; Sepia is a set of tools for Perl development in Emacs. Its goal is ;; to extend CPerl mode with two contributions: fast code navigation ;; and interactive development. It is inspired by Emacs' current ;; support for a number of other languages, including Lisp, Python, ;; Ruby, and Emacs Lisp. ;; ;; See sepia.texi, which comes with the distribution. ;;; Code: (require 'cperl-mode) (require 'gud) (require 'cl) ;; try optional modules, but don't bitch if we fail: (ignore-errors (require 'sepia-w3m)) (ignore-errors (require 'sepia-tree)) (ignore-errors (require 'sepia-ido)) (ignore-errors (require 'sepia-snippet)) ;; extensions that should always load (autoload later?) (require 'sepia-cpan) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Comint communication (defvar sepia-perl5lib nil "* List of extra PERL5LIB directories for `sepia-repl'.") (defvar sepia-program-name "perl" "* Perl program name.") (defvar sepia-view-pod-function (if (featurep 'w3m) 'sepia-w3m-view-pod 'sepia-perldoc-buffer) "* Function to view current buffer's documentation. Useful values include `sepia-w3m-view-pod' and `sepia-perldoc-buffer'.") (defvar sepia-module-list-function (if (featurep 'w3m) 'w3m-find-file 'browse-url-of-file) "* Function to view a list of installed modules. Useful values include `w3m-find-file' and `browse-url-of-file'.") (defvar sepia-complete-methods t "* Non-nil if Sepia should try to complete methods for \"$x->\". NOTE: this feature can be problematic, since it evaluates the object in order to find its type. Currently completion is only attempted for objects that are simple scalars.") (defvar sepia-indent-expand-abbrev t "* If non-NIL, `sepia-indent-or-complete' tries `expand-abbrev'.") (defvar sepia-use-completion t "* Use completion based on Xref database. Turning this off may speed up some operations, if you don't mind losing completion.") (defvar sepia-eval-defun-include-decls t "* Generate and use a declaration list for `sepia-eval-defun'. Without this, code often will not parse; with it, evaluation may be a bit less responsive. Note that since this only includes subs from the evaluation package, it may not always work.") (defvar sepia-prefix-key "\M-." "* Prefix for functions in `sepia-keymap'.") ;;; User options end here. (defvar sepia-process nil "The perl process with which we're interacting.") (defvar sepia-output nil "Current perl output for a response to `sepia-eval-raw', appended to by `sepia-collect-output'.") (defvar sepia-passive-output "" "Current perl output for miscellaneous user interaction, used to look for \";;;###\" lisp evaluation markers.") (defvar sepia-perl-builtins nil "List of Perl builtins for completion.") (defun sepia-collect-output (string) "Collect perl output for `sepia-eval-raw' into sepia-output." (setq sepia-output (concat sepia-output string)) "") (defun sepia-eval-raw (str) "Evaluate perl code STR, returning a pair (RESULT-STRING . OUTPUT)." (sepia-ensure-process) (let (ocpof) (unwind-protect (let ((sepia-output "") (start 0)) (with-current-buffer (process-buffer sepia-process) (setq ocpof comint-preoutput-filter-functions comint-preoutput-filter-functions '(sepia-collect-output))) (setq str (concat "local $Sepia::STOPDIE=0;" "local $Sepia::STOPWARN=0;" "{ package " (sepia-buffer-package) ";" str " }\n")) (comint-send-string sepia-process (concat (format "<<%d\n" (length str)) str)) (while (not (and sepia-output (string-match "> $" sepia-output))) (accept-process-output sepia-process)) (if (string-match "^;;;[0-9]+\n" sepia-output) (cons (let* ((x (read-from-string sepia-output (+ (match-beginning 0) 3))) (len (car x)) (pos (cdr x))) (prog1 (substring sepia-output (1+ pos) (+ len pos 1)) (setq start (+ pos len 1)))) (and (string-match ";;;[0-9]+\n" sepia-output start) (let* ((x (read-from-string sepia-output (+ (match-beginning 0) 3))) (len (car x)) (pos (cdr x))) (substring sepia-output (1+ pos) (+ len pos 1))))) (cons sepia-output nil))) (with-current-buffer (process-buffer sepia-process) (setq comint-preoutput-filter-functions ocpof))))) (defun sepia-eval (str &optional context detailed) "Evaluate STR in CONTEXT (void by default), and return its result as a Lisp object. If DETAILED is specified, return a pair (RESULT . OUTPUT)." (let* ((tmp (sepia-eval-raw (case context (list-context (concat "Sepia::tolisp([" str "])")) (scalar-context (concat "Sepia::tolisp(scalar(" str "))")) (t (concat str ";1"))))) (res (car tmp)) (errs (cdr tmp))) (setq res (if context (if (string= res "") "" (car (read-from-string res))) 1)) (if detailed (cons res errs) res))) (defun sepia-call (fn context &rest args) "Call perl function FN in CONTEXT with arguments ARGS, returning its result as a Lisp value." (sepia-eval (concat fn "(" (mapconcat #'sepia-lisp-to-perl args ", ") ")") context)) (defun sepia-watch-for-eval (string) "Monitor inferior Perl output looking for Lisp evaluation requests. The format for these requests is \"\\n;;;###LENGTH\\nDATA\". Only one such request can come from each inferior Perl prompt." (setq sepia-passive-output (concat sepia-passive-output string)) (cond ((string-match "^;;;###[0-9]+" sepia-passive-output) (if (string-match "^;;;###\\([0-9]+\\)\n\\(?:.\\|\n\\)*\n\\(.*> \\)" sepia-passive-output) (let* ((len (car (read-from-string (match-string 1 sepia-passive-output)))) (pos (1+ (match-end 1))) (res (ignore-errors (eval (car (read-from-string sepia-passive-output pos (+ pos len))))))) (message "%s => %s" (substring sepia-passive-output pos (+ pos len)) res) (goto-char (point-max)) (insert (substring sepia-passive-output (+ 1 pos len))) (set-marker (process-mark (get-buffer-process (current-buffer))) (point)) (setq sepia-passive-output "")) "")) (t (setq sepia-passive-output "") string))) (defvar sepia-metapoint-map (let ((map (make-sparse-keymap))) (when (featurep 'ido) (define-key map "j" 'sepia-jump-to-symbol)) (dolist (kv '(("c" . sepia-callers) ("C" . sepia-callees) ("a" . sepia-apropos) ("A" . sepia-var-apropos) ("v" . sepia-var-uses) ("V" . sepia-var-defs) ;; ("V" . sepia-var-assigns) ("\M-." . sepia-dwim) ;; ("\M-." . sepia-location) ("d" . sepia-location) ("f" . sepia-defs) ("r" . sepia-rebuild) ("m" . sepia-module-find) ("n" . sepia-next) ("t" . find-tag) ("p" . sepia-perldoc-this) ("l" . sepia-pod-follow-link-at-point) ("u" . sepia-describe-object))) (define-key map (car kv) (cdr kv))) map) "Keymap for Sepia functions. This is just an example of how you might want to bind your keys, which works best when bound to `\\M-.'.") (defvar sepia-shared-map (let ((map (make-sparse-keymap))) (define-key map sepia-prefix-key sepia-metapoint-map) (define-key map "\M-," 'sepia-next) (define-key map "\C-\M-x" 'sepia-eval-defun) (define-key map "\C-c\C-l" 'sepia-load-file) (define-key map "\C-cn" 'sepia-perl-ne-region) (define-key map "\C-c\C-p" 'sepia-view-pod) ;was cperl-pod-spell (define-key map "\C-cp" 'sepia-perl-pe-region) (define-key map "\C-c\C-d" 'cperl-perldoc) ;; (define-key map "\C-c\C-t" 'sepia-repl) (define-key map "\C-c\C-t" 'cperl-invert-if-unless) (define-key map "\C-c\C-r" 'sepia-eval-region) (define-key map "\C-c\C-s" 'sepia-scratch) (define-key map "\C-c\C-e" 'sepia-eval-expression) (define-key map "\C-c!" 'sepia-set-cwd) (define-key map (kbd "TAB") 'sepia-indent-or-complete) map) "Sepia bindings common to all modes.") ;;;###autoload (defun sepia-eval-region (beg end) "Evaluate region using current Sepia process." (interactive "r") (sepia-eval (buffer-substring beg end))) ;;;###autoload (defun sepia-perldoc-this (name) "View perldoc for module at point." (interactive (list (sepia-interactive-arg 'module))) (let ((wc (current-window-configuration)) (old-pd (symbol-function 'w3m-about-perldoc)) (old-pdb (symbol-function 'w3m-about-perldoc-buffer)) buf) (condition-case stuff (flet ((w3m-about-perldoc (&rest args) (let ((res (apply old-pd args))) (or res (error "lose: %s" args)))) (w3m-about-perldoc-buffer (&rest args) (let ((res (apply old-pdb args))) (or res (error "lose: %s" args))))) (funcall (if (featurep 'w3m) 'w3m-perldoc 'cperl-perldoc) name) (setq buf (current-buffer))) (error (set-window-configuration wc))) (set-window-configuration wc) (pop-to-buffer buf t))) (defun sepia-view-pod () "View POD for the current buffer." (interactive) (funcall sepia-view-pod-function)) (defun sepia-module-list () "List installed modules with links to their documentation. This lists not just top-level packages appearing in packlist files, but all documented modules on the system, organized by package." (interactive) (let ((file "/tmp/modlist.html")) ;; (unless (file-exists-p file) (sepia-eval-raw (format "Sepia::html_module_list(\"%s\")" file)) (funcall sepia-module-list-function file))) (defun sepia-package-list () "List installed packages with links to their documentation. This lists only top-level packages appearing in packlist files. For modules within packages, see `sepia-module-list'." (interactive) (let ((file "/tmp/packlist.html")) ;; (unless (file-exists-p file) (sepia-eval-raw (format "Sepia::html_package_list(\"%s\")" file)) (funcall sepia-module-list-function file))) (defun sepia-perldoc-buffer () "View current buffer's POD using pod2html and `browse-url'. Interactive users should call `sepia-view-pod'." (let ((buffer (get-buffer-create "*sepia-pod*")) (errs (get-buffer-create "*sepia-pod-errors*")) (inhibit-read-only t)) (with-current-buffer buffer (erase-buffer)) (save-window-excursion (shell-command-on-region (point-min) (point-max) "pod2html" buffer nil errs)) (with-current-buffer buffer (browse-url-of-buffer)))) (defun sepia-perl-name (sym &optional mod) "Convert a Perl name to a Lisp name." (setq sym (substitute ?_ ?- (if (symbolp sym) (symbol-name sym) sym))) (if mod (concat mod "::" sym) sym)) (defun sepia-live-p () (and (processp sepia-process) (eq (process-status sepia-process) 'run))) (defun sepia-ensure-process (&optional remote-host) (unless (sepia-live-p) (with-current-buffer (get-buffer-create "*sepia-repl*") (sepia-repl-mode) (set (make-local-variable 'sepia-passive-output) "")) (if remote-host (comint-exec (get-buffer-create "*sepia-repl*") "attachtty" "attachtty" nil (list remote-host)) (let ((stuff (split-string sepia-program-name nil t))) (comint-exec (get-buffer-create "*sepia-repl*") "perl" (car stuff) nil (append (cdr stuff) (mapcar (lambda (x) (concat "-I" x)) sepia-perl5lib) '("-MSepia" "-MSepia::Xref" "-e" "Sepia::repl"))))) (setq sepia-process (get-buffer-process "*sepia-repl*")) (accept-process-output sepia-process 1) ;; Steal a bit from gud-common-init: (setq gud-running t) (setq gud-last-last-frame nil) (set-process-filter sepia-process 'gud-filter) (set-process-sentinel sepia-process 'gud-sentinel))) ;;;###autoload (defun sepia-repl (&optional remote-host) "Start the Sepia REPL." (interactive (list (and current-prefix-arg (read-string "Host: ")))) (sepia-init) ;; set up keymaps, etc. (sepia-ensure-process remote-host) (pop-to-buffer (get-buffer "*sepia-repl*"))) (defun sepia-cont-or-restart () (interactive) (if (get-buffer-process (current-buffer)) (gud-cont current-prefix-arg) (sepia-repl))) (defvar sepia-repl-mode-map (let ((map (copy-keymap sepia-shared-map))) (set-keymap-parent map gud-mode-map) (define-key map (kbd "") 'comint-dynamic-complete) (define-key map "\C-a" 'comint-bol) (define-key map "\C-c\C-r" 'sepia-cont-or-restart) map) "Keymap for Sepia interactive mode.") (define-derived-mode sepia-repl-mode gud-mode "Sepia REPL" "Major mode for the Sepia REPL. \\{sepia-repl-mode-map}" ;; (set (make-local-variable 'comint-use-prompt-regexp) t) (modify-syntax-entry ?: "_") (modify-syntax-entry ?> ".") (set (make-local-variable 'comint-prompt-regexp) "^[^>\n]*> *") (set (make-local-variable 'gud-target-name) "sepia") (set (make-local-variable 'gud-marker-filter) 'sepia-gud-marker-filter) (set (make-local-variable 'gud-minor-mode) 'sepia) (sepia-install-eldoc) (setq gud-comint-buffer (current-buffer)) (setq gud-last-last-frame nil) (setq gud-sepia-acc nil) (gud-def gud-break ",break %f:%l" "\C-b" "Set breakpoint at current line.") (gud-def gud-step ",step %p" "\C-s" "Step one line.") (gud-def gud-next ",next %p" "\C-n" "Step one line, skipping calls.") (gud-def gud-cont ",continue" "\C-r" "Continue.") (gud-def gud-print "%e" "\C-p" "Evaluate something.") (gud-def gud-remove ",delete %l %f" "\C-d" "Delete current breakpoint.") ;; Sadly, this hoses our keybindings. (compilation-shell-minor-mode 1) (set (make-local-variable 'comint-dynamic-complete-functions) '(sepia-complete-symbol comint-dynamic-complete-filename)) (set (make-local-variable 'comint-preoutput-filter-functions) '(sepia-watch-for-eval)) (run-hooks 'sepia-repl-mode-hook) ) (defvar gud-sepia-acc nil "Accumulator for `sepia-gud-marker-filter'.") (defun sepia-gud-marker-filter (str) (setq gud-sepia-acc (if gud-sepia-acc (concat gud-sepia-acc str) str)) (while (string-match "_<\\([^:>]+\\):\\([0-9]+\\)>\\(.*\\)" gud-sepia-acc) (setq gud-last-last-frame gud-last-frame gud-last-frame (cons (match-string 1 gud-sepia-acc) (string-to-number (match-string 2 gud-sepia-acc))) gud-sepia-acc (match-string 3 gud-sepia-acc))) (setq gud-sepia-acc (if (string-match "\\(_<.*\\)" gud-sepia-acc) (match-string 1 gud-sepia-acc) nil)) str) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Xref (defun define-xref-function (package name doc) "Define a lisp mirror for a low-level Sepia function." (let ((lisp-name (intern (format "xref-%s" name))) (pl-name (sepia-perl-name name package))) (fmakunbound lisp-name) (eval `(defun ,lisp-name (&rest args) ,doc (apply #'sepia-call ,pl-name 'list-context args))))) (defun define-modinfo-function (name &optional doc context) "Define a lisp mirror for a function from Module::Info." (let ((name (intern (format "sepia-module-%s" name))) (pl-func (sepia-perl-name name)) (full-doc (concat (or doc "") " This function uses Module::Info, so it does not require that the module in question be loaded."))) (when (fboundp name) (fmakunbound name)) (eval `(defun ,name (mod) ,full-doc (interactive (list (sepia-interactive-arg 'module))) (sepia-maybe-echo (sepia-call "Sepia::module_info" ',(or context 'scalar-context) mod ,pl-func) (interactive-p)))))) (defun sepia-thing-at-point (what) "Like `thing-at-point', but hacked to avoid REPL prompt." (let ((th (thing-at-point what))) (and th (not (string-match "[ >]$" th)) th))) (defvar sepia-sub-re "^ *sub\\s +\\(.+\\_>\\)") (defvar sepia-history nil) (defun sepia-interactive-arg (&optional sepia-arg-type) "Default argument for most Sepia functions. TYPE is a symbol -- either 'file to look for a file, or anything else to use the symbol at point." (let* ((default (case sepia-arg-type (file (or (thing-at-point 'file) (buffer-file-name))) (t (sepia-thing-at-point 'symbol)))) (text (capitalize (symbol-name sepia-arg-type))) (choices (lambda (str &rest blah) (let ((completions (xref-completions (case sepia-arg-type (module nil) (variable "VARIABLE") (function "CODE") (t nil)) str))) (when (eq sepia-arg-type 'module) (setq completions (remove-if (lambda (x) (string-match "::$" x)) completions))) completions))) (prompt (if default (format "%s [%s]: " text default) (format "%s: " text))) (ret (if sepia-use-completion (completing-read prompt 'blah-choices nil nil nil 'sepia-history default) (read-string prompt nil 'sepia-history default)))) (push ret sepia-history) ret)) (defun sepia-interactive-module () "Guess which module we should look things up in. Prompting for a module all the time is a PITA, but I don't think this (choosing the current file's module) is a good alternative, either. Best would be to choose the module based on what we know about the symbol at point." (let ((xs (xref-file-modules (buffer-file-name)))) (if (= (length xs) 1) (car xs) nil))) (defun sepia-maybe-echo (result &optional print-message) (when print-message (message "%s" result)) result) (defun sepia-find-module-file (mod) (or (sepia-module-file mod) (car (xref-guess-module-file mod)))) (defun sepia-module-find (mod) "Find the file defining module MOD." (interactive (list (sepia-interactive-arg 'module))) (let ((fn (sepia-find-module-file mod))) (if fn (progn (message "Module %s in %s." mod fn) (pop-to-buffer (find-file-noselect (expand-file-name fn)))) (message "Can't find module %s." mod)))) (defmacro ifa (test then &rest else) `(let ((it ,test)) (if it ,then ,@else))) (defvar sepia-found-refiner nil) (defun sepia-show-locations (locs &optional unobtrusive) (setq locs (remove nil locs)) ; XXX where's nil from? (if locs (with-current-buffer (get-buffer-create "*sepia-places*") (let ((inhibit-read-only t)) (erase-buffer) (insert (format "-*- mode: grep; default-directory: %S -*-\n\n" default-directory)) (dolist (loc (sort locs (lambda (a b) (or (string< (car a) (car b)) (and (string= (car a) (car b)) (< (second a) (second b))))))) (destructuring-bind (file line name &rest blah) loc (let ((str (ifa (find-buffer-visiting file) (with-current-buffer it (ifa sepia-found-refiner (funcall it line name) (goto-line line)) (unless (= (line-number-at-pos) line) (message "line for %s was %d, now %d" name line (line-number-at-pos))) (setq line (line-number-at-pos)) (let ((tmpstr (buffer-substring (sepia-bol-from) (sepia-eol-from)))) (if (> (length tmpstr) 60) (concat "\n " tmpstr) tmpstr))) "..."))) (insert (format "%s:%d:%s\n" (abbreviate-file-name file) line str))))) (insert "\nGrep finished (matches found).\n") (grep-mode)) (if unobtrusive (save-window-excursion (next-error nil t)) (next-error nil t))) (message "No matches found."))) (defmacro define-sepia-query (name doc &optional gen test prompt) "Define a sepia querying function." `(defun ,name (ident &optional module file line display-p) ,(concat doc " With prefix arg, display matches in a `grep-mode' buffer. Without, go to the first match; calling `sepia-next' will cycle through subsequent matches. Depending on the query, MODULE, FILE, and LINE may be used to narrow the results, as long as doing so leaves some matches. When called interactively, they are taken from the current buffer. ") (interactive (list (sepia-interactive-arg ,(or prompt ''function)) (sepia-interactive-module) (buffer-file-name) (line-number-at-pos (point)) current-prefix-arg )) (let ((ret ,(if test `(let ((tmp (,gen ident module file line))) (or (mapcan #',test tmp) tmp)) `(,gen ident module file line)))) (sepia-show-locations ret (not display-p))))) (define-sepia-query sepia-defs "Find all definitions of sub." xref-apropos xref-location) (define-sepia-query sepia-callers "Find callers of FUNC." xref-callers xref-location) (define-sepia-query sepia-callees "Find a sub's callees." xref-callees xref-location) (define-sepia-query sepia-var-defs "Find a var's definitions." xref-var-defs (lambda (x) (setf (third x) ident) (list x)) 'variable) (define-sepia-query sepia-var-uses "Find a var's uses." xref-var-uses (lambda (x) (setf (third x) ident) (list x)) 'variable) (define-sepia-query sepia-var-assigns "Find/list assignments to a variable." xref-var-assigns (lambda (x) (setf (third x) ident) (list x)) 'variable) (defalias 'sepia-package-defs 'sepia-module-describe) (define-sepia-query sepia-apropos "Find/list subroutines matching regexp." (lambda (name &rest blah) (xref-apropos name 1)) xref-location 'function) (define-sepia-query sepia-var-apropos "Find/list variables matching regexp." xref-var-apropos xref-var-defs 'variable) (defun sepia-location (name &optional jump-to) "Find the definition of NAME. When called interactively (or with JUMP-TO true), go directly to this location." (interactive (list (sepia-interactive-arg 'function) t)) (let* ((fl (or (car (xref-location name)) (car (remove-if #'null (apply #'xref-location (xref-apropos name))))))) (when (and (car fl) (string-match "^(eval " (car fl))) (message "Can't find definition of %s in %s." name (car fl)) (setq fl nil)) (if jump-to (if fl (progn (sepia-set-found (list fl) 'function) (sepia-next)) (message "No definition for %s." name)) fl))) ;;;###autoload (defun sepia-dwim (&optional display-p) "Try to do the right thing with identifier at point. * Find all definitions, if thing-at-point is a function * Find all uses, if thing-at-point is a variable * Find documentation, if thing-at-point is a module * Prompt otherwise " (interactive "P") (multiple-value-bind (type obj) (sepia-ident-at-point) (let* ((module-doc-p nil) (ret (cond ((member type '(?% ?$ ?@)) (xref-var-defs obj)) ((or (equal type ?&) (let (case-fold-search) (string-match "^[^A-Z]" obj))) (list (sepia-location obj))) ((sepia-looks-like-module obj) (setq module-doc-p t) `((,(sepia-perldoc-this obj) 1 nil nil))) (t (setq module-doc-p t) (call-interactively 'sepia-defs))))) (unless module-doc-p (sepia-show-locations ret (not display-p)))))) (defun sepia-rebuild () "Rebuild the Xref database." (interactive) (xref-rebuild)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Perl motion commands. ;;; XXX -- these are a hack to prevent infinite recursion calling ;;; e.g. beginning-of-defun from beginning-of-defun-function. ;;; `beginning-of-defun' should handle this. (defmacro sepia-safe-bodf (&optional n) `(let ((beginning-of-defun-function (if (and (boundp 'beginning-of-defun-function) (eq beginning-of-defun-function 'sepia-beginning-of-defun)) nil beginning-of-defun-function))) (beginning-of-defun ,n))) (defmacro sepia-safe-eodf (&optional n) `(let ((end-of-defun-function (if (and (boundp 'end-of-defun-function) (eq end-of-defun-function 'sepia-end-of-defun)) nil end-of-defun-function))) (end-of-defun ,n))) (defun sepia-beginning-of-defun (&optional n) "Move to beginning of current function. The prefix argument is the same as for `beginning-of-defun'." (interactive "p") (setq n (or n 1)) (ignore-errors (when (< n 0) (sepia-end-of-defun (- n)) (setq n 1)) (re-search-backward sepia-sub-re nil nil n))) (defun sepia-inside-defun () "True if point is inside a sub." (condition-case nil (save-excursion (let ((cur (point))) (re-search-backward sepia-sub-re) (when (< (point) cur) (search-forward "{") (backward-char 1) (forward-sexp) (> (point) cur)))) (error nil))) (defun sepia-end-of-defun (&optional n) "Move to end of current function. The prefix argument is the same as for `end-of-defun'." (interactive "p") (setq n (or n 1)) (when (< n 0) (sepia-beginning-of-defun (- n)) (setq n 1)) ;; If we're outside a defun, skip to the next (ignore-errors (unless (sepia-inside-defun) (re-search-forward sepia-sub-re) (forward-char 1)) (dotimes (i n) (re-search-backward sepia-sub-re) (search-forward "{") (backward-char 1) (forward-sexp)) (point))) (defun sepia-rename-lexical (old new &optional prompt) "Replace lexical variable OLD with NEW in the current function. With prefix argument, query for each replacement. It is an error to call this outside a function." (interactive (let ((old (sepia-thing-at-point 'symbol))) (list (read-string "Old name: " old nil old) (read-string "New name: ") current-prefix-arg))) (message "(%s %s)" old new) (unless (sepia-inside-defun) (error "Can't rename %s outside a defun." old)) (setq old (concat "\\([$%@]\\)\\_<" (regexp-quote old) "\\_>") new (concat "\\1" new)) (let ((bod (sepia-beginning-of-defun)) (eod (sepia-end-of-defun))) (if prompt (query-replace-regexp old new nil bod eod) ;; (replace-regexp old new nil bod eod) (goto-char bod) (while (re-search-forward old eod t) (replace-match new))))) (defun sepia-defun-around-point (&optional where) "Return the text of function around point." (unless where (setq where (point))) (save-excursion (goto-char where) (and (sepia-beginning-of-defun) (match-string-no-properties 1)))) (defun sepia-lexicals-at-point (&optional where) "Find lexicals in scope at point." (interactive "d") (unless where (setq where (point))) (let ((subname (sepia-defun-around-point where)) (mod (sepia-buffer-package))) (xref-lexicals (sepia-perl-name subname mod)))) ;;;###autoload (defun sepia-load-file (file &optional rebuild-p collect-warnings) "Reload a file (interactively, the current buffer's file). With REBUILD-P (or a prefix argument when called interactively), also rebuild the xref database." (interactive (list (expand-file-name (buffer-file-name)) prefix-arg (format "*%s errors*" (buffer-file-name)))) (save-buffer) (when collect-warnings (let (kill-buffer-query-functions) (ignore-errors (kill-buffer collect-warnings)))) (let* ((tmp (sepia-eval (format "do '%s' || ($@ && do { local $Sepia::Debug::STOPDIE; die $@ })" file) 'scalar-context t)) (res (car tmp)) (errs (cdr tmp))) (message "sepia: %s returned %s" (abbreviate-file-name file) (if (equal res "") "undef" res)) (when (and collect-warnings (> (length errs) 1)) (with-current-buffer (get-buffer-create collect-warnings) (let ((inhibit-read-only t)) (delete-region (point-min) (point-max)) (insert errs) (sepia-display-errors (point-min) (point-max)) (pop-to-buffer (current-buffer)))))) (when rebuild-p (xref-rebuild))) (defvar sepia-found) (defun sepia-set-found (list &optional type) (setq list (remove-if (lambda (x) (or (not x) (and (not (car x)) (string= (fourth x) "main")))) list)) (setq sepia-found (cons -1 list)) (setq sepia-found-refiner (sepia-refiner type))) (defun sepia-refiner (type) (case type (function (lambda (line ident) (let ((sub-re (concat "^\\s *sub\\s +.*" ident "\\_>"))) ;; Test this because sometimes we get lucky and get the line ;; just right, in which case beginning-of-defun goes to the ;; previous defun. (or (and line (progn (goto-line line) (beginning-of-defun) (looking-at sub-re))) (progn (goto-char (point-min)) (re-search-forward sub-re nil t))) (beginning-of-line)))) ;; Old version -- this may actually work better if ;; beginning-of-defun goes flaky on us. ;; (or (re-search-backward sub-re ;; (sepia-bol-from (point) -20) t) ;; (re-search-forward sub-re ;; (sepia-bol-from (point) 10) t)) ;; (beginning-of-line) (variable (lambda (line ident) (let ((var-re (concat "\\_<" ident "\\_>"))) (cond (line (goto-line line) (or (re-search-backward var-re (sepia-bol-from nil -5) t) (re-search-forward var-re (sepia-bol-from nil 5) t))) (t (goto-char (point-min)) (re-search-forward var-re nil t)))))) (t (lambda (line ident) (and line (goto-line line)))))) (defun sepia-next (&optional arg) "Go to the next thing (e.g. def, use) found by sepia." (interactive "p") (save-window-excursion (next-error arg))) (defun sepia-previous (&optional arg) "Go to the previous thing (e.g. def, use) found by sepia." (interactive "p") (or arg (setq arg 1)) (sepia-next (- arg))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Completion (defun sepia-ident-before-point () "Find the Perl identifier at or preceding point." (save-excursion (skip-syntax-backward " ") (backward-char 1) (sepia-ident-at-point))) (defun sepia-simple-method-before-point () "Find the \"simple\" method call before point. Looks for a simple method called on a variable before point and returns the list (OBJECT METHOD). For example, \"$x->blah\" returns '(\"$x\" \"blah\"). Only simple methods are recognized, because completing anything evaluates it, so completing complex expressions would lead to disaster." (when sepia-complete-methods (let ((end (point)) (bound (max (- (point) 100) (point-min))) arrow beg) (save-excursion ;; XXX - can't do this because COMINT's syntax table is weird. ;; (skip-syntax-backward "_w") (skip-chars-backward "a-zA-Z0-9_") (when (looking-back "->\\s *" bound) (setq arrow (search-backward "->" bound)) (skip-chars-backward "a-zA-Z0-9_:") (cond ;; $x->method ((char-equal (char-before (point)) ?$) (setq beg (1- (point)))) ;; X::Class->method ((multiple-value-bind (type obj) (sepia-ident-at-point) (and (not type) (sepia-looks-like-module obj))) (setq beg (point)))) (when beg (list (buffer-substring-no-properties beg arrow) (buffer-substring-no-properties (+ 2 arrow) end) (buffer-substring-no-properties beg end)))))))) (defun sepia-ident-at-point () "Find the Perl identifier at point." (save-excursion (let ((orig (point))) (when (looking-at "[%$@*&]") (forward-char 1)) (let* ((beg (progn (when (re-search-backward "[^A-Za-z_0-9:]" nil 'mu) (forward-char 1)) (point))) (sigil (if (= beg (point-min)) nil (char-before (point)))) (end (progn (when (re-search-forward "[^A-Za-z_0-9:]" nil 'mu) (forward-char -1)) (point)))) (if (= beg end) ;; try special variables (if (and (member (char-before orig) '(?$ ?@ ?%)) (member (car (syntax-after orig)) '(1 4 5 7 9))) (list (char-before orig) (buffer-substring-no-properties orig (1+ orig))) '(nil "")) ;; actual thing (list (when (member sigil '(?$ ?@ ?% ?* ?&)) sigil) (buffer-substring-no-properties beg end))))))) (defun sepia-function-at-point () "Find the Perl function called at point." (condition-case nil (save-excursion (let ((pt (point)) bof) (sepia-beginning-of-defun) (setq bof (point)) (goto-char pt) (sepia-end-of-defun) (when (and (>= pt bof) (< pt (point))) (sepia-beginning-of-defun) (when (and (= (point) bof) (looking-at "\\s *sub\\s +")) (forward-char (length (match-string 0))) (concat (or (sepia-buffer-package) "") "::" (cadr (sepia-ident-at-point))))))) (error nil))) (defun sepia-repl-complete () "Try to complete the word at point in the REPL. Just like `sepia-complete-symbol', except that it also completes REPL shortcuts." (interactive) (error "TODO")) (defvar sepia-shortcuts '( "break" "eval" "lsbreak" "quit" "size" "wantarray" "cd" "format" "methods" "reload" "strict" "who" "debug" "freload" "package" "restart" "test" "define" "help" "pdl" "save" "time" "delete" "load" "pwd" "shell" "undef" ) "List of currently-defined REPL shortcuts. XXX: this needs to be updated whenever you add one on the Perl side.") (defun sepia-complete-symbol () "Try to complete the word at point. The word may be either a global or lexical variable if it has a sigil, a module, or a function. The function currently ignores module qualifiers, which may be annoying in larger programs. The function is intended to be bound to \\M-TAB, like `lisp-complete-symbol'." (interactive) (let ((win (get-buffer-window "*Completions*" 0)) len completions type meth) (if (and (eq last-command this-command) win (window-live-p win) (window-buffer win) (buffer-name (window-buffer win))) ;; If this command was repeated, and ;; there's a fresh completion window with a live buffer, ;; and this command is repeated, scroll that window. (with-current-buffer (window-buffer win) (if (pos-visible-in-window-p (point-max) win) (set-window-start win (point-min)) (save-selected-window (select-window win) (scroll-up)))) ;; Otherwise actually do completion: ;; 0 - try a shortcut (when (eq major-mode 'sepia-repl-mode) (save-excursion (comint-bol) (when (looking-at ",\\([a-z]+\\)$") (let ((str (match-string 1))) (setq len (length str) completions (all-completions str sepia-shortcuts)))))) ;; 1 - Look for a method call: (unless completions (setq meth (sepia-simple-method-before-point)) (when meth (setq len (length (caddr meth)) completions (xref-method-completions (cons 'expr (format "'%s'" (car meth))) (cadr meth) "Sepia::repl_eval") type (format "%s->" (car meth))))) ;; 1.x - look for a module (unless completions (setq completions (and (looking-back " *\\(?:use\\|require\\|package\\|no\\)\\s +[^ ]*" (sepia-bol-from)) (xref-apropos-module (multiple-value-bind (typ name) (sepia-ident-before-point) (setq len (length name)) name)) ))) (multiple-value-bind (typ name) (sepia-ident-before-point) (unless completions ;; 2 - look for a regular function/variable/whatever (setq type typ len (+ (if type 1 0) (length name)) completions (mapcar (lambda (x) (if (or (not type) (eq type ?&)) x (format "%c%s" type x))) (xref-completions (case type (?$ "VARIABLE") (?@ "ARRAY") (?% "HASH") (?& "CODE") (?* "IO") (t "")) name (and (eq major-mode 'sepia-mode) (sepia-function-at-point)))))) ;; 3 - try a Perl built-in (when (and (not completions) (or (not type) (eq type ?&))) (when (string-match ".*::([^:]+)$" name) (setq name (match-string 1 name))) (setq completions (all-completions name sepia-perl-builtins))) (case (length completions) (0 (message "No completions.") nil) (1 ;; XXX - skip sigil to match s-i-before-point (delete-region (- (point) len) (point)) (insert (car completions)) ;; Hide stale completions buffer (stolen from lisp.el). (if win (with-selected-window win (bury-buffer))) t) (t (let ((old name) (new (try-completion "" completions))) (if (<= (length new) (+ (length old) (if type 1 0))) (with-output-to-temp-buffer "*Completions*" (display-completion-list completions)) (let ((win (get-buffer-window "*Completions*" 0))) (if win (with-selected-window win (bury-buffer)))) (delete-region (- (point) len) (point)) (insert new)))))) t))) (defun sepia-indent-or-complete () "Indent the current line or complete the symbol around point. Specifically, try completion when indentation doesn't move point. This function is intended to be bound to TAB." (interactive) (let ((pos (point))) (let (beginning-of-defun-function end-of-defun-function) (cperl-indent-command)) (when (and (= pos (point)) (not (bolp)) (or (eq last-command 'sepia-indent-or-complete) (looking-at "\\_>"))) (when (or (not sepia-indent-expand-abbrev) (and (not (expand-abbrev)) ;; XXX this shouldn't be necessary, but ;; expand-abbrev returns NIL for e.g. the "else" ;; snippet. (= pos (point)))) (sepia-complete-symbol))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; scratchpad code (defvar sepia-mode-map (let ((map (copy-keymap sepia-shared-map))) (set-keymap-parent map cperl-mode-map) (define-key map "\C-c\C-h" nil) map) "Keymap for Sepia mode.") ;;;###autoload (define-derived-mode sepia-mode cperl-mode "Sepia" "Major mode for Perl editing, derived from cperl mode. \\{sepia-mode-map}" (sepia-init) (sepia-install-eldoc) (sepia-doc-update) (set (make-local-variable 'beginning-of-defun-function) 'sepia-beginning-of-defun) (set (make-local-variable 'end-of-defun-function) 'sepia-end-of-defun) (setq indent-line-function 'sepia-indent-line)) (defun sepia-init () "Perform the initialization necessary to start Sepia." ;; Load perl defs: ;; Create glue wrappers for Module::Info funcs. (unless (fboundp 'xref-completions) (dolist (x '((name "Find module name.\n\nDoes not require loading.") (version "Find module version.\n\nDoes not require loading.") (inc-dir "Find directory in which this module was found.\n\nDoes not require loading.") (file "Absolute path of file defining this module.\n\nDoes not require loading.") (is-core "Guess whether or not a module is part of the core distribution. Does not require loading.") (modules-used "List modules used by this module.\n\nRequires loading." list-context) (packages-inside "List sub-packages in this module.\n\nRequires loading." list-context) (superclasses "List module's superclasses.\n\nRequires loading." list-context))) (apply #'define-modinfo-function x)) ;; Create low-level wrappers for Sepia (dolist (x '((completions "Find completions in the symbol table.") (method-completions "Complete on an object's methods.") (location "Find an identifier's location.") (mod-subs "Find all subs defined in a package.") (mod-decls "Generate declarations for subs in a package.") (mod-file "Find the file defining a package.") (apropos "Find subnames matching RE.") (lexicals "Find lexicals for a sub.") (apropos-module "Find installed modules matching RE.") )) (apply #'define-xref-function "Sepia" x)) (dolist (x '((rebuild "Build Xref database for current Perl process.") (redefined "Rebuild Xref information for a given sub.") (callers "Find all callers of a function.") (callees "Find all functions called by a function.") (var-apropos "Find varnames matching RE.") (mod-apropos "Find modules matching RE.") (file-apropos "Find files matching RE.") (var-defs "Find all definitions of a variable.") (var-assigns "Find all assignments to a variable.") (var-uses "Find all uses of a variable.") (mod-redefined "Rebuild Xref information for a given package.") (guess-module-file "Guess file corresponding to module.") (file-modules "List the modules defined in a file."))) (apply #'define-xref-function "Sepia::Xref" x)) ;; Initialize built hash (sepia-init-perl-builtins))) (defvar sepia-scratchpad-mode-map (let ((map (make-sparse-keymap))) (set-keymap-parent map sepia-mode-map) (define-key map "\C-j" 'sepia-scratch-send-line) map)) ;;;###autoload (define-derived-mode sepia-scratchpad-mode sepia-mode "Sepia-Scratch" "Major mode for the Perl scratchpad, derived from Sepia mode." (sepia-init)) ;;;###autoload (defun sepia-scratch () "Switch to the sepia scratchpad." (interactive) (pop-to-buffer (or (get-buffer "*sepia-scratch*") (with-current-buffer (get-buffer-create "*sepia-scratch*") (sepia-scratchpad-mode) (current-buffer))))) (defun sepia-scratch-send-line (&optional scalarp) "Send the current line to perl, and display the result." (interactive "P") (insert (format "\n%s\n" (car (sepia-eval-raw (concat "$Sepia::REPL{eval}->(q#" (buffer-substring (sepia-bol-from) (sepia-eol-from)) "#)")))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Miscellany (defun sepia-indent-line (&rest args) "Unbind `beginning-of-defun-function' to not confuse `cperl-indent-line'." (let (beginning-of-defun-function) (apply #'cperl-indent-line args))) (defun sepia-string-count-matches (reg str) (let ((n 0) (pos -1)) (while (setq pos (string-match reg str (1+ pos))) (incf n)) n)) (defun sepia-perlize-region-internal (pre post beg end replace-p) "Pass buffer text from BEG to END through a Perl command." (let* ((exp (concat pre "<<'SEPIA_END_REGION';\n" (buffer-substring-no-properties beg end) (if (= (char-before end) ?\n) "" "\n") "SEPIA_END_REGION\n" post)) (new-str (car (sepia-eval-raw exp)))) (if replace-p (progn (delete-region beg end) (goto-char beg) (insert new-str)) (if (> (sepia-string-count-matches "\n" new-str) 2) (with-current-buffer (get-buffer-create "*sepia-filter*") (let ((inhibit-read-only t)) (erase-buffer) (insert new-str) (goto-char (point-min)) (pop-to-buffer (current-buffer)))) (message "%s" new-str))))) (defun sepia-eol-from (&optional pt n) (if (not pt) (line-end-position n) (save-excursion (goto-char pt) (line-end-position n)))) (defun sepia-bol-from (&optional pt n) (if (not pt) (line-beginning-position n) (save-excursion (goto-char pt) (line-beginning-position n)))) (defun sepia-perl-pe-region (expr beg end &optional replace-p) "Do the equivalent of perl -pe on region \(i.e. evaluate an expression on each line of region). With prefix arg, replace the region with the result." (interactive "MExpression: \nr\nP") (sepia-perlize-region-internal "do { my $ret=''; local $_; local $/ = \"\\n\"; my $region = " (concat "; for (split /(?<=\\n)/, $region, -1) { " expr "} continue { $ret.=$_}; $ret}") (sepia-bol-from beg) (sepia-eol-from end) replace-p)) (defun sepia-perl-ne-region (expr beg end &optional replace-p) "Do the moral equivalent of perl -ne on region \(i.e. evaluate an expression on each line of region). With prefix arg, replace the region with the result." (interactive "MExpression: \nr\nP") (sepia-perlize-region-internal "do { my $ret='';my $region = " (concat "; for (split /(?<=\\n)/, $region, -1) { $ret .= do { " expr ";} }; ''.$ret}") (sepia-bol-from beg) (sepia-eol-from end) replace-p)) (defun sepia-perlize-region (expr beg end &optional replace-p) "Evaluate a Perl expression on the region as a whole. With prefix arg, replace the region with the result." (interactive "MExpression: \nr\nP") (sepia-perlize-region-internal "do { local $_ = " (concat "; do { " expr ";}; $_ }") beg end replace-p)) (defun sepia-core-version (module &optional message) "Report the first version of Perl shipping with MODULE." (interactive (list (sepia-interactive-arg 'module) t)) (let* ((version (sepia-eval (format "eval { Sepia::core_version('%s') }" module) 'scalar-context)) (res (if version (format "%s was first released in %s." module version) (format "%s is not in core." module)))) (when message (message "%s" res)) res)) (defun sepia-guess-package (sub &optional file) "Guess which package SUB is defined in." (let ((defs (xref-location (xref-apropos sub)))) (or (and (= (length defs) 1) (or (not file) (equal (caar defs) file)) (fourth (car defs))) (and file (fourth (find-if (lambda (x) (equal (car x) file)) defs))) ;; (car (xref-file-modules file)) (sepia-buffer-package)))) ;;;###autoload (defun sepia-apropos-module (name) "List installed modules matching a regexp." (interactive "MList modules matching regexp: ") (let ((res (xref-apropos-module name))) (if res (with-output-to-temp-buffer "*Modules*" (display-completion-list res)) (message "No modules matching %s." name)))) ;;;###autoload (defun sepia-eval-defun () "Re-evaluate the current function and rebuild its Xrefs." (interactive) (let (pt end beg sub res sepia-eval-package sepia-eval-file sepia-eval-line) (save-excursion (setq pt (point) end (progn (end-of-defun) (point)) beg (progn (beginning-of-defun) (point))) (goto-char beg) (when (looking-at "^sub\\s +\\(.+\\_>\\)") (setq sub (match-string 1)) (let ((body (buffer-substring-no-properties beg end))) (setq sepia-eval-package (sepia-guess-package sub (buffer-file-name)) sepia-eval-file (buffer-file-name) sepia-eval-line (line-number-at-pos beg) res (sepia-eval-raw (if sepia-eval-defun-include-decls (concat (apply #'concat (xref-mod-decls sepia-eval-package)) body) body)))))) (if (cdr res) (progn (when (string-match " line \\([0-9]+\\), near \"\\([^\"]*\\)\"" (cdr res)) (goto-char beg) (beginning-of-line (string-to-number (match-string 1 (cdr res)))) (search-forward (match-string 2 (cdr res)) (sepia-eol-from) t)) (message "Error: %s" (cdr res))) (xref-redefined sub sepia-eval-package) (message "Defined %s" sub)))) ;;;###autoload (defun sepia-eval-expression (expr &optional list-p message-p) "Evaluate EXPR in scalar context." (interactive (list (read-string "Expression: ") current-prefix-arg t)) (let ((res (sepia-eval expr (if list-p 'list-context 'scalar-context)))) (when message-p (message "%s" res)) res)) (defun sepia-extract-def (file line obj) (with-current-buffer (find-file-noselect (expand-file-name file)) (save-excursion (funcall (sepia-refiner 'function) line obj) (beginning-of-line) (when (looking-at (concat "^\\s *sub\\_>.*\\_<" obj "\\_>")) (buffer-substring (point) (progn (end-of-defun) (point))))))) (defun sepia-eval-no-run (string) (let ((res (sepia-eval-raw (concat "eval q#{ BEGIN { use B; B::minus_c(); $^C=1; } do { " string " };BEGIN { die \"ok\\n\" }#, $@")))) (if (string-match "^ok\n" (car res)) nil (car res)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; REPL (defvar sepia-eval-file nil "File in which `sepia-eval' evaluates perl expressions.") (defvar sepia-eval-line nil "Line at which `sepia-eval' evaluates perl expressions.") (defun sepia-set-cwd (dir) "Set the inferior Perl process's working directory to DIR. When called interactively, the current buffer's `default-directory' is used." (interactive (list (expand-file-name default-directory))) (sepia-call "Cwd::chdir" 'list-context dir)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Doc-scanning (defvar sepia-doc-map (make-hash-table :test #'equal)) (defvar sepia-var-doc-map (make-hash-table :test #'equal)) (defvar sepia-module-doc-map (make-hash-table :test #'equal)) (defvar sepia-skip-doc-scan nil) (defun sepia-doc-scan-buffer () ;; too many confusing things in perldiag, so just give up. (when (or sepia-skip-doc-scan (and (buffer-file-name) (string-match "perldiag\\.pod$" (buffer-file-name)))) (return nil)) (save-excursion (goto-char (point-min)) (loop while (re-search-forward "^=\\(item\\|head[2-9]\\)\\s +\\([%$&@A-Za-z_].*\\)" nil t) if (ignore-errors (let ((short (match-string 2)) longdoc) (setq short (let ((case-fold-search nil)) (replace-regexp-in-string "E" "<" (replace-regexp-in-string "E" ">" (replace-regexp-in-string "[A-DF-Z]<\\([^<>]+\\)>" "\\1" short))))) (while (string-match "^\\s *[A-Z]<\\(.*\\)>\\s *$" short) (setq short (match-string 1 short))) (setq longdoc (let ((beg (progn (forward-line 2) (point))) (end (1- (re-search-forward "^=" nil t)))) (forward-line -1) (goto-char beg) (if (re-search-forward "^\\(.+\\)$" end t) (concat short ": " (substring-no-properties (match-string 1) 0 (position ?. (match-string 1)))) short))) (cond ;; e.g. "$x -- this is x" ((string-match "^[%$@]\\([A-Za-z0-9_:]+\\)\\s *--\\s *\\(.*\\)" short) (list 'variable (match-string-no-properties 1 short) (or (and (equal short (match-string 1 short)) longdoc) short))) ;; e.g. "C" or "$x = $y->foo()" ((string-match "^\\([A-Za-z0-9_:]+\\)\\s *\\(\\$\\|(\\)" short) (list 'function (match-string-no-properties 1 short) (or (and (equal short (match-string 1 short)) longdoc) short))) ;; e.g. "C<$result = foo $args...>" ((string-match "^[%@$*][A-Za-z0-9_:]+\\s *=\\s *\\([A-Za-z0-9_:]+\\)" short) (list 'function (match-string-no-properties 1 short) (or (and (equal short (match-string 1 short)) longdoc) short))) ;; e.g. "$x this is x" (note: this has to come last) ((string-match "^[%$@]\\([^( ]+\\)" short) (list 'variable (match-string-no-properties 1 short) longdoc))))) collect it))) (defun sepia-buffer-package () (save-excursion (or (and (re-search-backward "^\\s *package\\s +\\([^ ;]+\\)\\s *;" nil t) (match-string-no-properties 1)) "main"))) (defun sepia-doc-update () "Update documentation for a file. This documentation, taken from \"=item\" entries in the POD, is used for eldoc feedback. Set the file variable `sepia-skip-doc-scan' to non-nil to skip scanning this buffer. This can be used to avoid generating bogus documentation from files like perldiag.pod." (interactive) (let ((pack (ifa (sepia-buffer-package) (concat it "::") ""))) (dolist (x (sepia-doc-scan-buffer)) (let ((map (ecase (car x) (function sepia-doc-map) (variable sepia-var-doc-map)))) (puthash (second x) (third x) map) (puthash (concat pack (second x)) (third x) map))))) (defun sepia-looks-like-module (obj) (let (case-fold-search) (or (string-match (eval-when-compile (regexp-opt '("strict" "vars" "warnings" "lib"))) obj) (and (string-match "^\\([A-Z][A-Za-z0-9]*::\\)*[A-Z]+[A-Za-z0-9]+\\sw*$" obj))))) (defun sepia-describe-object (thing) "Display documentation for `thing', like ``describe-function'' for elisp." (interactive (let ((id (sepia-ident-at-point))) (when (string= (cadr id) "") (setq id (sepia-ident-before-point))) (if (car id) (list id) (cdr id)))) (cond ((listp thing) (setq thing (format "%c%s" (car thing) (cadr thing))) (with-current-buffer (get-buffer-create "*sepia-help*") (let ((inhibit-read-only t)) (erase-buffer) (shell-command (concat "perldoc -v " (shell-quote-argument thing)) (current-buffer)) (view-mode 1) (goto-char (point-min))) (unless (looking-at "No documentation for") (pop-to-buffer "*sepia-help*" t)))) ((gethash thing sepia-perl-builtins) (with-current-buffer (get-buffer-create "*sepia-help*") (let ((inhibit-read-only t)) (erase-buffer) (shell-command (concat "perldoc -f " thing) (current-buffer)) (view-mode 1) (goto-char (point-min)))) (pop-to-buffer "*sepia-help*" t)))) (defun sepia-symbol-info (&optional obj type) "Eldoc function for `sepia-mode'. Looks in `sepia-doc-map' and `sepia-var-doc-map', then tries calling `cperl-describe-perl-symbol'." (unless obj (multiple-value-bind (ty ob) (sepia-ident-at-point) (setq obj (if (consp ob) (car ob) ob) type ty))) (if obj (or (gethash obj (ecase (or type ?&) (?& sepia-doc-map) ((?$ ?@ ?%) sepia-var-doc-map) (nil sepia-module-doc-map) (?* sepia-module-doc-map) (t (error "sepia-symbol-info: %s" type)))) ;; Loathe cperl a bit. (flet ((message (&rest blah) (apply #'format blah))) (let* (case-fold-search (cperl-message-on-help-error nil) (hlp (car (save-excursion (cperl-describe-perl-symbol (if (member type '(?$ ?@ ?%)) (format "%c%s" type obj) obj)))))) (if hlp (progn ;; cperl's docstrings are too long. (setq hlp (replace-regexp-in-string "\\s \\{2,\\}\\|\t" " " hlp)) (if (> (length hlp) 75) (concat (substring hlp 0 72) "...") hlp)) ;; Try to see if it's a module (if (and (let ((bol (save-excursion (beginning-of-line) (point)))) (looking-back " *\\(?:use\\|require\\|package\\|no\\)\\s +[^ ]*" bol)) (sepia-looks-like-module obj)) (sepia-core-version obj) "")))) ""))) (defun sepia-install-eldoc () "Install Sepia hooks for eldoc support. This automatically disables `cperl-lazy-installed', the `cperl-mode' reimplementation of eldoc." (interactive) (require 'eldoc) (set-variable 'eldoc-documentation-function 'sepia-symbol-info t) (if cperl-lazy-installed (cperl-lazy-unstall)) (eldoc-mode 1) (set-variable 'eldoc-idle-delay 1.0 t)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Error jump: (defun sepia-extract-next-warning (pos &optional end) (catch 'foo (while (re-search-forward "^\\(.+\\) at \\(.+?\\) line \\([0-9]+\\)" end t) (unless (string= "(eval " (substring (match-string 2) 0 6)) (throw 'foo (list (match-string 2) (string-to-number (match-string 3)) (match-string 1))))))) (defun sepia-goto-error-at (pos) "Visit the source of the error on line at point." (interactive "d") (ifa (sepia-extract-next-warning (sepia-bol-from pos) (sepia-eol-from pos)) (destructuring-bind (file line msg) it (find-file file) (goto-line line) (message "%s" msg)) (error "No error to find."))) (defun sepia-display-errors (beg end) "Display source causing errors in current buffer from BEG to END." (interactive "r") (goto-char beg) (let ((msgs nil)) (loop for w = (sepia-extract-next-warning (sepia-bol-from) end) while w do (destructuring-bind (file line msg) w (push (format "%s:%d:%s\n" (abbreviate-file-name file) line msg) msgs))) (erase-buffer) (goto-char (point-min)) (mapc #'insert (nreverse msgs)) (goto-char (point-min)) (grep-mode))) (defun sepia-lisp-to-perl (thing) "Convert elisp data structure to Perl." (cond ((null thing) "undef") ((symbolp thing) (let ((pname (substitute ?_ ?- (symbol-name thing))) (type (string-to-char (symbol-name thing)))) (if (member type '(?% ?$ ?@ ?*)) pname (concat "\\*" pname)))) ((stringp thing) (format "%S" (substring-no-properties thing 0))) ((integerp thing) (format "%d" thing)) ((numberp thing) (format "%g" thing)) ;; Perl expression ((and (consp thing) (eq (car thing) 'expr)) (cdr thing)) ; XXX -- need quoting?? ((and (consp thing) (not (consp (cdr thing)))) (concat (sepia-lisp-to-perl (car thing)) " => " (sepia-lisp-to-perl (cdr thing)))) ;; list ((or (not (consp (car thing))) (listp (cdar thing))) (concat "[" (mapconcat #'sepia-lisp-to-perl thing ", ") "]")) ;; hash table (t (concat "{" (mapconcat #'sepia-lisp-to-perl thing ", ") "}")))) (defun sepia-find-loaded-modules () (interactive) "Visit all source files loaded by the currently-running Perl. Currently, this means any value of %INC matching /.p[lm]$/." (dolist (file (sepia-eval "values %INC" 'list-context)) (when (string-match "\\.p[lm]$" file) (find-file-noselect file t)))) (defun sepia-dired-package (package) (interactive "sPackage: ") "Browse files installed by `package'. Create a `dired-mode' buffer listing all flies installed by `package'." ;; XXX group by common prefix and use /^ DIRECTORY:$/ format (let ((ls (sort #'string< (sepia-call "Sepia::file_list" 'list-context package))) pfx maxlen) (setq maxlen (apply #'max (mapcar #'length ls))) (with-current-buffer (get-buffer-create (format "*Package %s*" package)) (let ((inhibit-read-only t) marker) ;; Start with a clean slate (erase-buffer) (setq marker (point-min-marker)) (set (make-local-variable 'dired-subdir-alist) nil) ;; Build up the contents (while ls ;; Find a decent prefix (setq pfx (try-completion "" ls)) (unless (file-exists-p pfx) (string-match "^\\(.*/\\)" pfx) (setq pfx (match-string 1 pfx))) ;; If we found a lousy prefix, chew off the first few paths and ;; try again. XXX not done. (insert (format " %s:\n" pfx)) (setq default-directory pfx) (apply 'call-process "/bin/ls" nil (current-buffer) t (cons "-lR" (mapcar (lambda (x) (replace-regexp-in-string (concat pfx "?") "" x)) ls))) (push `((,default-directory . ,marker)) dired-subdir-alist) (setq ls nil)) (dired-mode pfx) (pop-to-buffer (current-buffer)))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Follow POD links from source (defun sepia-pod-follow-link-at-point (str src) "Follow a POD-style link. If called interactively, follow link at point, or prompt if no such link exists. With prefix argument, view formatted documentation with `sepia-perldoc-this'; otherwise, view raw documentation source." (interactive (list (or (sepia-pod-link-at-point (point)) (read-string "Link: ")) (not current-prefix-arg))) (sepia-pod-follow-link str src)) (defun sepia-pod-follow-link (str &optional src) "Follow link STR to documentation, or to source of documentation if SRC. For URL links (e.g. L), always follow the link using `browse-url'." ;; strip off L<...> (when (string-match "^L<\\(.*\\)>$" str) (setq str (match-string 1 str))) ;; strip out text|... (when (string-match "[^/\"|]+|\\(.*\\)" str) (setq str (match-string 1 str))) (cond ;; URL -- no way to "jump to source" ((string-match "^[a-z]+:.+" str) ;; view the URL -- there's no "source" (browse-url str)) ;; name/sec ((string-match "^\\([^/\"]+\\)/\"?\\([^\"]+\\)\"?$" str) ;; open the POD, then go to the section ;; -- `M-. d' or `M-. m', plus jump (let ((page (match-string 1 str)) (sec (match-string 2 str))) (sepia-perldoc-this page) (if src (let (target) (sepia-module-find page) (save-excursion (goto-char (point-min)) (if (search-forward (concat "^=.*" sec) nil t) (goto-char target) (message "Can't find anchor for %s." str)))) (w3m-search-name-anchor sec)))) ;; /"sec" or /sec or "sec" ((or (string-match "^/\"?\\([^\"]+\\)\"?$" str) (string-match "^\"\\([^\"]+\\)\"$" str)) ;; jump to POD header in current file or in displayed POD (let ((sec (match-string 1 str))) (if src (let (target) (save-excursion (goto-char (point-min)) (unless (search-forward (concat "^=.*" sec) nil t) (error "Can't find anchor for %s." str)) (setq target (match-beginning))) (and target (goto-char target))) (sepia-view-pod) (w3m-search-name-anchor (match-string 1 str))))) ;; name ((string-match "^[^/\"]+$" str) ;; view the pod ;; -- `M-. d' or `M-. m' (if src (sepia-module-find str) (sepia-perldoc-this str))) (t (error "Can't understand POD link %s." str)))) (defun sepia-pod-link-at-point (p) "Extract POD link at point, or nil." (let* ((bol (save-excursion (forward-line 0) (point))) (eol (save-excursion (forward-line 1) (backward-char 1) (point))) (beg (or (save-excursion (forward-char 1) ;in case we're on < of L< (search-backward "L<" bol t)) p)) (end (save-excursion (search-forward ">" eol t)))) (if (and beg end) (buffer-substring-no-properties (+ beg 2) (1- end)) nil))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Fight CPerl a bit -- it can be opinionated (defadvice cperl-imenu--create-perl-index (after simplify compile activate) "Make cperl's imenu index simpler." (flet ((annoying (x) (dolist (y '("Rescan" "^\\+Unsorted" "^\\+Packages")) (when (string-match y (car x)) (return-from annoying t))) nil)) (setq ad-return-value (remove-if #'annoying ad-return-value)))) ;; (defun sepia-view-mode-hook () ;; "Let backspace scroll again. ;; XXX Unused, yet." ;; (local-unset-key (kbd ""))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; __DATA__ (defun sepia-init-perl-builtins () (setq sepia-perl-builtins (make-hash-table :test #'equal)) (dolist (s '( "abs" "accept" "alarm" "atan2" "bind" "binmode" "bless" "caller" "chdir" "chmod" "chomp" "chop" "chown" "chr" "chroot" "close" "closedir" "connect" "continue" "cos" "crypt" "dbmclose" "dbmopen" "defined" "delete" "die" "dump" "each" "endgrent" "endhostent" "endnetent" "endprotoent" "endpwent" "endservent" "eof" "eval" "exec" "exists" "exit" "exp" "fcntl" "fileno" "flock" "fork" "format" "formline" "getc" "getgrent" "getgrgid" "getgrnam" "gethostbyaddr" "gethostbyname" "gethostent" "getlogin" "getnetbyaddr" "getnetbyname" "getnetent" "getpeername" "getpgrp" "getppid" "getpriority" "getprotobyname" "getprotobynumber" "getprotoent" "getpwent" "getpwnam" "getpwuid" "getservbyname" "getservbyport" "getservent" "getsockname" "getsockopt" "glob" "gmtime" "goto" "grep" "hex" "import" "index" "int" "ioctl" "join" "keys" "kill" "last" "lc" "lcfirst" "length" "link" "listen" "local" "localtime" "log" "lstat" "map" "mkdir" "msgctl" "msgget" "msgrcv" "msgsnd" "next" "oct" "open" "opendir" "ord" "pack" "package" "pipe" "pop" "pos" "print" "printf" "prototype" "push" "quotemeta" "rand" "read" "readdir" "readline" "readlink" "readpipe" "recv" "redo" "ref" "rename" "require" "reset" "return" "reverse" "rewinddir" "rindex" "rmdir" "scalar" "seek" "seekdir" "select" "semctl" "semget" "semop" "send" "setgrent" "sethostent" "setnetent" "setpgrp" "setpriority" "setprotoent" "setpwent" "setservent" "setsockopt" "shift" "shmctl" "shmget" "shmread" "shmwrite" "shutdown" "sin" "sleep" "socket" "socketpair" "sort" "splice" "split" "sprintf" "sqrt" "srand" "stat" "study" "sub" "sub*" "substr" "symlink" "syscall" "sysopen" "sysread" "sysseek" "system" "syswrite" "tell" "telldir" "tie" "tied" "time" "times" "truncate" "uc" "ucfirst" "umask" "undef" "unlink" "unpack" "unshift" "untie" "utime" "values" "vec" "wait" "waitpid" "wantarray" "warn" "write" )) (puthash s t sepia-perl-builtins))) (provide 'sepia) ;;; sepia.el ends here Sepia-0.992/Sepia.html000644 000765 000765 00000136520 11657301577 015036 0ustar00seanoseano000000 000000 SEPIA: Simple Emacs Perl Integration

SEPIA: Simple Emacs Perl Integration

Sepia.jpg

Sepia is a set of Perl development tools for Emacs supporting code navigation and interactive evaluation.

1 Introduction

Sepia is a set of tools for Perl development in Emacs. Its goal is to extend CPerl mode to support fast code navigation and interactive development. It is inspired by Emacs' current support for a number of other languages, including Lisp, Python, and Emacs Lisp.

1.1 Getting Started

To install Sepia, its Emacs Lisp files must be in Emacs' load-path, and the lib directory must be in Perl's @INC. Assuming that Sepia has been unpacked in ~/sepia, it can be installed by adding the following lines to ~/.emacs:

     (add-to-list 'load-path "~/sepia")
     (setq sepia-perl5lib (list (expand-file-name "~/sepia/lib")))
     (defalias 'perl-mode 'sepia-mode)
     (require 'sepia)

Then to bring up the interactive Perl prompt, type M-x sepia-repl.

1.2 Philosophy

A development environment should support three activities: code spelunking, interaction, and customization. Emacs as an environment for developing Emacs Lisp thoroughly supports all of them: It has commands to visit individual functions' code and documentation, commands to evaluate or step through expressions, and an architecture that encourages customization in Emacs Lisp. As an environment for Perl, however, it is lacking: there is limited interactivity with the Perl debugger, and reasonable documentation browsing, but no support for navigating, editing, and re-evaluating code. Sepia attempts to remedy the situation.

Modern IDEs also support these three activities, but do so awkwardly. Rather than having functions to visit definitions (find-function) and search for functions (apropos), they clutter the screen with class and file trees. Rather than supporting interactive evaluation of small pieces of code, they perform background semantic checking on whole projects and highlight errors. Rather than allowing minor customizations to grow organically into features, they support limited configuration files and baroque plug-in APIs1. Sepia tries to adhere to the apparent Emacs philosophy that rich semantic information should be unobtrusive, and that the best way to build working code is to start by experimenting with small pieces.

Language support packages for Emacs vary widely in the degree to which they make use of or replace existing Emacs features. Minimal modes provide keyword-based syntax highlighting and an unadorned comint buffer as an interpreter. Others provide their own specialized equivalents of comint, eldoc, completion, and other Emacs features. Sepia takes a third approach by trying to do as much as possible with existing Emacs features, even when they are not optimal for Perl. For example, it uses comint to communicate with the subprocess, eldoc to display documentation, and grep to list source locations.

This approach has three advantages: First, it maximizes the number of features that can be supported with limited development time. Second, it respects users' settings. A seasoned Emacs user may have changed hundreds of settings, so a mode that reimplements features will have to support equivalent settings, and will force the user to re-specify them. Finally, this approach respects decades of development spent, as Neal Stephenson put it, “focused with maniacal intensity on the deceptively simple-seeming problem of editing text.” Many non-obvious choices go into making a polished interface, and while a reimplementation gets rid of accumulated cruft, it must rediscover these hidden trade-offs.

Anyways, I hope you enjoy using Sepia. Its development style is strange for someone used Perl's typical mix of one-liners and edit-save-run, but once you are accustomed to it, you may find it very effective.

1.3 Related Work

A number of more-or-less related Emacs extensions are currently under development. Here is a list of the ones I have heard about, along with my brief impression of how they differ from Sepia. Since I use none of them regularly, these impressions should be taken with a grain of salt.

Emacs::PDE
PDE is similar to Sepia in offering an interactive Lisp-like development environment interfacing with a long-running Perl process. It seems more ambitious, and therefore a bit more invasive.

http://search.cpan.org/dist/Emacs-PDE/

Devel::PerlySense
Devel::PerlySense offers a more Eclipse-like development environment, with offline code analysis via PPI.

http://search.cpan.org/dist/Devel-PerlySense/

Emacs::EPL
Emacs::EPL is a low-level IPC interface between Emacs and Perl. Sepia was originally based on Emacs::EPL, but the current comint-based implementation proved more maintainable.

http://search.cpan.org/dist/Emacs-EPL/

Stylish
Stylish is a similar effort with a very different implementation philosophy, requiring maximal rather than minimal dependencies in both Perl and Emacs, and reimplementing comint in Emacs.

http://github.com/jrockway/stylish.git

2 Editing

Sepia's first contribution is a set of commands to explore a Perl codebase. These include commands to browse and display documentation, to find function definitions, and to query a cross-reference database of function and variable uses. Sepia also provides intelligent symbol completion.

2.1 Completion

Sepia implements partial-word completion that communicates with the inferior Perl process. For example, `%S:X:v_u' completes to `%Sepia::Xref::var_use' when Sepia is loaded. This completion only operates on functions and global variables known to the Perl interpreter, so it works best when code and interpreter are in sync.

More precisely, completion examines the text before point and tries each of the following in turn, using the first successful approach:

  1. If the text looks like a method call (e.g. `$object->f' or `Class->f'), complete on methods.
  2. If it looks like a variable (e.g. `%hash' or `$scalar'), complete first on lexical, then global variables.
  3. Complete on modules and functions.
  4. Otherwise, complete on Perl built-in operators.

For each of the first three cases, completions candidates are first generated by splitting the text on characters [:_] and matching the resulting word parts. For example, `X:a_b' will complete to all symbols matching `^X[^:]*:+a[^:_]*_b' such as `Xref::a_bug' and `X::always_bites_me'. If the module parts of the input match a module exactly and completions exist, they are not expanded. For example, `X:a' will expand only to `X::aa' when `X::aa' and `Xx::aa' exist. If no matches result, the text is treated as an acronym. For example, `dry' will complete to `dont_repeat_yourself'. Note: partial-word completion is not currently supported for lexicals.

Completion is performed by the following commands:

M-x sepia-complete-symbol
Complete the symbol before point as described above. This is always case-sensitive, independent of completion-ignore-case.
TAB
M-x sepia-indent-or-complete
First try to reindent the current line. If its indentation does not change, then try to expand an abbrev at point (unless sepia-indent-expand-abbrev is nil). If no abbrev is expanded, then call sepia-complete-symbol.

2.2 Navigation

Sepia provides several commands for navigating program source. All of them rely on information from the inferior Perl process, so it is important both that it be running, and that its internal representation of the program match the program source. The commands marked (Xref) below also rely on a cross-reference database, which must be explicitly rebuilt by calling xref-rebuild when the program changes.

There are two basic kinds of navigation commands. The first kind jumps directly to the first matching location when possible, prompting only if no such location is found. These commands find only a single location.

M-. M-.
M-x sepia-dwim
Guess what kind of identifier is at point, and try to do the right thing: for a function, find its definition(s); for a variable, find its uses; for a module, view its documentation; otherwise, prompt for the name of a function to visit. sepia-dwim automatically goes to the first function definition or variable use found.
M-. d
M-x sepia-location
Jump directly to the definition of the function at point, prompting if point is not on a known function. If multiple definitions are found, choose one arbitrarily. This function is similar to sepia-defs, and the two should probably be merged.
M-. j
M-x sepia-jump-to-symbol
Navigate to a function using “ido” interactive completion. Within interactive completion, press <:> to descend into a package, <DEL> to ascend to a parent package, and <RET> to go to the currently-selected function.
M-. l
M-x sepia-pod-follow-link-at-point
Follow the POD link (L<...>) at point, or prompt for a link if there is none. Go to the appropriate location in the document source or, with a prefix argument, in the rendered documentation. This can be especially useful when writing links in your own documentation.

The second kind of navigation commands always prompts the user – though usually with a sensible default value – and finds multiple locations. When called with a prefix argument, these commands present their results in a grep-mode buffer. When called without a prefix argument, they place all results on the found-location ring and jump directly to the first. The remaining locations can be cycled through by calls to sepia-next.

M-. f name <RET>
M-x sepia-defs
Find definition(s) of function name.
M-. m name <RET>
M-x sepia-module-find name <RET>
Find the source of module name.
M-. a regexp <RET>
M-x sepia-apropos regexp <RET>
Find definitions of all functions whose names match regexp.
M-x sepia-apropos-module regexp <RET>
Find all installed modules matching regexp. This function may be slow the first time it is called, because it has to build a list of installed modules.
M-. c name <RET>
M-x sepia-callers name <RET>
(Xref) Find calls to function name.
M-. C name <RET>
M-x sepia-callees name <RET>
(Xref) Find the definitions of functions called by name.
M-. v name <RET>
M-x sepia-var-uses name <RET>
(Xref) Find uses of the global variable name.
M-. V name <RET>
M-x sepia-var-defs name <RET>
(Xref) Find definitions of global variable name. Since Perl's global variables are not declared, this is rarely useful

Finally, there are several other navigation-related commands that do not fit into either of the above categories.

M-,
M-x sepia-next
Cycle through the definitions found by the previous <M-.> search.
M-. r
M-x sepia-rebuild
Rebuild the cross-reference database by walking the op-tree and stashes.
M-. t
M-x find-tag
Execute the find-tag command typically bound to <M-.>.

2.3 Documentation

Sepia can be used to browse installed modules' documentation, to format and display the current buffer's POD, and to browse the list of modules installed on the system.

M-. p name <RET>
M-x sepia-perldoc-this
View documentation for module name or Perl manual page name.
C-c C-d
M-x sepia-view-pod
Format and view the current buffer's documentation.
sepia-package-list
Browse a tree of installed packages. This lists only the top-level packages from installed distributions, so if package My::Stuff also provides My::Stuff::Details, it will not be displayed. When Emacs-w3m is available, each module is linked to its documentation.
sepia-module-list
Browse a tree of both top-level and internal packages, like sepia-package-list.

Sepia also integrates with eldoc (at least in GNU Emacs >= 22). Documentation for Perl operators and control structures is taken from CPerl mode. Sepia will also display documentation for user-defined functions if their POD is formatted in the standard way, with functions described in a “=head2” or “=item” entry. To load user documentation, visit the relevant file and type M-x sepia-doc-update.

If Module::CoreList is available, Sepia's eldoc function will also display the first version of Perl with which a module was shipped. This is intended to give the programmer a sense of when he is creating external dependencies.

2.4 Other commands

M-x sepia-rename-lexical
Rename a variable in the function at point, querying for each replacement when called with a prefix argument. Currently, this is only a thin wrapper around query-replace.

3 Interactive Perl

Sepia's second main contribution is an interactive interface (REPL) to an inferior Perl process. The interface is based on GUD mode, and inherits many of its bindings; this chapter discusses only the Sepia extensions. To start or switch to the repl, type M-x sepia-repl. As in Sepia mode, <TAB> in the REPL performs partial-word completion with sepia-complete-symbol.

Sepia also provides a number of other ways to evaluate pieces of code in Perl, and commands to process buffer text using the inferior process.

Finally, Sepia comes with the sepl program, a standalone REPL that can be run from the command-line, and provides many features of the Emacs-based REPL.

3.1 Shortcuts

“Shortcuts” are commands handled specially by the REPL rather than being evaluated as Perl code. They either communicate with the REPL function, or provide a convenient interface to Sepia variables and functions. Shortcuts are prefixed by a comma (<,>), and may be abbreviated to the shortest unique prefix. The debugger defines additional shortcuts (See Debugger.).

break file:line [expr]
Set a breakpoint in file at line. If expr is supplied, stop only if it evaluates to true.
cd dir
Change Perl's current directory to dir.
debug [val]
Turn Sepia debugger hook on or off, or toggle if val is missing.
define name ['doc'] body...
Define name as a shortcut for Perl code body, with optional documentation doc, surrounded by single quotes. body is passed the raw command-line text as its first argument.
format type
Set the output format to type, either “dumper” (using Data::Dumper), “dump” (Data::Dump), “yaml” (YAML), “peek” (Devel::Peek), “dumpvar” (dumpvar.pl, somewhat rough), or “plain” (stringification). Default: “dumper”.

Note that this setting is independent of $COLUMNATE and $STRINGIFY.

help
Display a list of shortcuts.
load [file]
Reload saved variables from file (or ~/.sepia-save), created by save.
lsbreak
List breakpoints.
lsmod [pattern]
List currently-loaded modules matching optional pattern.
methods name [regexp]
Display a list of functions defined in package name and its ISA-ancestors matching optional pattern regexp.
package name
Set the default evaluation package to name.
pwd
Show the process's current working directory.
quit
Exit the inferior Perl process.
reload [module | /pattern/]
Reload module (but not its dependencies), or all modules matching pattern.
freload module
Reload module and all of its dependencies.
restart
Reload Sepia.pm and recursively invoke the REPL. This command is mostly of interest when working on Sepia itself, and will fail catastrophically if Sepia.pm fails to compile.
save [pattern [file]]
Save variables matching pattern (or all variables) to file (or ~/.sepia-save) in Storable format. Note that because saving magic variables can have unpredictable results, using save without a pattern argument is risky. Sepia excludes common magic variables and dangerous packages, but its list is not foolproof.
shell [command]
Execute shell command command, displaying its standard output and standard error.
size package [regexp]
size [regexp]
List the variables in package (or the current package) along with their total sizes. This requires the Devel::Size module. In strict mode, list lexical variables if no package is given.
strict [val]
Set evaluation strictness to val, or toggle it if val is not given. Note that turning strictness off and on clears the REPL's lexical environment.
test [file]
Run tests in the current directory. If file is given, only run test file or t/file
time [val]
Set time display to val, or toggle it if val is not given. With time display enabled, Sepia will use BSD::Resource and/or Time::HiRes to display wall clock time and CPU usage for the previous command as part of the prompt.
undef name
Undefine shortcut name. Warning: this can equally be used to remove built-in shortcuts.
wantarray [val]
Set the evaluation context to val: @ means array, $ means scalar, and anything else means void.
who package [regexp]
who [regexp]
List identifiers in package (main by default) matching optional regexp. In strict mode, list lexical variables if no package is given.

3.2 Debugger

Sepia uses Perl's debugger hooks and GUD mode to support conditional breakpoints and single-stepping, and overrides Perl's die() to invoke the debugger rather than unwind the stack. This makes it possible to produce a backtrace, inspect and modify global variables, and even continue execution when a program tries to kill itself. If the PadWalker module is available, Sepia also provides functions to inspect and modify lexical variables.

The debugger has its own set of shortcuts, also prefixed by a comma.

backtrace
Show a backtrace.
delete
Delete the current breakpoint.
down n
up n
Move the current stack frame up or down by n (or one) frames.
inspect [n]
Inspect lexicals in the current frame or frame n, counting upward from 1.
next [n]
Advance n (or one) lines, skipping subroutine calls.
quit
die
warn
Continue as the program would have executed without debugger intervention, dying if the debugger was called from die().
return expr
Continue execution as if die() had returned the value of expr, which is evaluated in the global environment.
step [n]
Step forward n (or one) lines, descending into subroutines.
xreturn sub expr
Return expr from the innermost call to sub. This is a somewhat dangerous and experimental feature, but is probably more useful than returning a value from die().

3.3 Evaluation

When interactive Perl is running, Sepia can evaluate regions of code in the inferior Perl process. The following commands assume that this process has already been started by calling sepia-repl.

C-M-x
M-x sepia-eval-defun
Evaluate the function around point in the inferior Perl process. If it contains errors, jump to the location of the first.
C-c C-l
M-x sepia-load-file
Save the current buffer, then reload its file and if warnings or errors occur, display an error buffer. With a prefix argument, also rebuild the cross-reference index.
C-c e
M-x sepia-eval-expression <RET> expr <RET>
Evaluate expr in scalar context and echo the result. With a prefix argument, evaluate in list context.
C-c!
sepia-set-cwd
Set the REPL's working directory to the current buffer's directory.

3.4 Mutilation

Sepia contains several functions to operate on regions of text using the interactive Perl process. These functions can be used like standard one-liners (e.g. `perl -pe ...'), with the advantage that all of the functions and variables in the interactive session are available.

M-x sepia-perl-pe-region <RET> code <RET>
Evaluate code on each line in the region with $_ bound to the line text, collecting the resulting values of $_. With a prefix argument, replace the region with the result.
M-x sepia-perl-ne-region <RET> code <RET>
Evaluate code as above, but collect the results instead.
M-x sepia-perlize-region <RET> code <RET>
Evaluate code once with $_ bound to the entire region, collecting the final value of $_. With a prefix argument, replace the region.

3.5 Scratchpad

Sepia also supports a scratchpad, another form of interaction inspired by Emacs' *scratch* buffer. To create or switch to the scratchpad, type M-x sepia-scratch. Scratchpad mode is exactly like Sepia mode, except <C-j> evaluates the current line and prints the result on the next line.

4 CPAN browsing

Sepia has rudimentary support for browsing documentation and installing modules from CPAN. Modules whose names, descriptions, or authors match a query are displayed in a *sepia-cpan* buffer, in which the following commands are available:

s
M-x sepia-cpan-search <RET> pattern <RET>
List modules whose names match pattern.
/
M-x sepia-cpan-desc <RET> pattern <RET>
List modules whose names or descriptions match pattern.
l
M-x sepia-cpan-list <RET> name <RET>
List modules authored by name.
r
M-x sepia-cpan-readme <RET> module <RET>
Fetch and display module's README file.
d
M-x sepia-cpan-doc <RET> module <RET>
Browse module's documentation on http://search.cpan.org.
i
M-x sepia-cpan-install <RET> module <RET>
Install module and its prerequisites. This feature is not yet well tested.

5 Customization

While Sepia can be customized in both the Perl and Emacs Lisp, most of the user-accessible configuration is in the latter.

5.1 Emacs Customization

Since Sepia tries where possible to reuse existing Emacs functionality, its behavior should already be covered by existing customizations. The two variables most likely to need customization are sepia-program-name and sepia-perl5lib. General Sepia mode configuration can be done with sepia-mode-hook, while REPL-specific configuration can be done with sepia-repl-mode-hook.

sepia-complete-methods
If non-nil, sepia-complete-symbol will complete simple method calls of the form $x-> or Module->. Since the former requires evaluation of $x, this can be disabled. Default: t.
sepia-eval-defun-include-decls
If non-nil, attempt to generate a declaration list for sepia-eval-defun. This is necessary when evaluating some code, such as that calling functions without parentheses, because the presence of declarations affects the parsing of barewords. Default: t.
sepia-indent-expand-abbrev
If non-nil, sepia-indent-or-complete will, if reindentation does not change the current line, expand an abbreviation before point rather than performing completion. Only if no abbreviation is found will it perform completion. Default: t.
sepia-module-list-function
The function to view a tree of installed modules. Default: w3m-find-file if Emacs-w3m is installed, or browse-url-of-buffer otherwise.
sepia-perldoc-function
The function called to view installed modules' documentation. Default: w3m-perldoc if Emacs-w3m is installed, or cperl-perldoc otherwise.
sepia-perl5lib
A list of directories to include in PERL5LIB when starting interactive Perl. Default: nil.
sepia-prefix-key
The prefix to use for for functions in sepia-keymap. Default: <M-.>.
sepia-program-name
The Perl program name for interactive Perl. Default: “perl”.
sepia-use-completion
If non-nil, various Sepia functions will generate completion candidates from interactive Perl when called interactively. This may be slow or undesirable in some situations. Default: t.
sepia-view-pod-function
The function called to view the current buffer's documentation. Default: sepia-w3m-view-pod if Emacs-w3m is available, or sepia-perldoc-buffer otherwise.

5.2 Perl Customization

When Sepia starts up, it evaluates the Perl script in ~/.sepiarc.

The following variables in the Sepia package control various aspects of interactive evaluation.

$PACKAGE
The package in which user input is evaluated, determined automatically when code is evaluated from a buffer. Default: main.
$PRINTER
The function called to format interactive output, normally set with the printer shortcut.
$COLUMNATE
If true, columnate simple arrays independent of the value of $PRINTER. Default: true.
$STRINGIFY
If true, stringify objects that overload the operation independent of the value of $PRINTER. Default: true.
$PS1
The trailing end of the prompt string, which should end with “> ”. Default: "> ".
$STOPDIE
If true, calls to die from interactive code will invoke the Sepia debugger. Default: true.
$STOPWARN
If true, calls to warn from interactive code will invoke the Sepia debugger. Default: false.
$WANTARRAY
If @, evaluate interactive expressions in list context, if $, scalar, otherwise, void. Default: @.

Additional REPL shortcuts can be defined as follows:

Sepia::define_shortcut name, function [, shortdoc [, longdoc]]
Define a shortcut name to call function. Also define a short usage message shortdoc and documentation longdoc. For example,
          
          Sepia::define_shortcut time => sub { print scalar localtime, "\n" },
              'time', 'Display the current time.';
          
     

defines a shortcut “time” that displays the current time. For more examples, see the function define_shortcuts code in Sepia.pm.

Sepia::alias_shortcut new, old
Make new an alias for old.

6 Internals

Many things remain unexplained except by the code itself, and some details mentioned above should probably be given less prominence. For developer documentation, please see the POD for Sepia and Sepia::Xref, and the doc-strings in sepia.el.

7 FAQ

Can I use Sepia outside of Emacs?
Sepia comes with the sepl program, a command-line REPL using the Sepia::Readline module, that provides many features of the Emacs-based REPL. It could be improved, though – patches welcome!

sepl currently provides completion for Term::ReadLine::Gnu and Term::ReadLine::Perl. If you have neither of these, using rlwrap might be the best option.

Why is the documentation in TeXInfo format?!
TeXInfo is the worst form of documentation, except for all the others. TeX and LaTeX produce beautiful printed output, and Info is the best way to view documentation in Emacs for things that are not themselves part of Emacs (i.e. “can have docstrings”).

It's awful to edit, being both verbose and redundant – just look at AUCTeX's texinfo-every-node-update for desperate placation of the suck, then try to figure out what's wrong when makeinfo complains about texinfo-every-node-update's output – but it's what we have. At least it sucks less than DocBook, raw HTML, or troff.

Credits

Hilko Bengen
Found and motivated me to fix a bunch of bugs, created Debian packages.
Ævar Arnfjörð Bjarmason
Miscellaneous fixes. Tested unicode support.
Ye Wenbin
Found and fixed numerous bugs.
Free Software
Portions of the code were lifted from Emacs-w3m, SLIME, ido, and B::Xref, all of which are Free software.

Function Index

Variable Index


Footnotes

[1] In my brief experience with Visual Studio, I was struck by the fact that I saw several toolbars, a couple of navigation windows, and a tiny view of the actual code. Sometimes a tooltip would obscure part of that tiny window.


Sepia-0.992/sepia.info000644 000765 000765 00000105632 11657301577 015065 0ustar00seanoseano000000 000000 This is sepia.info, produced by makeinfo version 4.8 from sepia.texi. INFO-DIR-SECTION Emacs START-INFO-DIR-ENTRY * Sepia: (sepia). Simple Emacs Perl Integration. END-INFO-DIR-ENTRY Copyright (C) 2005-2010 Sean O'Rourke. All rights reserved, some wrongs reversed. This module is distributed under the same terms as Perl.  File: sepia.info, Node: Top, Next: Introduction, Prev: (dir), Up: (dir) SEPIA ***** Sepia is a set of Perl development tools for Emacs supporting code navigation and interactive evaluation. * Menu: * Introduction:: * Editing:: * Interactive Perl:: * CPAN browsing:: * Customization:: * Internals:: * FAQ:: * Credits:: * Function Index:: * Variable Index::  File: sepia.info, Node: Introduction, Next: Editing, Prev: Top, Up: Top 1 Introduction ************** Sepia is a set of tools for Perl development in Emacs. Its goal is to extend CPerl mode to support fast code navigation and interactive development. It is inspired by Emacs' current support for a number of other languages, including Lisp, Python, and Emacs Lisp. * Menu: * Getting Started:: * Philosophy:: * Related Work::  File: sepia.info, Node: Getting Started, Next: Philosophy, Prev: Introduction, Up: Introduction 1.1 Getting Started =================== To install Sepia, its Emacs Lisp files must be in Emacs' `load-path', and the `lib' directory must be in Perl's `@INC'. Assuming that Sepia has been unpacked in `~/sepia', it can be installed by adding the following lines to `~/.emacs': (add-to-list 'load-path "~/sepia") (setq sepia-perl5lib (list (expand-file-name "~/sepia/lib"))) (defalias 'perl-mode 'sepia-mode) (require 'sepia) Then to bring up the interactive Perl prompt, type `M-x sepia-repl'.  File: sepia.info, Node: Philosophy, Next: Related Work, Prev: Getting Started, Up: Introduction 1.2 Philosophy ============== A development environment should support three activities: code spelunking, interaction, and customization. Emacs as an environment for developing Emacs Lisp thoroughly supports all of them: It has commands to visit individual functions' code and documentation, commands to evaluate or step through expressions, and an architecture that encourages customization in Emacs Lisp. As an environment for Perl, however, it is lacking: there is limited interactivity with the Perl debugger, and reasonable documentation browsing, but no support for navigating, editing, and re-evaluating code. Sepia attempts to remedy the situation. Modern IDEs also support these three activities, but do so awkwardly. Rather than having functions to visit definitions (`find-function') and search for functions (`apropos'), they clutter the screen with class and file trees. Rather than supporting interactive evaluation of small pieces of code, they perform background semantic checking on whole projects and highlight errors. Rather than allowing minor customizations to grow organically into features, they support limited configuration files and baroque plug-in APIs(1). Sepia tries to adhere to the apparent Emacs philosophy that rich semantic information should be unobtrusive, and that the best way to build working code is to start by experimenting with small pieces. Language support packages for Emacs vary widely in the degree to which they make use of or replace existing Emacs features. Minimal modes provide keyword-based syntax highlighting and an unadorned comint buffer as an interpreter. Others provide their own specialized equivalents of comint, eldoc, completion, and other Emacs features. Sepia takes a third approach by trying to do as much as possible with existing Emacs features, even when they are not optimal for Perl. For example, it uses comint to communicate with the subprocess, eldoc to display documentation, and grep to list source locations. This approach has three advantages: First, it maximizes the number of features that can be supported with limited development time. Second, it respects users' settings. A seasoned Emacs user may have changed hundreds of settings, so a mode that reimplements features will have to support equivalent settings, and will force the user to re-specify them. Finally, this approach respects decades of development spent, as Neal Stephenson put it, "focused with maniacal intensity on the deceptively simple-seeming problem of editing text." Many non-obvious choices go into making a polished interface, and while a reimplementation gets rid of accumulated cruft, it must rediscover these hidden trade-offs. Anyways, I hope you enjoy using Sepia. Its development style is strange for someone used Perl's typical mix of one-liners and edit-save-run, but once you are accustomed to it, you may find it very effective. ---------- Footnotes ---------- (1) In my brief experience with Visual Studio, I was struck by the fact that I saw several toolbars, a couple of navigation windows, and a tiny view of the actual code. Sometimes a tooltip would obscure part of that tiny window.  File: sepia.info, Node: Related Work, Prev: Philosophy, Up: Introduction 1.3 Related Work ================ A number of more-or-less related Emacs extensions are currently under development. Here is a list of the ones I have heard about, along with my brief impression of how they differ from Sepia. Since I use none of them regularly, these impressions should be taken with a grain of salt. `Emacs::PDE' PDE is similar to Sepia in offering an interactive Lisp-like development environment interfacing with a long-running Perl process. It seems more ambitious, and therefore a bit more invasive. `http://search.cpan.org/dist/Emacs-PDE/' `Devel::PerlySense' Devel::PerlySense offers a more Eclipse-like development environment, with offline code analysis via PPI. `http://search.cpan.org/dist/Devel-PerlySense/' `Emacs::EPL' Emacs::EPL is a low-level IPC interface between Emacs and Perl. Sepia was originally based on Emacs::EPL, but the current `comint'-based implementation proved more maintainable. `http://search.cpan.org/dist/Emacs-EPL/' `Stylish' Stylish is a similar effort with a very different implementation philosophy, requiring maximal rather than minimal dependencies in both Perl and Emacs, and reimplementing `comint' in Emacs. `http://github.com/jrockway/stylish.git'  File: sepia.info, Node: Editing, Next: Interactive Perl, Prev: Introduction, Up: Top 2 Editing ********* Sepia's first contribution is a set of commands to explore a Perl codebase. These include commands to browse and display documentation, to find function definitions, and to query a cross-reference database of function and variable uses. Sepia also provides intelligent symbol completion. * Menu: * Completion:: * Navigation:: * Documentation:: * Other commands::  File: sepia.info, Node: Completion, Next: Navigation, Prev: Editing, Up: Editing 2.1 Completion ============== Sepia implements partial-word completion that communicates with the inferior Perl process. For example, `%S:X:v_u' completes to `%Sepia::Xref::var_use' when Sepia is loaded. This completion only operates on functions and global variables known to the Perl interpreter, so it works best when code and interpreter are in sync. More precisely, completion examines the text before point and tries each of the following in turn, using the first successful approach: 1. If the text looks like a method call (e.g. `$object->f' or `Class->f'), complete on methods. 2. If it looks like a variable (e.g. `%hash' or `$scalar'), complete first on lexical, then global variables. 3. Complete on modules and functions. 4. Otherwise, complete on Perl built-in operators. For each of the first three cases, completions candidates are first generated by splitting the text on characters `[:_]' and matching the resulting word parts. For example, `X:a_b' will complete to all symbols matching `^X[^:]*:+a[^:_]*_b' such as `Xref::a_bug' and `X::always_bites_me'. If the module parts of the input match a module exactly and completions exist, they are not expanded. For example, `X:a' will expand only to `X::aa' when `X::aa' and `Xx::aa' exist. If no matches result, the text is treated as an acronym. For example, `dry' will complete to `dont_repeat_yourself'. _Note: partial-word completion is not currently supported for lexicals._ Completion is performed by the following commands: `M-x sepia-complete-symbol' Complete the symbol before point as described above. This is always case-sensitive, independent of `completion-ignore-case'. `TAB' `M-x sepia-indent-or-complete' First try to reindent the current line. If its indentation does not change, then try to expand an abbrev at point (unless `sepia-indent-expand-abbrev' is `nil'). If no abbrev is expanded, then call `sepia-complete-symbol'.  File: sepia.info, Node: Navigation, Next: Documentation, Prev: Completion, Up: Editing 2.2 Navigation ============== Sepia provides several commands for navigating program source. All of them rely on information from the inferior Perl process, so it is important both that it be running, and that its internal representation of the program match the program source. The commands marked (Xref) below also rely on a cross-reference database, which must be explicitly rebuilt by calling `xref-rebuild' when the program changes. There are two basic kinds of navigation commands. The first kind jumps directly to the first matching location when possible, prompting only if no such location is found. These commands find only a single location. `M-. M-.' `M-x sepia-dwim' Guess what kind of identifier is at point, and try to do the right thing: for a function, find its definition(s); for a variable, find its uses; for a module, view its documentation; otherwise, prompt for the name of a function to visit. `sepia-dwim' automatically goes to the first function definition or variable use found. `M-. d' `M-x sepia-location' Jump directly to the definition of the function at point, prompting if point is not on a known function. If multiple definitions are found, choose one arbitrarily. This function is similar to `sepia-defs', and the two should probably be merged. `M-. j' `M-x sepia-jump-to-symbol' Navigate to a function using "ido" interactive completion. Within interactive completion, press <:> to descend into a package, to ascend to a parent package, and to go to the currently-selected function. `M-. l' `M-x sepia-pod-follow-link-at-point' Follow the POD link (`L<...>') at point, or prompt for a link if there is none. Go to the appropriate location in the document source or, with a prefix argument, in the rendered documentation. This can be especially useful when writing links in your own documentation. The second kind of navigation commands always prompts the user - though usually with a sensible default value - and finds multiple locations. When called with a prefix argument, these commands present their results in a `grep-mode' buffer. When called _without_ a prefix argument, they place all results on the found-location ring and jump directly to the first. The remaining locations can be cycled through by calls to `sepia-next'. `M-. f NAME ' `M-x sepia-defs' Find definition(s) of function NAME. `M-. m NAME ' `M-x sepia-module-find NAME ' Find the source of module NAME. `M-. a REGEXP ' `M-x sepia-apropos REGEXP ' Find definitions of all functions whose names match REGEXP. `M-x sepia-apropos-module REGEXP ' Find all installed modules matching REGEXP. This function may be slow the first time it is called, because it has to build a list of installed modules. `M-. c NAME ' `M-x sepia-callers NAME ' (Xref) Find calls to function NAME. `M-. C NAME ' `M-x sepia-callees NAME ' (Xref) Find the definitions of functions called by NAME. `M-. v NAME ' `M-x sepia-var-uses NAME ' (Xref) Find uses of the global variable NAME. `M-. V NAME ' `M-x sepia-var-defs NAME ' (Xref) Find definitions of global variable NAME. Since Perl's global variables are not declared, this is rarely useful Finally, there are several other navigation-related commands that do not fit into either of the above categories. `M-,' `M-x sepia-next' Cycle through the definitions found by the previous search. `M-. r' `M-x sepia-rebuild' Rebuild the cross-reference database by walking the op-tree and stashes. `M-. t' `M-x find-tag' Execute the `find-tag' command typically bound to .  File: sepia.info, Node: Documentation, Next: Other commands, Prev: Navigation, Up: Editing 2.3 Documentation ================= Sepia can be used to browse installed modules' documentation, to format and display the current buffer's POD, and to browse the list of modules installed on the system. `M-. p NAME ' `M-x sepia-perldoc-this' View documentation for module NAME or Perl manual page NAME. `C-c C-d' `M-x sepia-view-pod' Format and view the current buffer's documentation. `sepia-package-list' Browse a tree of installed packages. This lists only the top-level packages from installed distributions, so if package `My::Stuff' also provides `My::Stuff::Details', it will not be displayed. When Emacs-w3m is available, each module is linked to its documentation. `sepia-module-list' Browse a tree of both top-level and internal packages, like `sepia-package-list'. Sepia also integrates with eldoc (at least in GNU Emacs >= 22). Documentation for Perl operators and control structures is taken from CPerl mode. Sepia will also display documentation for user-defined functions if their POD is formatted in the standard way, with functions described in a "=head2" or "=item" entry. To load user documentation, visit the relevant file and type `M-x sepia-doc-update'. If `Module::CoreList' is available, Sepia's eldoc function will also display the first version of Perl with which a module was shipped. This is intended to give the programmer a sense of when he is creating external dependencies.  File: sepia.info, Node: Other commands, Prev: Documentation, Up: Editing 2.4 Other commands ================== `M-x sepia-rename-lexical' Rename a variable in the function at point, querying for each replacement when called with a prefix argument. Currently, this is only a thin wrapper around `query-replace'.  File: sepia.info, Node: Interactive Perl, Next: CPAN browsing, Prev: Editing, Up: Top 3 Interactive Perl ****************** Sepia's second main contribution is an interactive interface (REPL) to an inferior Perl process. The interface is based on GUD mode, and inherits many of its bindings; this chapter discusses only the Sepia extensions. To start or switch to the repl, type `M-x sepia-repl'. As in Sepia mode, in the REPL performs partial-word completion with `sepia-complete-symbol'. Sepia also provides a number of other ways to evaluate pieces of code in Perl, and commands to process buffer text using the inferior process. Finally, Sepia comes with the `sepl' program, a standalone REPL that can be run from the command-line, and provides many features of the Emacs-based REPL. * Menu: * Shortcuts:: * Debugger:: * Evaluation:: * Mutilation:: * Scratchpad::  File: sepia.info, Node: Shortcuts, Next: Debugger, Prev: Interactive Perl, Up: Interactive Perl 3.1 Shortcuts ============= "Shortcuts" are commands handled specially by the REPL rather than being evaluated as Perl code. They either communicate with the REPL function, or provide a convenient interface to Sepia variables and functions. Shortcuts are prefixed by a comma (<,>), and may be abbreviated to the shortest unique prefix. The debugger defines additional shortcuts (*Note Debugger::.). `break FILE:LINE [EXPR]' Set a breakpoint in FILE at LINE. If EXPR is supplied, stop only if it evaluates to true. `cd DIR' Change Perl's current directory to DIR. `debug [VAL]' Turn Sepia debugger hook on or off, or toggle if VAL is missing. `define NAME ['DOC'] BODY...' Define NAME as a shortcut for Perl code BODY, with optional documentation DOC, surrounded by single quotes. BODY is passed the raw command-line text as its first argument. `format TYPE' Set the output format to TYPE, either "dumper" (using `Data::Dumper'), "dump" (`Data::Dump'), "yaml" (`YAML'), "peek" (`Devel::Peek'), "dumpvar" (`dumpvar.pl', somewhat rough), or "plain" (stringification). Default: "dumper". Note that this setting is independent of `$COLUMNATE' and `$STRINGIFY'. `help' Display a list of shortcuts. `load [FILE]' Reload saved variables from FILE (or `~/.sepia-save'), created by `save'. `lsbreak' List breakpoints. `lsmod [PATTERN]' List currently-loaded modules matching optional PATTERN. `methods NAME [REGEXP]' Display a list of functions defined in package NAME and its `ISA'-ancestors matching optional pattern REGEXP. `package NAME' Set the default evaluation package to NAME. `pwd' Show the process's current working directory. `quit' Exit the inferior Perl process. `reload [MODULE | /PATTERN/]' Reload MODULE (but not its dependencies), or all modules matching PATTERN. `freload MODULE' Reload MODULE and all of its dependencies. `restart' Reload `Sepia.pm' and recursively invoke the REPL. This command is mostly of interest when working on Sepia itself, and will fail catastrophically if `Sepia.pm' fails to compile. `save [PATTERN [FILE]]' Save variables matching PATTERN (or all variables) to FILE (or `~/.sepia-save') in `Storable' format. Note that because saving magic variables can have unpredictable results, using `save' without a pattern argument is risky. Sepia excludes common magic variables and dangerous packages, but its list is not foolproof. `shell [COMMAND]' Execute shell command COMMAND, displaying its standard output and standard error. `size PACKAGE [REGEXP]' `size [REGEXP]' List the variables in PACKAGE (or the current package) along with their total sizes. This requires the `Devel::Size' module. In strict mode, list lexical variables if no PACKAGE is given. `strict [VAL]' Set evaluation strictness to VAL, or toggle it if VAL is not given. Note that turning strictness off and on clears the REPL's lexical environment. `test [FILE]' Run tests in the current directory. If FILE is given, only run test FILE or `t/FILE' `time [VAL]' Set time display to VAL, or toggle it if VAL is not given. With time display enabled, Sepia will use `BSD::Resource' and/or `Time::HiRes' to display wall clock time and CPU usage for the previous command as part of the prompt. `undef NAME' Undefine shortcut NAME. *Warning*: this can equally be used to remove built-in shortcuts. `wantarray [VAL]' Set the evaluation context to VAL: `@' means array, `$' means scalar, and anything else means void. `who PACKAGE [REGEXP]' `who [REGEXP]' List identifiers in PACKAGE (main by default) matching optional REGEXP. In strict mode, list lexical variables if no PACKAGE is given.  File: sepia.info, Node: Debugger, Next: Evaluation, Prev: Shortcuts, Up: Interactive Perl 3.2 Debugger ============ Sepia uses Perl's debugger hooks and GUD mode to support conditional breakpoints and single-stepping, and overrides Perl's `die()' to invoke the debugger rather than unwind the stack. This makes it possible to produce a backtrace, inspect and modify global variables, and even continue execution when a program tries to kill itself. If the PadWalker module is available, Sepia also provides functions to inspect and modify lexical variables. The debugger has its own set of shortcuts, also prefixed by a comma. `backtrace' Show a backtrace. `delete' Delete the current breakpoint. `down N' `up N' Move the current stack frame up or down by N (or one) frames. `inspect [N]' Inspect lexicals in the current frame or frame N, counting upward from 1. `next [N]' Advance N (or one) lines, skipping subroutine calls. `quit' `die' `warn' Continue as the program would have executed without debugger intervention, dying if the debugger was called from `die()'. `return EXPR' Continue execution as if `die()' had returned the value of EXPR, which is evaluated in the global environment. `step [N]' Step forward N (or one) lines, descending into subroutines. `xreturn SUB EXPR' Return EXPR from the innermost call to SUB. This is a somewhat dangerous and experimental feature, but is probably more useful than returning a value from `die()'.  File: sepia.info, Node: Evaluation, Next: Mutilation, Prev: Debugger, Up: Interactive Perl 3.3 Evaluation ============== When interactive Perl is running, Sepia can evaluate regions of code in the inferior Perl process. The following commands assume that this process has already been started by calling `sepia-repl'. `C-M-x' `M-x sepia-eval-defun' Evaluate the function around point in the inferior Perl process. If it contains errors, jump to the location of the first. `C-c C-l' `M-x sepia-load-file' Save the current buffer, then reload its file and if warnings or errors occur, display an error buffer. With a prefix argument, also rebuild the cross-reference index. `C-c e' `M-x sepia-eval-expression EXPR ' Evaluate EXPR in scalar context and echo the result. With a prefix argument, evaluate in list context. `C-c!' `sepia-set-cwd' Set the REPL's working directory to the current buffer's directory.  File: sepia.info, Node: Mutilation, Next: Scratchpad, Prev: Evaluation, Up: Interactive Perl 3.4 Mutilation ============== Sepia contains several functions to operate on regions of text using the interactive Perl process. These functions can be used like standard one-liners (e.g. `perl -pe ...'), with the advantage that all of the functions and variables in the interactive session are available. `M-x sepia-perl-pe-region CODE ' Evaluate CODE on each line in the region with `$_' bound to the line text, collecting the resulting values of `$_'. With a prefix argument, replace the region with the result. `M-x sepia-perl-ne-region CODE ' Evaluate CODE as above, but collect the results instead. `M-x sepia-perlize-region CODE ' Evaluate CODE once with `$_' bound to the entire region, collecting the final value of `$_'. With a prefix argument, replace the region.  File: sepia.info, Node: Scratchpad, Prev: Mutilation, Up: Interactive Perl 3.5 Scratchpad ============== Sepia also supports a scratchpad, another form of interaction inspired by Emacs' `*scratch*' buffer. To create or switch to the scratchpad, type `M-x sepia-scratch'. Scratchpad mode is exactly like Sepia mode, except evaluates the current line and prints the result on the next line.  File: sepia.info, Node: CPAN browsing, Next: Customization, Prev: Interactive Perl, Up: Top 4 CPAN browsing *************** Sepia has rudimentary support for browsing documentation and installing modules from CPAN. Modules whose names, descriptions, or authors match a query are displayed in a `*sepia-cpan*' buffer, in which the following commands are available: `s' `M-x sepia-cpan-search PATTERN ' List modules whose names match PATTERN. `/' `M-x sepia-cpan-desc PATTERN ' List modules whose names or descriptions match PATTERN. `l' `M-x sepia-cpan-list NAME ' List modules authored by NAME. `r' `M-x sepia-cpan-readme MODULE ' Fetch and display MODULE's README file. `d' `M-x sepia-cpan-doc MODULE ' Browse MODULE's documentation on `http://search.cpan.org'. `i' `M-x sepia-cpan-install MODULE ' Install MODULE and its prerequisites. This feature is not yet well tested.  File: sepia.info, Node: Customization, Next: Internals, Prev: CPAN browsing, Up: Top 5 Customization *************** While Sepia can be customized in both the Perl and Emacs Lisp, most of the user-accessible configuration is in the latter. * Menu: * Emacs Customization:: * Perl Customization::  File: sepia.info, Node: Emacs Customization, Next: Perl Customization, Prev: Customization, Up: Customization 5.1 Emacs Customization ======================= Since Sepia tries where possible to reuse existing Emacs functionality, its behavior should already be covered by existing customizations. The two variables most likely to need customization are `sepia-program-name' and `sepia-perl5lib'. General Sepia mode configuration can be done with `sepia-mode-hook', while REPL-specific configuration can be done with `sepia-repl-mode-hook'. `sepia-complete-methods' If non-`nil', `sepia-complete-symbol' will complete simple method calls of the form `$x->' or `Module->'. Since the former requires evaluation of `$x', this can be disabled. Default: `t'. `sepia-eval-defun-include-decls' If non-`nil', attempt to generate a declaration list for `sepia-eval-defun'. This is necessary when evaluating some code, such as that calling functions without parentheses, because the presence of declarations affects the parsing of barewords. Default: `t'. `sepia-indent-expand-abbrev' If non-`nil', `sepia-indent-or-complete' will, if reindentation does not change the current line, expand an abbreviation before point rather than performing completion. Only if no abbreviation is found will it perform completion. Default: `t'. `sepia-module-list-function' The function to view a tree of installed modules. Default: `w3m-find-file' if Emacs-w3m is installed, or `browse-url-of-buffer' otherwise. `sepia-perldoc-function' The function called to view installed modules' documentation. Default: `w3m-perldoc' if Emacs-w3m is installed, or `cperl-perldoc' otherwise. `sepia-perl5lib' A list of directories to include in `PERL5LIB' when starting interactive Perl. Default: `nil'. `sepia-prefix-key' The prefix to use for for functions in `sepia-keymap'. Default: . `sepia-program-name' The Perl program name for interactive Perl. Default: "perl". `sepia-use-completion' If non-`nil', various Sepia functions will generate completion candidates from interactive Perl when called interactively. This may be slow or undesirable in some situations. Default: `t'. `sepia-view-pod-function' The function called to view the current buffer's documentation. Default: `sepia-w3m-view-pod' if Emacs-w3m is available, or `sepia-perldoc-buffer' otherwise.  File: sepia.info, Node: Perl Customization, Prev: Emacs Customization, Up: Customization 5.2 Perl Customization ====================== When Sepia starts up, it evaluates the Perl script in `~/.sepiarc'. The following variables in the Sepia package control various aspects of interactive evaluation. `$PACKAGE' The package in which user input is evaluated, determined automatically when code is evaluated from a buffer. Default: `main'. `$PRINTER' The function called to format interactive output, normally set with the `printer' shortcut. `$COLUMNATE' If true, columnate simple arrays independent of the value of `$PRINTER'. Default: true. `$STRINGIFY' If true, stringify objects that overload the operation independent of the value of `$PRINTER'. Default: true. `$PS1' The trailing end of the prompt string, which should end with "> ". Default: `"> "'. `$STOPDIE' If true, calls to `die' from interactive code will invoke the Sepia debugger. Default: true. `$STOPWARN' If true, calls to `warn' from interactive code will invoke the Sepia debugger. Default: false. `$WANTARRAY' If `@', evaluate interactive expressions in list context, if `$', scalar, otherwise, void. Default: `@'. Additional REPL shortcuts can be defined as follows: `Sepia::define_shortcut NAME, FUNCTION [, SHORTDOC [, LONGDOC]]' Define a shortcut NAME to call FUNCTION. Also define a short usage message SHORTDOC and documentation LONGDOC. For example, Sepia::define_shortcut time => sub { print scalar localtime, "\n" }, 'time', 'Display the current time.'; defines a shortcut "time" that displays the current time. For more examples, see the function DEFINE_SHORTCUTS code in `Sepia.pm'. `Sepia::alias_shortcut NEW, OLD' Make NEW an alias for OLD.  File: sepia.info, Node: Internals, Next: FAQ, Prev: Customization, Up: Top 6 Internals *********** Many things remain unexplained except by the code itself, and some details mentioned above should probably be given less prominence. For developer documentation, please see the POD for `Sepia' and `Sepia::Xref', and the doc-strings in `sepia.el'.  File: sepia.info, Node: FAQ, Next: Credits, Prev: Internals, Up: Top 7 FAQ ***** Can I use `Sepia' outside of Emacs? Sepia comes with the `sepl' program, a command-line REPL using the `Sepia::Readline' module, that provides many features of the Emacs-based REPL. It could be improved, though - patches welcome! `sepl' currently provides completion for `Term::ReadLine::Gnu' and `Term::ReadLine::Perl'. If you have neither of these, using `rlwrap' might be the best option. Why is the documentation in TeXInfo format?! TeXInfo is the worst form of documentation, except for all the others. TeX and LaTeX produce beautiful printed output, and Info is the best way to view documentation in Emacs for things that are not themselves part of Emacs (i.e. "can have docstrings"). It's awful to edit, being both verbose and redundant - just look at AUCTeX's `texinfo-every-node-update' for desperate placation of the suck, then try to figure out what's wrong when `makeinfo' complains about `texinfo-every-node-update''s output - but it's what we have. At least it sucks less than `DocBook', raw HTML, or `troff'.  File: sepia.info, Node: Credits, Next: Function Index, Prev: FAQ, Up: Top Credits ******* Hilko Bengen Found and motivated me to fix a bunch of bugs, created Debian packages. Ævar Arnfjörð Bjarmason Miscellaneous fixes. Tested unicode support. Ye Wenbin Found and fixed numerous bugs. Free Software Portions of the code were lifted from Emacs-w3m, SLIME, ido, and B::Xref, all of which are Free software.  File: sepia.info, Node: Function Index, Next: Variable Index, Prev: Credits, Up: Top Function Index ************** [index] * Menu: * sepia-apropos: Navigation. (line 68) * sepia-apropos-module: Navigation. (line 71) * sepia-callees: Navigation. (line 81) * sepia-callers: Navigation. (line 77) * sepia-complete-symbol: Completion. (line 38) * sepia-cpan-desc: CPAN browsing. (line 17) * sepia-cpan-doc: CPAN browsing. (line 29) * sepia-cpan-install: CPAN browsing. (line 33) * sepia-cpan-list: CPAN browsing. (line 21) * sepia-cpan-readme: CPAN browsing. (line 25) * sepia-cpan-search: CPAN browsing. (line 13) * sepia-defs: Navigation. (line 60) * sepia-dwim: Navigation. (line 20) * sepia-eval-defun: Evaluation. (line 12) * sepia-eval-expression: Evaluation. (line 23) * sepia-indent-or-complete: Completion. (line 43) * sepia-install-eldoc: Documentation. (line 29) * sepia-jump-to-symbol: Navigation. (line 36) * sepia-load-file: Evaluation. (line 17) * sepia-location: Navigation. (line 29) * sepia-mode: Editing. (line 6) * sepia-module-find: Navigation. (line 64) * sepia-module-list: Documentation. (line 25) * sepia-next: Navigation. (line 98) * sepia-package-list: Documentation. (line 19) * sepia-perl-ne-region: Mutilation. (line 17) * sepia-perl-pe-region: Mutilation. (line 12) * sepia-perldoc-this: Documentation. (line 12) * sepia-perlize-region: Mutilation. (line 20) * sepia-pod-follow-link-at-point: Navigation. (line 43) * sepia-rebuild: Navigation. (line 102) * sepia-rename-lexical: Other commands. (line 7) * sepia-repl: Interactive Perl. (line 6) * sepia-scratch: Scratchpad. (line 6) * sepia-set-cwd: Evaluation. (line 28) * sepia-var-defs: Navigation. (line 89) * sepia-var-uses: Navigation. (line 85) * sepia-view-pod: Documentation. (line 16)  File: sepia.info, Node: Variable Index, Prev: Function Index, Up: Top Variable Index ************** [index] * Menu: * sepia-complete-methods: Emacs Customization. (line 13) * sepia-eval-defun-include-decls: Emacs Customization. (line 18) * sepia-indent-expand-abbrev: Emacs Customization. (line 25) * sepia-module-list-function: Emacs Customization. (line 31) * sepia-perl5lib: Emacs Customization. (line 41) * sepia-perldoc-function: Emacs Customization. (line 36) * sepia-prefix-key: Emacs Customization. (line 45) * sepia-program-name: Emacs Customization. (line 49) * sepia-use-completion: Emacs Customization. (line 52) * sepia-view-pod-function: Emacs Customization. (line 57)  Tag Table: Node: Top331 Node: Introduction701 Node: Getting Started1139 Node: Philosophy1764 Ref: Philosophy-Footnote-14830 Node: Related Work5064 Node: Editing6447 Node: Completion6928 Node: Navigation9005 Node: Documentation12904 Node: Other commands14474 Node: Interactive Perl14809 Node: Shortcuts15705 Node: Debugger19715 Node: Evaluation21259 Node: Mutilation22235 Node: Scratchpad23187 Node: CPAN browsing23592 Node: Customization24586 Node: Emacs Customization24892 Node: Perl Customization27403 Node: Internals29299 Node: FAQ29655 Node: Credits30852 Node: Function Index31304 Node: Variable Index34223  End Tag Table Sepia-0.992/Sepia.jpg000644 000765 000765 00000124412 10732630143 014632 0ustar00seanoseano000000 000000 ÿØÿàJFIFKKÿþLEAD Technologies Inc. V1.01ÿÛ„         ÿÄ¢  }!1AQa"q2‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúw!1AQaq"2B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÀ ÿÚ ?üÑ4M_Ěƙáÿ鷺Ʒ¨\¥µ¤FI®%c…DQÉ$1@/,îtëË« ÈŒvÓ43ÄH%NãЃ@š¯†Â€4ü5àÿxËQ“Hð†ñŸ‹ ²‘c¼“EÑg¼[w ®cS´Ò€9 Ë;½:îëO¿µ¸±¾µ™¡¸·ž2’C"’YO!yPj( € ( € ( ¢?gU0^|_Õìa†_i_ 5k­³bHf&¦’!‘—KYnÜcîí-ü4èŸ üö…Þ Ö|ðSBø×ªêÚ…ì>1¹¿7.Ú ŽEX¡)[+D|ß´8Á.FvEyünÿe϶©o]'âe¤~–Gùã3ÙÜÈãç•ýÅ“6iïFÁ±Ñüð·Œ,(Õ.á7ÔõmFêæ  »1­»\¤±­°Ko._´H¸s!ì„ W¿Ýü ðv‡ðÏ@ø•¥x®öð_êÆæX5]RÚvò…»™’8^H!rFH du ¯ÆŸ |¦xãá¬>/ð…<á_K¨xn;Y|?{áÝWM¸xã[{ë‹i§œâšXØK•u)Î0 ƒcKú™ðóSø÷ð[Á^ð—Ä/è ìôíjÖU—PþÛÕâÔíg¾òV7Fu‡{  ÚÌ7#9ÈÔ.|â“ðïáψ>x>íŸàêð‘3\®©msm§ÝÜÀ#a/–^R»àH<óFÁ±¿ã?„?´ï„:Ídž|â]sJ¶ð­-<2ËjÞ9I5F¿1ìó £[ýœ0û¡w ÔùÓâ ø‡Âw66^$Ònôk˽> BÚ•Úïo2 "“@t!†{{Ðßúo„%yZΤ¥~#hk[·cû©Ààtãé@G뿼á¯|)°ñÍ…ö«âÏ|<Òu߆BXü‘É\dü°‡\ûµ¹_ùiFÁ±éÞ3‹Uñ>›ñ’æ/†ž=øË©Mñ@¹¹·ðÞ¯qks6‚7M+ÃŒÀ±#O\ÐÆß´ß…|G­ü\ø™â{;ÝB×KÓt»ï=.‡^X-áw©Ä’Ã![rÿyÝ #vêµûËñ/ÚÀCáïü%"ÔíÓÄŸØË!ÙÆd !ÎÐwqÒ€6þ è~1‡Pø…ð?Sð?Å3\½ÕtíVî À¶Ú®–mÚ@ŸhmÛnÆé±e Q(Ø6=¶Ó\°ø‘ñã‚ü §üE›ÃÇ⯈#ñ_‚/-Õá’Úšòአ¶/æMöŒ€¤³m;ð ƒc;CžO‰0øÃ xcà÷Œüoð{Ä_'Ô-üKát鋤mÇæI*ÆñÄWndÚ¼g×Á±ùëã :ÃGñoŠ4+XOév:½Í½žª‡+}JÊ“gPñ v€ ( € ( € (Ö¾[xÂ×^Öükà«­:ÛSð^‹&¹5‡Þ(ñµß…ü ãŸÚ|<ðƒ·†¯ïø× ¸’8ÂÇþ¾I®¦pUÄ|·&Á±ê2ü|¶¹žÓÁw^?žo† ð4gÑ\¹°:ºh»Q¸3-â¦$#†PC(Ø6&“ãÕ•çÄøtáñ};ÁÖÿ,,“âÝ݂鿌÷æ(-bšå§ÓþßäyáÛÌ‚_3n0žVìqFÁ±àZÂÚ?‹î¾#k¼?ã}GOñ^ŸË[ÚÜ%Ö°Éux”2!‹a.UÝ™[q ê«_ü3øiâ¯xþÓâÏ…¼FuÏŽ~ñnŸcáØoMí¶™åüò³ùÆ« YÕLa‰Ï·4l©|`ñ'‚-h›/ã|¾#ñö½­ho¢x“IÔn¤žöÎ6¼gXæ•DòÕàVn: Š6 BñÇßø—Ç­µ¯E¨øBß↵_@ñ1·¶†–kÉmã ˆÎÒKàÙç&ƒc•øÓãû?xâ/‡|YñÏÛÄÞ1‚óÁÂw:xfÛÏ”É9i`Chš8Ì1g=HùFMƒcCà7ŽüðÓž1ð Œ|gâø|dÓŸÜkÚÆi­i«Ž?"æÒ?0¢¸‘ü©w‰ÆWØ6;ÿ |YðmÏŽ¼ ¯x3㟃~xoKøsªx÷H±‡R±ƒ]GÔ„é=º¤NóÀmÂB#›iËbTo$›Çà=sáv§âOÙóÆZ¯Å_xVËÀ#Ô_]±Õ­ï>ÕpªMyÀ±Âë"4s*ä²í*Ù “`Øü÷¸…šâS•å` Ÿ\ý(³ 0cœqôã@›~»q€TŒû}zþTl¢ÈÜ“š–Þ•ˆvhÐ+`ª†;°vŒdu8ì2yÆ)=b1UNá’Ø ƒþýtÀtP™ÁUFI4͘ÙÎ>ÜŸð UË*çžÜâ€ÜízP•+žކ€@UÜq¾Ÿá@  € (톣¨iS=Ι}y§\42@ÒÛLѱŽE(èH íefR:H=hØ6)PÍqpË4ó2@1 —8Œg?/§$ž;Ðe–Yå’i¤’i‹<ŽÅ™‰ä’OS@Ð@ p}G½OíeŒÊ_ :3Œç¿ÿZ€¢‹óNy¡ÁÀëô  †1ÄlÅp¬ÊÀg€Ç?•Fƒd1ñæ†9 ´Çq@lY÷lYÓÊ*¹6xç?ZdÑ–còõxü¿•XX‚!U‰ þ~ôXD#pÁ·$hrGQí@©ýì[’2J“…PB1Àç¥ X±eãi±îrSòô皌ǟ+*œ"ç9Æ;àŽ8þt PŒ¸0üòOãøûÐHȱ™U[å(#yÇáFÁ°’lòT>æ‘#pQëÛ'Û9¤`G+,@Á†'§úš{Ä>CÈ«å¡P `è?>s@bRÞ«†ÂãÛõ‚€eDqòä’JçóÖ€+îå\ _oN½¿Ï4…IÏÊ:’©˜ü9Ó‚ªÅŽîF=€ Ý„ØG«cše)cv  € ( € ( € ±Eÿ[`x=>¢€$‚! Øòœ(~þÃó ­©õhÁ(n½zš¿ vÄË·îóõÿ>Ù©nºB¬*Àbxç$uÿëÓ½» , ²ô#µ §°Æùl À)'ãŸéL.;FÐp2;Ÿ­ †¼eww`=¿Ï¥$ÄÃaV/–$t—©ŒaB` ÁÞóƒ€3ÀëÇn¸¥`°ç\€ØÚÀŒz®>´À€Â,¼@9ƒ×éúw  6•GŒŸ—fÕã¿ù#Š`Ž8ÈË\ßsíþ}h 1p›~`ãsž3Ž•G$[ä?#¦'r럻þ}èØ6& w¥™—8ÜÇæhË«¿`o–5 p=?_J¦G“lw©q†L`?•:vwx€ r™ ôïš«´’NNÐGb¡‡OZAÀ<íã§­ñ@;PP@P@P@ ‚  Ž£(êÄÀ¦Ý«°í×oo΀,¤#*Ø ´íÏ_\ÐØ`vÂ…e¹Rý*%4‚Dz|=ø)ñâIcàÏ _jöñ ³]–H N§G!AÀéšä©RÊïbáI·¡é&ý‘~:x[ÃWž+Ôü$þ·Rnï´ëÈ.ÒÉ-És“Œ s\òÅFºkÍìk?7ÂÓ}–çÍrØy9óÔŽ?ÃÆ?¥u©Ë¡‡%Šÿf‰T §Îi$ÅÊ‚ €íœâš›¸íb¶)äçoR; µRÒØOB'Ë Œ¶ äcÐf­I$J¹–à…ÚÁ±œb«™XiŒdÚ\r?çÖš`ˆÖ"»H±Áççñþ”^ÃT®1žœv¦ “œü£¯^Ü~T›PFO î$€qŸþµ ?z<žNÈÎ8õë@…0;d\g”nÇŒ:r•ä[…Gv_”ÄØ*ÝŽO\zqBcJÆ›Ï;Ä€#†ÎÑÝqŒç$ƒÆ !@²M&æùú.Àn0iŒ@ 4L±Ѹ¨ëéÿ× ÙX¹dQ…Àà” -°£¦{ mP@P@9rq<Š–Rž¨7OZ–|—XðK ¡€?犽©^9#¸ÿ³o[ À§¿8úÿõª'.T ÿû>|,>"i^»¹k :Í©Ü#glK‘·ýæ$(ôÍc&”žÈi7$–çí~µáÛ/x[CÒt}9aÒ4×éÚM³íH`κ©ù܃œžIäú׊Å^¤\ÿ¤z¸l-£%_ŸõÿÛݼ3âÍTÒí´+KdÐfB¼q 08É`x#Œxù‰ö­(Ⓡ,?¯ëú¹…|5E.i;¯Èø‹öÕý”|wà}WâçÃí]ÄV2†Õìíe¤ñÆ28aê¸Ï=qWí>¯5ð¿Ãþ»:ë]û÷?:þ þË¿~7]¬~ÐHÓeIµ;ÓäÛ¡ãŒòO$(>ýkÕq’NKoëúüâŸ+Üúú÷þ §¬øwOšãÄß<=¦Ë; µÓ%¹Á9\œœZૉä\×þ™×J‚•£gëÐùÏâïìk㯇>oiš•—‹¼<±ù’´I ÄIýö…ÆHÇR Æ:S†2I¨Ïð…‹àþóâãE)UáBsœƒšîr\§Ž£XŸÝçoCõü)¶’±1w*!xþojx·Ô#¶ÓâI˹Ø!ÎÜ{Iú^KÍe*›_×õÔõéåêœ|Ìí>yþ"ÝEw¬\%¾™idc‚ß!VqŸ˜²÷ëŽs]QÄJSu%¡„¨Bå‹ÔüEøÙá› |Nñ–¥GåØA¨±·Œºóù’?/Çè0rr¦®x˜¸(TÐófÈ]}¢Ø³\y"Ûqó>è;±ŒmíÉëÚº¹TRoú±ÊµÐ¥°r01Ž˜üézV#0êØ83ÔöþµIÉ+ÃZÝxÀ+Ô¸ïMJIØ› ÄlŠŒÀŽ çëJ4ÀÎx™w¹ yöô®˜É0µ†U߸§œdàh¡t*6ìÏAÛüþ^8öyxºò3×ñÏùéÅ(ØÃ?^ÿÒ€!º›åˆžüƒù‘@ Žªˆe­€T—ޏJªw–» 0È;G$cŠäÎ?@zžÝ½*um‹…‡~}9úPP@P•ˆ \p:PëhXá¡” £çp;ÿ‡åI´€êçðî±e§Úê×VɦÜX.ü†LW‚º\æŽ.›—*zš:Œy­¡M-Ù ‘”gÿ­ß¡ªuÐɦJ¶Ê?‰ð1€OùúRR“‹ðÛcòíÏñc¯:ÍZÅZÇéW€´4оÙZl·¿ûVŒ¿l¶x¶In\ÝÈùÎqÏ W‰›Õ—¶iè•—à_-¢”êîÎgLÓ ½Ô¼?§ønËû§¸XÞÁt²¶FBƒÏ|ç§¿9® 0S­³×cÒ­Q•’Jßyö÷„?g¯ŒzÅôo¯É§økÃmp9¸¹V¹Š0ùQr3Œ g­z §VòØâxµFá¹Ýøºêëá¶«oáfÖ"‚ä¹bR¾^~PXžsÓŽ¼×"~É8Çc¢’çIö<Uø”ÇÆè—·ÐGb3 ì­‚ßí§¶kÇ'Y³Ó”•8«_3ÍüEâ)t©%—K¸IÅËì Äœ¨ö=?Ïõ°j”aýlb±ŠS’F…|w©jWé_l¸°u·Ý=ËpcNŠ;œöÏjp‡,.žæ2|Õ› üxÓ¤‡â‡‰!yšúUhüÙ9qŒdå_M‚OÙÙ=Œ~ýÏû9B ÇdÒºW‘ÌýÝÈ_OtZ2¹à±Nþßçóªr¶ “½ˆÐ¹P•PI\Ñ;‹bxìVFÚ±nÂô\þ4·Ñ "„önî c¸÷>”“²³@Öše× W-%–[ù4É#ØáNÀ ®ß½Ê½\=8V§?{–IiëØá›têGKÇ©õ~¯¨h« ê>7!5 8­Y’!¼ˆð»‰î¤ãßëŠù\]oiUÕîÏz…7I(Xó/‡ž?Òü ãD×¯åŠØ[Ç"ZÍFV'-’#ƒÆ~k*3«Jœ½ŸÄíéýhtNœ&Ò–ÇÐßí£a|úlZVŸ ·0b2· [ÏÇq‘Î=)B®!˘•Bš‹ÔÔø«à/XøÃãŠ5½:Þ÷SoK…ŒBÒåUÌ3Ó¸§‰ÃÎnÖäá±~ïCó¥ïußj3Í[7b­;3eÏ'“Á<Ó§ tW+ÔÒ¤ç=Rþ¿?ëÐ÷tÔ¶¶¬êЍZ[œ‘&0IU×>.³©;ì­ò:0öq²Üö¯x FÔ›K¹ºÔš;û©Ð$qI´“Ž'œt÷§†ƒUe‰©ÉÙ•ñoö%’ëÄšõŸŒqâ=ZðÜ,öÀEµ†H,9Èc×ô\«’›½ºmý]OQæ|íZú_{¾ÿ‚wxµüãxÿV‡@¿Ól™ô[+^ù–Ѩp£Œ“׌b¶ÅÊtè{Xü]¼½­Ž*§:ê”¶îsßÁïk¿³–³iàÿ Íÿ ï…æ¥æ®cv—R•O$@w¨+·œä“ˈœœ£U;Fö~ŽÉ?“üÎÚtáÊ÷·^Mj×õ±ðÄ^ñ‘[\Á£ëfº‘–ÞD‚JËÔ)Û‚FG‘‘]RQ½ºÿ[Ðm+ôïþgêOì'û#ÚO>½ñã/Ãè®4{{d‹B¶×ì E$¤Òµ¹åÀ\HÛ–=qšÓAà ¾¯§—Ÿõÿ 5®•µG~Ú?³ÿ†ü!&¿ãé–Fª±=³*1.v(A÷3´• q€rA¯žÊñ5•*¯ú_×ã÷ûøì5)Rç‚×KŸš“Û´DËÌŒœvôö¯¡Vhð6+í`ãq,ÀÚ8yö¤¶Ð±U¡Dqóðí´*Ž•´fÚô¬UtvÂØ`ãµk-†Æ2WßÒ¨¼¡Æ \¼ßã@ h“%™' ýsþq@íE3D…ÏRr¤à‘ñæ€ XÚ'x¼È× –ÈÏíøŽ(MÿÂW»œÐ°©Q$ª U'§·ÿª€+Ð@P€I “ÐPµCc*àüì[9äc4·eq%´°Íe•H1°nTöæ¢k@Zl~¼~À¾>¼ÖnF[3ןq^UIÅI-öþ¿®§t"ס¹á? ørÏÄ7ÚÚXØE-ér’Æ :8-‘÷rãòª¡MS…º˜×”§³ò±Ùøƒ@¼sÞé•ÍÖ”Bnµ†T §<òp­ÇLó“J³””–ˆŠOt·?¼}¨ßÛx÷Æv¾½×çe˜¸üÇ#¦=8éÅx4’•ÿ[³éjsB|¿ÖÈóËŽ¶Ô ¶Kö›ˆÎæ_P}€ô#Óš„¢à“ØÕ6¶)ìië,ÐÛZ\Ƕ\²¬!™;xQÇ ­ðïØUS†¶1«ïÓqz\û£âgǽÅŸb´»Š[ówj †Ý_màƒü8<ñïZʪud›éý]L)PP§]‘ðæŠéslÑßj7+Œ$vê¤ô Ó§§Ò¹&¬ýÔvGc½´×b‚ÚÚ8ž(R5‹ ½=3Ï@kŠ46¿Ö§Dë%º?f_'u“¬ÜÚ&•£hQ&’6ži¦=ÔÁ|€8^3Í{<*³ŸÈó18§õ{Ÿ}¦Ÿa©_Émá-cVšHáIïÁ-mÁÞbåca¸Ço¼{÷Ó¤œÕ•›Ýžl±„9o¢^—=EôË­Oëz¥ƒî…£ŠKKuF`ØR1ŽŸîö®Š”âàâôèqAJüÉÜño‡ÞÐü!u©ØÙÁgö„èØ1†/ŒàsÔ“ž cjÔNê•yçκ‘ ž…áѺ>es¹Úv0"" *qÁÁû§ŒãÒ´¥8'©…XÔ›lóÚOâö™ðß᜺™–ÊÂâæ1öxBn GÎGÞ÷䦲Åiî¯ëú¹® WyÍçÄß‹>8ø€n¬µ­j÷ûï>Ó€ÝïÃÇÕ†æÁí“Í*XzpJJ;V­+ò¹$ny`Ì7&pß–=«µI%cŒ¦Ñ.’pÀc?ýzj7Ð63Ì68,œ„ÆsƒÓ­>}5 XŒÅÏÎþ^Ü«mü==qùÖ‰»‹b«¸Ê¡8©§d{Tcqè:UÃ÷h죓Éçð ,À‘ó ¶Q¿çüû€T´ŠªÅTžê„öÎI —É(Gcó. Ç4i–ˬjšš >Øž!»Q…U0C)ÿLJ'ŒsÍxi{4£Ý~§·óɾßäžµH-m–aq,7I#)]¹ú€9Éü¹éÝ'ØÝ»œÆ¨’\Z´zŒR Лá’5ÜO~~¦ºi7¡ÏR1h«ocw%‚êzŒé¥ÀÛ’>ÒNNx¦ê+¾¡Z'Y¦­šÏ±X‰ì‘Àc3(RÀëùã>¾™®Yé£þ­ýW:b´=JÓM·½¿–êî-mmmí’)mݨPx9 ç ÇaXPæQåŽÿ×õÐu•çwÓò?F¾j÷ÞðM—„´ûû}Q¸¶†mF£¹•;A*C>09•PöqP迦xn¤ù­£ëä}Ÿàé÷=®…áÅ’ÛQDú¾¡2üÒ¹áÏ8 ýz lí)BܰZ.‡‹·4÷ÿ/Èôo_µÓmgÓš4ûBÇåDÓ ¦xê;ãÓÔZËžñ³ÜÒ•7uc€¾¼Ò|3£Ÿ̶÷ em)¹…_v€Øä‘ΦsŠ*JÚ"èÒ›Óþåu4ø¬º4Z÷Ù´Km6ëmÌ:vL `d+ƒ¸·ãÕ­<4”§oëúþ®{8l>§¹ÎüϾ1ßéï<)ðÓǶ× µ“RÙöë7ó#ˆ°ä*°P€¸ ƒ½x5èeécdÔ¤“²ïn„f8)ài)[š-­_ëÓCñãâÃ}SÀ¾+Ö4˜­õVÒ­5 ¢Óïo,šµFŽÀJïÆµÂÕS¤›ÑÚöG^“UJë¹ãSÀC2>å$`àãôé[&ÓÕò‡.Æd¨ÈNᆠ2p!øV±šN䨤ñ²–Úx<¯óŠ©'{‰hQ(±²Hî#Û÷T)ïýj”¯¥…°Ù#Sj/Ìß( Ð{‘Ö”eg¸ö+ù[A.vàà §'üóZ)v¬DTýí¦<ô8ýj–°…A#¨Ç¥0" wãý¬Ÿoò1ù÷ aJ Û9ä1çüŸo¥1ÜbQ²]ƒ•ÎÑÛåô  º( €pNãPˆ£"UŒmV\ò Éíë@Q&Õ¨>é'¯çòÇáíJö í*ݾÝn¹ ‹"œvÎ{Vji´)GCôoàŸí“¬~Ïž×ü-eáÛoê—:u¸Ò.î®JŦN ÌKG°ïíí ¹#$œšêÄÖ¼=žÒO’_¦Ïcž’jMi×ï¹ÔþÇž,ñ'Ž~4xÃÆ"Ô®u]FþÄ˨ßÜ9ÞÒ5Ärn'×1äcqSBᆒé§Þîi:Òö‰­ÿÊÌýKÖüU¦é`Ò­lLò[éêÑH’.dÈÆzãiή+”äÜßMV•&ã½?¯ëüÎWW:þ»ä–Zuΰ†íãr¶ì„±à*®qÜdž>b8Š¥~^̵hNKçý]OÏ¿‰³i¾2¹ûD ¼NÌ$’LÄýÒ:pqùc>Jžë=šPjV>yñ&Œ“¥ÕüÄ“[RÔQ‚If߸`³8ç§éN¥åøm8ò^ûoÿúÜõƒ:­’ÛE&–-ï­.™Zi{lÜv§$•]ÄpHú×Z’””Ÿo¿ÔæÄBQ¼cÜúR=#ÄWm=ާ »C©²Ú[c}Ö%Hü­W°´naÖÓk3’¿ð™©Ë„îšWÓ®îR+ŒHrÃr49äÆxÉ©¡üH¤öý eVQ„¥òûô?)aý«'ðmÿ†n|5£OªIdl¤’úÉ%&&V]ŹÝ×'Üs\˜ü-:õ^–O¯Tôü ÁÆxT›{tþ¾ïÀü,ø×ðŵwU‹C¹_ Û\"ÅÖ,0c¯ü³N[8©=n\éhÜ–ÿ‚|Ãue.×ýÔ…õUÀúûWD[„¬r¸ÝsÒÄQˆÚXɘ«QMé¡-@;äIäaIïÖª-ê!•É."zäŸÿUU;t …7ïC Êå1YÁsÐçÓSm *˜£B[æî!†Ñ€8ïùÕ+†Âg qŠ`WùJ]þ\7Ⱦ½,ÿŸJzÈ{Ñ÷KcZÆÁÁ88úQ°l% ~  öv<©”Í#V>„ûþ˜ýjg%v5Ý‘ôÿ†?e/‰ú©‚ãX¶Óü3kpüËùòÔŽ F¡›AÁZó¥Nê+ïÐõ!”WqRkO¼öbÝiW:„üIáïÏnà}Ž síÇÌAn2#íøVK;&ÖžF5p‘†ïï8Íöcø¹gâ[[MsÀúö›iFéåx7£F£'pNÎFyÅvÒ­N›æ’øS–T%$¢žÿðçØ6¿³ßÂÏøk-MÖ¼!âÝ:u‘õ{DË]Fê+#½8ÁQŠ©(Ê2·Gþ6T£(&œoÛòý¯áσ|9ð¯Âš´^šæ}nþðyw·NI• Àª02ž£œæ¶ÆW¦”hÓÙjÙ8|,Ô]J‹É.‡©x.óQ¼Ô¦×ï®ã’òâwßÙ´* ûÀË tàõè<¬]”R·ÇëþôpÑ´š·côOᦽ¥êž á² y¹ód’ÜiQN:qÀÆ=«Ñ¯*j~‡Š¥%UÂ^‡ãOĽvÛÄ:¡¾Yãi#ÊyR¨éò“ϦIôí×ð5nž›ŸqA$­?ëcȵhn5«ìC ¶Ò‰T˜•Ë;qŒO ­hZÓ©›–ý<)øá¥Ó¥´ÕtèÒ"|Ë· &;.?Lšõ0Ú|­ªi+ÜÐðÒ^Ëj·ØÆ¥åP$gÚø° žjËÊß+þºДâ¯ýw=7N·Óíç™gigºXÎ"ÈBÄ’xÁÇCë׫Δ¥(®Çl#;uþ¿¯Ðû×ö8°Ò5Z„¶·±†i€‘ÎUFwrNÑ–ÀÇnkÛÊh»óÉè—ç¡âçi5ëó¿è~Ÿ·€<-gtšÌPµ´ð1‘ÛqÉÃæ$Ï^=¯WØFÜñý¼Ú²ZžAâ[Ã-âéÿ°Z[8‚ÞÄcØ›$`ž§§Ozçåä“QÛm>Gd§©-~g5¦ø–êÖ—Œl¯ãÜçÌ,HÚ[=r8ퟦsEÞ͸1U¡í©ûDõOúýM7Å—2j….Væ{Ä»²¾x„aäf#oÝí´À‘Ö¦Ü9{ù—=“ô?;þ4~È>+øÁñKÄ^9øwªø>-UÔ¼û¨µmKÈ’ÎåïP a¼1A8*qȯRž­kKÁêš·Üû[׺²<ú˜êJ¯%V•Hîõ¶Íw½»vÜôŸ ~Å:ÁÝCÂ^0µñÕçŠüe¥Ëæ^E lWoî²wü…óæ6 Û€ÔOâžÖµ¶×§ùmújJ¤â¼ï¾O§¼)mq­Çz—dxd+˜¥!ƒ ''Ü3ƒõèNUbÔ¡çnÆê·-V¥k+tò:xFñGƒ®mnlc»™m¶ÞÛ<fÖò Gä+ U%Q]íøÜ(b:–[ùícó?ÄŸ²Ýž‹áýZÆÏL°–Ìïe½wÃÎ{c séXâ¥(Æëuò6 é_mù7­iÃMÕo¬UѼ‰š0ÊÙÈ×ú×]9·qUŠSiãZ¾Qw1AÆOn½¿*èæNæ6±JX‚“Œàô5:F:0*IÀEÚ íÎ7üüV°]IJÄj³ÚΪŽT©À|ü¤úuÇjm¦„ŠNK1brÇ’sÞµZ aœÀ>”À„[´{‘ù{X£<ö Œ4|fR~P@úóÓ¥e£°G‰X a—Éàã)5bZ°ÀŸ1L€zsÐS(e9x猊ÔÓ§–Þx¥€´O‡Ôtaß4lÝzGí«j/þ/Ó‘u…D ¨éê'ÀÆæŒpsƒÖ¼Ú¸$¥ÍòèzÔóZŠš§.Š×ëcêφ?´FŽÓé÷ºuȱ’ã„ Ê¿!O$c'Ð÷³F•-oÓñ&¬1N[ô׿}«yñÃB_érZßÛ›“¹¦ŽhI#‚CÓ8îsô®˜Ón§uØó%»iùÆÍkJ³ð=¼ºN¡k§«¬7,ÈáÚF9(,|°½}r9í\õã8ÖPG¯©ÓB´eßkð³ZkÝMlu9î.5K¶û=Š˜öà ™ƒŽ\{æŸ/=ùV¿©n|”Ò–ßÖŸðç¨Üøi<ãµ[ŸµÙ¦š“,¬‡Ìv+ÁÌBŽ€ŒšÍÅÕ½öLé¥V4Ôd–ëõ4<'ñk^Ñ5‹­ËRûœ—]BÔE¼²Œnvæúu¯N¿³–ÆoK5¯Ý©ãr?oÌ–ºkm/öƳ˜1pP†N)$@ôÀã f¾«Yy^GØý–×ëϱÎÍ©Ïuog ÔKoÂòݾdÎ$v<ÕÆŸ+æM-ÜÊRMZÿ×õýt<ÿÅ—–óIžŸ©½ýô© u@wFÀpsÓ¾1=ë³ ­Ö†UœI3¥ðç„u+;(/Õô¹L°qJÿ×õ¡àfÒ‹’¾šÿ™ú sñÚßE‡Uðî¹ð׬¢qEÊ×õèqŸ¯üA¯øÞ Yµ’]3Zß"É4Ø–åe~a‚~Uf Ù<ž=\¿R•%öUý6üàœ™µrq«mvòëùöè}ª¿ "Škö”‚ÛbÇ ²ÅçSÈ'Ÿçžq×5´¹å¶‡B´iµùê ð¿ƒ,­µ‡†u{p1ÎãÌÝÈæäg¦M.e«’å:¨½^çΞ!ø§áéõ6ˆÝÉ¥–’$–ç‡#jàcÅ#£O•ã!OýõƒëWQÔ§f¬Û¹¦–R侉~¯úûŒìKJ›L×®¾Ësa®ÈD³[Ü£®ç6у•oaÖ¼Üd¯JP¶–þ¿#ª‹Š’w×V|÷ãå‡Z¸–É”œowrÌ9>ùÏð5óO•Å&{Vpzt$ðÄ,“ÜÚØÛ5ì½e¶–@ún##o^r1Ï¥g8=層&“´V§—xêÆÆ]oW“MŒøzâ 9ähØ„?0Ê®Üç“úW^¤”V·W·¡Ž&浺\ì¼ ¨j‡OÓà}uO s5ØÜ2yRwgþ‡>&0U¹¥ ¨h‹÷ú|±^=Ü2ÄÓË"´°ØªíˆtòpO~ƒpy¬¡eý]Íeåtõ>®ý´MSO“Q×ôõ»i-íÞY\ ª˜=ÉltÇSÓ½¬&)Â)ôü{f&„g$ºÜöÝ+Q³>-MOÄz=¸€[¼7 ±Vp@'=N8$Ÿjô=¥8RåkÓú_ðN)Ór³‹Ù6§®Øh 6£eoäÁ}&%!vÅ»€’<¾øïÏL"8‡*Ü›¯ëþîÓ¡%†r{ýý¿#°ÒgƒM»¹Õ"žkyî4ÿ·­ŒrüîѕޫÁ ©î:v⽕†tá&µµŸÞx«)8ÁéÓîZ~qóg‰|Q¨j·Z¶¯a¢é‘?™H÷’Y‹7±%H9Î8ôËT´JßõþŸôr1ŠW“é÷ÀÐú;àâ­úhž+ñ]°´Õü%nÖQ…†KbÍåã•ePK+Ã9qêÆ6“­ÒI«~~yâbªICØ-ÕýVŸÒ=îïãuŒ«a¤ÚZIi|“Rʜά^ì[w?Ý탎ÈÍÊZu<ÙaySæò<¯ã·Æ)4,o¥š ¤·Û/”ÿ½r s¾=Ié\¸™%v´G^®÷> ðº7Н¦ñˆV[M9´¶‡vùòBýñÏ‘ž„þUÇ 'ïKFÿ¯#ÕSš÷SÛþSÒìt[Í7Y·–)Ö4…_ÉÉP2¸ÇØJãÜW©C’”ZÕëú?ž×9êÐwŽºl¿ø&­¯Š®~x‡KÔ´}LËezêe¶d B #9Á×m G´~ÃËñþ¯÷~+ îûW§‘½ûM~Ò?<%ðÿOÓ<k¨Ýx“Xã[»kbÍ〠×ùöõ¯Õ¨æâö(B ›Ïî?üMk­EªÝÉâ(ï!ÕæœÉsö¥>avl¶Csœžs]Ÿ»¦ÆURÔã¤i”|Ã*3Ó?JÛ–Ú£=ˆJ•ݰíb?É¢ü€f6bfÊm;†ÓÀ#þ±Z%tHž[ôª‹ºÀêô+íœÑœ¯=*€Ç‚(¤%d˜Ärmß•Km&ÖÆ†¦¥|œî,ÄáAÈäŸÐqQLΓ ˆ’_Í#–!Ï××®F¥icD´ey#xÜdc%³ÓŒôü)”=c,±ç,p…zã Ïç@@8Rrй {Óƒ´nçëþOéXÎ\¬9S=ë³^ÜøOL¸ˆ<Ñ[^=³„\ü›wõ¬+&Úô6¡>H³Ýáðž©ká?W¼7vÖZ¢³Hq´HÝè;~´æ7Ë-ÿ¯êÿðÅÃOy- Ö Õôz=ä Gch×dŒ‚wsÜ÷îåÙ‚¢ÝU;h·ü­ŒkÔQƒ]á£týZö²Õâ‡ì¶–̉Av¢ªçqÏÞ‘’åŠÃ2•§¾ÿ—OêÇf\“ô_Ó(|^ø›yý›g£[Uµò¤Óã†ÜB …¸Eçxõ#§\ù5¦çi.Ÿ×õó:£IS›‹ë·âxöªÜêÁsª‰ÛÌ” džB<ÐÆF{OûXƒÅ­IBVŽÇ¡J£åG®M ÞiQYëÍktúg*·VÎíÏ nöàu9ËN´[tïgÐê'ylxOnn®µk­GO¼Û"ˆÓ 8ß·CŒW^ )èaVm»\ôMÿTºÑí¢¾¼ŠÝgŒ2Ål›YÆ Äðy#kžº„%dh¹5¹ÚéÚ%ãÆÚÆ—1 vÖöÊKKعÈÉ'Ÿrj!ghÇrÚi7Ðû?öY¸Ô¢ƒP³¾µ‡FÒ­õb÷ìv`å;°zpBzã9¯ ÀÓi§Qio¼ðñóMZ/þÙxÊ]*[»é.me¿»¿º–[i4Á$PŒY”0ÈãïH©ªÔ)Ûnß3£ Ö¨­®–·¡åÞ5µÔå¶Ýo†pûvµÆY! g,\(S³Ó¾qÔŸ3Võ¶‹ï>eIEnx΋ñ'ÄV¹w¬ø~îõï}žÞ)JË*Ü2ã,¨=:uæ¾âQpÃ÷[þ_‡õcáyyêÚÚ¯ëúF°¿ÔìuýpÇ=¬×ÍEŒJÛ `.:ñÎqõ3&”Ô/ëþúŠ2å ÷ëø/êÞ§Ò>ŸÄš'ƒgðÞ±t/õB_´ÝÂg’âIÀ˜Œƒ…@8=ã§=ònZ=ÓòÜñÔc7êߦ½/‡·æ/ÜêZ¼"q¦Hï,ÒnÜÓ*¨'i'<(”WM%6¿¯øUq·*Ù^]Ùó/ÅýzÿÆþ&{ôi'·–æD¶¶MÛÕ‚Êb¡O^‹è§ŒR8®‹[ïvÿ¯ÏR0i¹¸Çw§mí_ ŸÃZ„‡H³´ƒK[u[XÚYÄ‘Üpg8#wÏ©>•Çjvåð=6þ¬uóÊE·ê'Ä«¿ø:÷N±»ðý½†“=Ükq Q¡a‘Øäaˆ€@äb•RsJïš××OOÀmÍÒ“ŠÒöïÓ^†±i«si®Y£¼71nT,2Œ¼8êqÉ$gµwaéªZtþ­ùkær7ÏknEÑoî!ðàÕõ ;;‹1ØY´çåaÐŽœqÜúñïž!ÅOmשŒh&ÚOU®‡â?í ®Üx—â‰5 8iÙŸËû:€ãåŽk „W»êEw6îÏž2«ª¨2¨3Áïþ­v@æØ§ƒÛŒZ&Þ€‘RdÊ^rÃ*öŸ¥T/qGÀ`H Ù;GÖŠ)l-†Ýy"°É'Ÿ¥ Ká@F7ðçp*›°bê2¿4Gr;4d±lgœþþ¾i(Ø…Ë [÷6w|¥ˆàŸ»œõíŠ9m°r¥°ÕkÄ ÌO8ÂúŽ¿Ê«böçÎæÃdŒŒ(â?OÔÚ#£–lžµ.V>ÚJ*.OsŒqÿÖãéS&Ñ¡f3ݱÀçœqúVwÑ h}ÇðGÁ77_ |_qw§·Û­/๶Ëd‚¤·߇”aÉn›ý gÌÓê«>è–¾?ðƵá‹ëèí`Ð-—Ëšâ]¨¡¹ )뾃 tâ³ÇÞk™|°œ°ýÛØÑÐþ'ˆt]OÃcY¿Ð’.D°Û³‰|µ>ã“òÓ®*ñ؇ SÞ*ïçýl*QJ¯¿­Ý†ü3øsk{á»=Z½’ fî67VÈTþÎ9òHƾ3Çɸ¤¶_¿­O£Ê2ÕìÜæ÷¿üëäGñoö]ñeÞ“¥àß*ëU´µg¹°y„“ÉÜ)Ôl<`ëË&œ£ªíÕ|ŒêJ7åz=“Úÿ™ð–™ªj~½‹K½¹pñÎÂHf@†9:a‡QŽx¥R0šÑh(9Aï¯ä}]ð¿ÅÑêMö‰+³ZÆHD|`©©_Ë#·=sÏ…Š¦Õ´×úþ¿­=Œ$¬ìŽkSðM¾¯­­••ƒ_ý« 0W<áˆ9çëÍN­i´¢ÎŠ´iÂîß×õó=ßÁ¿ |áï³ÿÂC|x7´ûgi¶¨9;ÈAü¹¯BtÚWo™¿’ÿ‚gKwh«Xú>ifŸiý‘aiw Öæ(Ý¡W1®ßá…<ž¾¾Üõq ä×õs®†[ ó7±Åø‡Çzdíý™Úã`Éž7,d’BüÄ‚Lt÷®œ _Þ%}ßÕŒñØxJ>÷Oë©RâOìýKÏík¯í ë†Ì’ÜD&à6äoâ Ã;FNý4ÄÉJ¢Œ~ïËþÇGÙÃé·ê^ñ\Ú¾¡-…úC¥Ä®ek–d˜t(IAœ7~¸#&º0Òšï{_õ9q8¸7$Úµ¯o;Hóo Zê÷¦ÞðèPZY_];P[bb NYT… )‚[⾎¼©§Ëo“þºŸ?‡U$ܶw¾–îu7:^Ÿg¤^NîÁmd/¶&@‘€HIà°ãc8ñ^e8bcæ{øZ¯ØN)­äŸo»_ø¤Éâ{hv÷öš¢×Z½œ‡tY¹ç=‰;WäÏ8¯JRWp¾þ×êîy ”¦”Ö©içþZÓµ«›«]:öÖMbòIeFŒ©dP2IÇ?uëÇ~ì=8¸^û%ù³ÎÄUj§Ïôÿƒý\çþ5xN/ƒ>!ørt•eÕe±½¹–EŒK¹ŠìUä‚8'<×;9)EmoÍYmNÒk[þKÐù¡µaaÞ¯n.lLò•º„.ÉT63†9úf¸hó¨rG¶Ÿ¯õØö«¸):¶ê®Tð§‹õýfIlõ›«NWf+u)n~êíÝÇOå]å©M;]O/ûºÖ½™é?|M6ú·…¯õO²ÜHì`¸™~[y6…<“Ðàä^õ¼šœ#åøÿ_×rcQ«%+öô>ŠðF™­ÞM>…®Ílúeí¨K»I–DeNßbN@À52jiÅi.ß—õ©Œœ©5+ÝZ³óƒö›ýŸµK_jZ¹·þǽ‰"™ £ž~e?Ÿÿ[”chžŸˆU‚›µ´è~vOÛK,';ÒBl©­UšÔâk–V0€Fr£œú8®§x„ìŠì:€äþu1i +´@(S'’Èöªz!ìVdÿ–®¡cl»’>¿:šÃ¥„®7rGüúÓi-Î0©ÆåÜ£àu«Ø(RÀ6Ü`c9ÎÆi&£ ¢­¡"Bá·ÎW§EL¦]0ÀC6tþ˜¢öEX™!Ü0Ù%ÇÛôëPçm‡bí½žù#Ž(̳»áW’IÀVnr{ µàO†>"×|Ga§=‹Ø*Ÿ5¤»ˆ¢mQ»#ñéNžüÉ^ÛBÖGÝ^ ñ>‘ˆÌvökcg8ûÄ ÿ»b¨Fz{Ó¡.E%Ñë÷W\Î-o¡éº$~2¬‰§h‹#<óZËs¸ü¨êO7îôçЂURô³ØçæPm~;5ßï5tß‹(øv5Ö:œ¶:¬ ¶×  îF"«•n‚~^AÍrVÅ©^-kú÷ó5†E$ôþ´8„^:½³¸¸[)gŠñ‘mî9—È9ôÉàAô¯‘ÆËÙ»Ÿ_–â9£Ë#í üI¼²¿wË4ø*l¹,0lç· ç¶qa1Ö”g}{]-øXÜ ´õGÇ?´gìè|}â»|>Ô4Kk«¶+u§\î†IçÎI_—nH ö뙯R†Áó%ýÀ1£SÛ~¨èu\]ßÛiñM‹Á-£]Ÿg$)Âòx' ƒ÷Ž@º0ØF½ë?Ÿùÿ]ˆ­ ~êÛm Í_Dz^isx iW6wqΑ޵ºïò|¶oû¿' 98“Š÷èÔ„j%®š¯ë¡óuªBÉzüºŸUi—ºV“ðÍâÓo-”6ø\© ;N¤sО@w­±*Ô£¯’þ´Ôå¡uY®ß×õÐó_ éòj ªhW6&ŸjEeq(Î0 ’FWäd}+Ž­ê8=Ú×ɼ¦¦Ò²²ý®§Ò¾%ø=,šfoyâM3G½±x´ùM8Âå¸ &È#©ëÓyÒi¹´¿¯#Æ¥Š…ÒIžÉ§xU´ÝgÁzìªhöÀEÈy–G\3`ž¼AÏ$g¯G>Nh÷_‘äbš•ŸcÉ?i_‹5?x;LÓí·n¼:—‹}3|¨­&Å©ãq …l€2qŠó±0ƒ¼¼¾ýtþ¼Ïo*§7h^ÚßÓCäÙõoêž6Õ§Óìo ÑÊ´·ºtŠ «¢°ÈÆw1㎿—›ì\)¾W§Oëúè{1®œÒ–û?=WõÛ±ä÷¶6ëê<®»f7RŒ9Œt<Œ×ð®ªs•&Œja•h{ßõÓúû̈±:y:•­Ë,š…¢ÜG1Ü\œHî;öúÖÔ×*qKEýLãŤ”e}Zü¿­Qô'À¯É/…oâD•n­¡/™ãpMÀÓ¶=±ÅwãaÍKw<Ü%KTQjç7âßê>.Ñol5ÙÓQÔd[¤wh¡#aœl8ëϯ“1Op™ÊÌÉŒžUÉ힤ôãÄE)óÅé±¥9Ê>ì÷gÆ:¿®¼Z“\ÃmtÌ2—’6ç `/=ºò3^f7 5n§§ƒ¯%'udŽÃ@×µél-£]vK™‘¼ÈÒ|dsŽ3ï“ÿꯘ­I)måøEFiu=2Ë_Õ.¼5«x jp­æƒ*L°n˲–UgžpzŽxéáhNt¹£-{}ÿÖÇ-lW²©Ë(ï÷hxí5âˆüg£xoÅn,âÕ RIcÁ2ê@ä qìy5¦›oúíý}ÆY‡"¦¥Ðó/†v–¾!›S½Ô/%·´²µó]„¤I+•#8'9Îp:Vò¡ìéÊ£Ó—k[w±É Ñœ£×ô;i%hqxdó]\ FsŽ˜ÀíÇáô¯ÉͶ÷g°×$Uºs]O}xÑI8XäÂHÁE÷{}zVÔ©Ý$rT¨ÛhúÿáF™bþžÊ2¥‚’b3äepÄãò3ÎFÑœôc(ÉÇM??3¿/¨©ôþ¿¦ŽTÑ/l´ŸkÏX“f.B¼™Âª¼¶r1ÁÈ&½œ%5ÏúÒ<¬}[Õq‹³û´þ½WFðoм= ¾!¼-%Ô! ö{ØÆæÜU—9€1€0?PröŽû¿ëþËM%âÏUðE{fZà=Ý”Š±]I"10\¨P¸À%—È>œ ºí¨7ÿá·ØÞ“Š–¯]_çø—ƒZk$·¹”ê·r½ÄI$VÒ…»x–UBƒ#åb‚ÙäÆ+l3æœRî½Uÿ¯À+E*3³è÷ÛMºÿ•®}ÅãoßêyeÄpx^âKoµO:³Ý²†a& ÏÞ3‚xsÓh«TM­.|úª¡XüV׿Pø‘ñA_†Z힇 Ô®ü<¨"¹ŒŽ ˜UÉÎXàŒcMoˆ^ò’óü¿¦g†ƒNÒZ3â;]¡¾ðŒú¼±­‘Ñ$½çB­#È̬0yãiüÆz×—™U”*¸.‰~7g¹–Æ´zÝ¿ÂÇãk(t/èú­—•w¥êÇ÷“`ç.dù[ N3Üõ®|:“œ©Ëúþ¿«Ø­jEyß–çÂWÆÖÐȶ,žbù«‘,n§ŒãcpÈë·QR¼e¿õýXÊu=’‹Žß×{žm}a5µ¥­ÌŽí91Èsœ=»çé]TçË£}>­$•Òë¹ôÇìÿw¤iRjP\MµÕ™’7²Æø<:søjìjô%¸å/ÞFKúù¾)ðżWS\<©ÿH)Àb8é‘^u*¾ÅóEÙÿ[…H{H¤¾ïë¹ò‡Åÿ†:^¿¥6­¶4t×s—ðgì—¬ø›O¾Õ® ZC¹Ì ÃwNzÿ‘^¥jó…5Ë«ÓÈòéa¡:?3¶øû/ÚèÚõä'‰nM˜£,HÇMØÛëüë•f<ñ²ÜÕàÕ>›ŸMx‡àŸƒu- ôõÒ`ùâ![h8ÇCíÁL×ö‰s_S±Æ6³G‚|2ýž¼1àÏ\ø¯Æ&³ai0™##}¢P7npO!x ¤{W½‡ÄMP¿-åÓ²ó(ñ6­âÍS—z.•æ¤ ‘ìXTúîäpÇÓŸzóÛŒ&Ü^¿õ¯æz„Ô_nŸÖŸÖÇÉß õdÓ5û? ±\]I‰¦í‚1ìüë» ¹æ£sžºå\ÉyÐgÂ]CÒt}&Þ×Å)y¤­²ÚÙÂÁbŠ]‘ªù€¸–Ãd’5ÖFŸõýly³pæ]Œk=ËÃz†•aáko}žéäûUª\+Ymጛ7ddîËŒàW—‹¼-ô¶Ý¯æzxß¼ýtê|9¤ê ¿dšÎÙ›nÀ Sêß§²3_)VšO–çÔÒ›q½¬{—…®üxÖ7ºž£mu¥ZÇ(»³º™n”ƒÐ~RÄã=pG^œ®r…gM½‚Ƹʃåéo—™ð7Åí [ð/µÝèØAosçZióH^8¢‘CÇ·œcc¯8õ¯n*÷‹w³±â]+J'©ê^ ñHм'á¿Ïá½3M»k—Ô.oÝpdL*»B€8‹±ÆkÆQ”c­müýMpɹßúGj.þØd¹@c…>èT<`ô\ÿJùµ™ïª‰- }'Ã/s­hš}ôÂÒ »¨âÄ’)0F@<~G×5êå°U11‰Áæ§AËðþ¿¦{ž•ý·à-fuh%O'Ë«?ÝVÇ<}ÒG¸ëÛ߆\æùzþ~G×ù#u·å¯Èê|Qà»ýwŹÓïat7ú…€•°"bÔ绸Ïàz!N¿³û1·Îç%Y¹Qçëþ_æ}ýðRˆ–úˆ/n_KŽ(Òh¢ŠÕ]¤9]¢QœaN'ŒÑ[•W#Ï£Œœi*}¿À~ Ûx»À¾µ©ÚÃ6«£<,‰rˆ±ù b¿ ,ØÉQ’úW“Rs§Ío±îa%¼¶{t<Ëá”ÚÅ÷Š<6­’vº t³œ™£È,«Ç-‡l˜>ÜöaiFüËoø§ôÇŽ›' ooÆÿÕßå±Ñ|Tø¥«xfóÇ·±¾´Ö6öî>c"ÈJ3´†Hzu+Ïz’Xt­«jÞ¶³ü&¤ªóõK_KÜgìóàŸüQøi%•¼eôßíØ5+ù%^gtÝû¶ß3' ÔÁþUèaëÚ-¥¥µô<ºÔycË.OÔú6ÃXÑíIªyWpGlcpÑ´qÎ:¯<æ¸'U«µÓúÿ€v*RM&÷þ¯ú+â[‹/‰?°í$¸°ÚRXÝrJÿxóÜ ûgð¯SWUéý_oéœ8§{û%ªGŸüQýôoø>ü1…-u›{r÷–ݧ ’y‚=G¥qæRx*œ×¼?¯ëÔÃɈ‡+²—CòóQðýÖ›=Þ›¶×öò˜§ŠTÚQ†F1­o ”y£·F`èÊ/•ïØå.,ÜeL@ô8ç§zÕ'$d¤žÆQB1µ\ó»ßÒ´r°ía›z68^‡ÒžÀ~æ|F¸ðeåͲiréáãÉTv\¯ºÏá_Ršs½?ò>Š•IÆ è³ámVêÚÍl­% ÇVÉ#Ô©Ïã^•6êPSµ¬ÿ¯ò9§7õ=Rí¨î¤Y#@˜‘S¡#ŽFyëúWŸW)×JNºX«Siÿ_ðÇYq«²¶’vŠ?1Lˆ…ÀcÛ‘ëßZÖ¾­'dº LfŸ“< µ‡Ö|VËÌŸ`8Y€D“qvädçæ#ðô®ìü÷×ü‘Í]´¬ö?C~ \éþ Ða³¾—ìWªŸº‘[ƒŒÿ8ëú×¹Oø|ñ>z«µG?Ãúþ™Ò|Eðž¥c¤>¡¡]ÜGo»[•›`%r@,:çúûW-VéÇš®†¸{N\²Zl|ñ;㧬ü&ñ>‘}.µwªNû#†L3[Û’\‚Ç9>†£Ó¢šõ¹Ý‡¦á_EîÛ_ëúÿ/Ïï‡ÞÔ ñ7‡uýA.!ˆÌ¬¼|ÎNx鑨~>Õ®¨ÍYÞ<§ë]—u?†º…#Õš&öÈðÄHóììÔd›d[Žï-J¶s““[:–¬ù·1%:wZ/Éœ÷Ä߉ÇÅþñ~¡:D¬Û-ê̳™¦wí µ@ 0qɸ±õoGÝѲòü%ªEßCâË©^çO´ó#´j²ª§ßlœåסì3œþòÕ"úŸWM%{²øƒPÒ¬ä[X¼ø#ƒ`v˜¯*¬æõ’Ó[ü¿{¸ZiF;ôýNsÀwƒÁ>ñ'kUŽÚÕ,í_Þv ïÈázwë‚xÇ>†#–%w¹Š^Ú½–©n|­6¡®üL]e}2çPò#R ’ƒcرÉ'Øu»²Ì<\£Í²×±Å‹«(ÂMuÓúì~þÏ:ľ ¹´‹K± §ÝÛF%œœ±Â³(^GE,§uë¿(;Ƕߗèy§Q{ËÐúƒ_Öu¿hž&„Ûµž§´ci‰&B¥T€{ä9ÆqšùÌd àùw=\ ”*©Kkÿ^‡äfµ Óõûû[¤³¼ebGBNÜ ªÊy†=xâ¼(J÷iw):r¿õý\ð{}V]i¡±yb‚h¤Œ¬r~aéÅvTªÒ|ÚèxT°ÒuyaÒç¥|/–î®™ ÷p½Ü;I‚]§8糌ýx¬k>jR·õýHëÁ7J¯,´þ½MßI©øWÇ3,±HÑ-Ë"Ìùb 9ê^¿zD$“oúîpãð“§Q¥±îúG¬¥Üx¹.Éã$‚zún\p;ÓÄR‹IÅ|ÿàÑwv[uü?¯CÄZãPðæ½.—¦]rCFvžÝ={ÙVšsÙV:¤©=4ÿ‡.]xÇãWuÍëáî‘?‰4‰U¼ý?aa¼þø#ü=pÆâiª’…HÞ Âžs‚9YŸ|kµñeç5ŸøŸÁ·¾¸Ôn ¢Þ[b«èv¶0Oµãa%Föp{tüNÜBªçÏ$xŒ°€x][†Qמkºšä×ü¿3ž£æ^}7üŒ+« ŽI$“ßê*¤¹RiÜ猛mZÇ?4B6èAã“øgÚ´„®‹Øý¡Õ>húÌ¿n‰Ò÷i ±ì?—ƾ&–*šjÌú_eY-QÙhz=„:m›ÛHÐ\$dÒYD²ÈÌBÈÌHP1€8äô11zÙëÑJ[$´GÄ—Ž5¨´‰¼)¥öMLo68nIXã c#q>¤gñÅc^§@Î$c8 ?ª©+Ê*Oþ¡I]ùV~‡-?//|?ôMPëºL¡e¹S ŽXØpȇ¾äg­e_Ÿ%+wÿ2ðÒ§Y[¯õ·êyÿŒ®|?®êñÞh¾›G[h|›¸Òqå<à…i#Îe@ïÏj•?ßòÅÝ=};ößðèzƒT\¦öòû¿SÈüaãMv÷Hºøa£¼’i7Œ-ymîn1•\õáJô8$ó÷k®¥G‰¬©G£9œ:n£ê¿ïÿ_¼-¡ü3±ðW-4­'ÄöÒ´×HÓ"JL 0~Ìpƒh?ìçšìÅÁ{8ÊžËOŸSÎÃÖ”&î·×å·ôÏ¡< ?Ã9¤³ðí••Ù´]àPÈæÇÍÆO-œV 6ù¤ÿ¦g^vV±çõ–ñ‡ŠŒ°Ç—h¡T!”*ý?ý^g·q”½OMÐNmt¿Þ|ƒñ{—ç_™ÁxêÎóáçÅe6ð£Cmv“F £Ì¹¦~¼íZe|®*2üºVeÍ ¼ðÒú£ß.tõŸ[Cå›}&H’òv)U]û2~¥W¿ÞïYá¨Ê›•×Ãs£1©â×ÚÓòþ´ü ß Ãs«k-‥êÈG YNv¦ùâ½ø4©íªWù%x8Ô÷_Wòó±ÉüUðÆ­áŸ}>úYÌq\A²Ýˆê:úcè}«ÑÊ+B Wg®¬óóÎjö¿Ëïý Wö’ð÷ÿØXÙhÂÿÄgsÊJãaÏCß¹®\Ò1ö¼´ßC"qÚÿê|ñ‹ãÏŽ>2 {-q­a°µ”5ºÄªeRpÏøç¿å…)s(«šÊRJÉè|Ùv’ÛÉåÊKpB÷Ç<¥l¦”v彊ËlÓÅ"… §€jªjÖ¦tí½?¯ëÈÎ}Ì0Åz, ‘K™íqr¤~ÓB »—%CrBž:cü?ZüÕ»rŽ~g3ê´ÜO8,æÆ§Ð~uíå–¢çzøÅCÝÝÿ‘èðÁi¥ÝêØÆcÝ8lt=8ã·¥vû::³…J¦‹úßä|ÅqñŸCÑ5`¾Ž&³órWoú£ž3òŸO¯µzØZ´ªZ2Ó³Zúúœ˜ˆÔ¦¹—Í|_ñ.‘â-c@ñž‡(6Ú®•·Wž z{ôçW¤éb¥mž¿y×…¨ÞÚ8é÷lsžøÅâ Û˧j°Ç¬hos½2„ qÇó®ªkÛG’F òKT}7áO†?Äù4[ÿ øgÓLŠoc4ó¹FWPGO ì¥Nµ9®}Wõoë× Uz3‹åø»t>¯ðÏìÝà?êòêÐè‚qf{QrîþS© ¸$Œ¶<ñÏ^p:eÏ9_U¯üÉx‹»5¾Ÿ×Ïî?<þ3|]µñŒô»-:8­oSÛ-¤jK@Ô0%ºŸ—¶1øóQÄ:“‹kOëúýBtU:RKsØ|àÝ;â%¼–W³j¦ò ÛìvVP﹞S…]îß$Q"ä’Üszé©E9o¯õþF5+Êþþ3~ÍþðŽ·REk¨%ÔØ‘¯®D× NJ…*Š€ã ÙÎNÎpÎÊ7Óúõþ¾àÂbçv¿áÿ®çäߌôác­ÞÚBÛÒ9p§@8®jOÝJçeEË;”'Õç´·µ¶¿ŽáÑ@E˜Ç‚¼ñ’y#ñ¨QSo§¡iÊ Öy®\½¬ú|Æv)óBNcÜÊ+`r …lîÕÑj!M9¤Ú1¡”ÄP!Ì‹œ8%yÆ8ö¤£­ÙNܺhnYO5åå¼.ee'%Î9þ•2mlÊŒÚüïGñ±iuyse*YZ®c…neoï޽?@:R¥N.”¥Ÿ¦_±/†õÛë˜o™µ §»_dÀ¶Îœ9<ûv&¾Š‹…<-»ïùž%{Ê|ÇèŠ~i×ú}¦™¥¨4ØmÌV3­´märþ˹×=x¯&pÛnï¿sªž3‘ö]W©óÂ'‰>ésm2ÝØÝ‰,àÍkpAÁFÑž}±X¼Ck’¢ÑîtÆ•74éoŸ^ÇŒAb° :Œè¢ÈšæXÂ;§.ÙL:ôã¨Í`gFUe¢Øô1P|Š”»Kþ—»þÈ¿´oË®üAº¶„Õ%{[i\Ÿ-Ën ϱG½jð4e)-ÿ3ÏÌ17n’Vþ¼Ë?çºðGÄ›ÿߤ”—wg†Û“*ªFÀŸP®åI®­™ÂƒI5º±Ëü¸ñz_êš­ö~c¾ÖǶòÕ¨=¸ätãzVî½=#a[ '}<¿ËúüÏPÖ|C¥ø[Ær-ýź]Ï0;TfIãÆqËg?÷Ðõ¯6œï'÷ÿ_×êz«%F+d´þ¿¯ø·߆µ]n±]èê…âe†pK5Ðl¨Ùýã€OºÉ5Ìœ£WçußÌé¥к¾š|„>0x©¯>&ɨăKû-ÚH¦0ÀÆàõçÜúr1×,ä¬ç{}Ç«Ž›TaOÐæ¾"êö?õ«›ËI¢·¼Ó I+³¥¯Øc$ýúV”pÞź‰é{|ºlrb+F¼•«ú·õÜú3ÂCÂÚ×mu;­N /XM.+pfºE!¢A·{3cÔóø×]xN›}uùöô9×=nHÇe¥ü¿Äñ_†~/Ñ|­jî§¾h­.<Ñ u*H ¤¯¹ïøW¡98Ó/õëú_*s©ºþ¿«·‹koÄÖ›|;§iÖ ƒ¸’$ƒè0zvÀ®ŒXªûÓØå«Œt—,:u>ø‹¥j×’O©]:YæóÙÆyÎ{;犬vØòÅ- hTrm¶x‹X-´…¤P‡$Ó$qÓÅÈjå{\©y¤Û^E!*sÐûwúsúô©qKb”Ì(tø­eH`¤íVÆGùâ¢I§fmN)j˜5–s"ãÍÇñ î{ÿŸÐ½‰ö]OÔŸ \ZM¯.â+ÛkK–ˆYù“ÛŒŸåúWÌá2Úu"ôÕþ'ìâšþ¼Žê}ÏCÔn§²–6…Ø*&rÓÿë¦ð|²3u.ù¤qÞ,ñu½Å«³Æ­•pçƒÇlðükÍ• Fþö‡e*ñ––µük¤øòÌjV³ÇçHäH7ó¸œñþ}+|5Zê\½<´(ò¦yfŸ¬[ÛÙaÍ8Ššß+ñÀ'žŸ•{ Ni.½?¯ø'/gMëð›ÞµÔ<[â‹ê0È·ÒNÔ–~ãðëϵw`"ÝEÉýXãÅ$£®ßyú›ðŸáôÿ |A¢ñÜÛG4*$µ‡<¢.â[œ‘ŒÿµÒ½Š5}Ö¤ôÆE+=¿Cß>|]¼ðV{kcl—?Ú;2×vW ݳ¹@9ÁÁÀ í:‘vÐójQ“ZɯëúîÏý§¾*üJ½ñtM©-¼Ú}¼atëAKgÛ¼1Rã¹ëž§^5ZÎu–×gu 4aKÝ캳âK•¿Ô乺ÔmnMáÆì¾2}NxüóÍ>udR¥);œ»ˆ&”ywmmp§Y1Ûõ³VØÊËÞ,î¥'”P>là+$¬’FëÌU%>ztþT“±I»htš»»`)Ý;c nÎxÀç°ýy¦¢º ɤ®{/…ÍŽ«wŸ¨Û­¨¶?¹ŠÎÐ2÷±Þµ„yŸ4Nió/uì~ÊüŸCðÖ ØÇ5¯‡u ¢4‘\.å·v@ÏÞõ¿éÛ:²æÓD–§,¨%µ¾ÇÚ:'ÄmôÉ|ëópP·/nt#¦;ãùâ”§kØãTf’>;ø»â(åšßLk8,>Í+]]ÛCÀ•8$gio»Ô9ÅyX‰)Ú1ßõþ·>‹.Ãò{ÒÛ£Úþ_‘áƒK—Åþ×´hîÚ=X–Ú×K¡ä2!‘…Ù¼–ìäŠì«G–ŒiC½þíÇx:®£Û_¹ì§¾ø¶„eþx®í Ö"¹a"Ú½c¸õ=8¼ñ†—y«ÚO=ü‚Qat–ÈÑÜ8@8Á䌓ڸ T”ü¶ÿ/Ôì£ZP£ö>4ñǯXkþ#µÓ4ì}>ÂrÒ=´†V@À…VvÂô!wòŽ™Æ”©ÁRK›Óúþ®tUœµå…Òü½=”üu}ãjößS½Õu ¿´vÀa†1Á$œ¼sŠãÄ¿fΨÂsJß×õ苚_‰õÏ -ç¾’îíXi1û°[kr08ÎF3ߊãŒù¦ºØôyÝ($Þûù÷Ž.´ÿ|J†öú?"Êõà{£gvüÏŽN^3øÖÒQnKe«^¿Ò1¥Q©Óvì¾ZþGœÀ`mFá·Am Ìs¬7Upc PäàV´œÔ9zègR4”ùžÎën›W<ÆÓZÕìuû >ööãì,çÉŒ³Wô®Êîm_CÈ“i+ž¬šU÷ˆôÍfÚÆ Ä>HfW•8Âàõ=zsŸzî•8¸(½~ÿëúõ3Š”¥)-ÿåøy~hÂøC¡ÝI$ÖSÚùÏe~c–9bÞ­“×?—ç^öS*o Êïtyx¨Ú«hö‰^ ‡EÑln.!Ûo$žT ©"FAÇoáïÛµsfN$¬Èù¤ô>A×| qs}!¶¹Ç~‡Üqúýkæ®âíc×Q÷V¿×ù~†5¿…ZÝ>Ï6Ó€pJðôíSõéá)N~ê815#w¿oòØègð 麡â-I­ŸÎ‘ía¶ŒÈ²FÁr%ÿVn׎ÕÕS ìéó[Ãúþ®a O5NVöüO?E…æŠO¶3Cœ´®yíØšò}´—CÕT¢Ö’6î`¸‚;i Š( YByÍ‚ÊáA?ð™ã5¼$R±„ãvíÐûÓöK𠶯«ywP¼xoŸP¸)1æ#g…õãŸÂ½*8kÑsjÏúþ¾ãžUù%Ë3ìkhZ¯‹¿³4}nëQÕ­í%x®ndHA èpÈÀç¸ýx–&PæM^Ç\ Üc7§ésBø©âŸx#Ö'±Õü/§³¤6n²%J:Ù/j£R)M^æ0ÊîPvåýW9?xŠox¶ßE²¹V22ùŒ³íXC7œí€ëžkŽŒ)sÝßÏñþ¼YKž)tõÿ'ú<-ã&Ñþ4ø?ðÛJš6ƒIïX†D˜€]ä<“Œ¨<ÿZê¡YN³©{[EùZ8ºTÒ»×ü7©ö–¥ðçNøÉâ¹#táK{oäÏ`ñÇÁ?ëµÓ-,áÓ.´èÂYÞ3`BØ8'až•XŠ3ræ†ç.¿"qžÇç”>%ø›\×⹺ŠÃI¹¸ }r¨V ò¬còƒž03Ú¸ý¥¢¯n—³å|²Ñ­æGñ6óá‚4]SÃ6°%ÿˆ‘ƒ£Û>æyÛ÷€É?{žsÎXZ”ÝHsGu§õý~G] º=U»u>5[¿íÍRÎ) \„L¡2q–¶•s ú#Z•yÚæþ¿3éh<0Ó¤Ékv¶W%!ŒL$7•(Ä_/ ãž+ÓXXN<ÑÞßð?¯Öâx‹$¥µ÷ÚÚßþÿ‘yác,U¤ˆ×ZRÊ, xzïcÉ~ ã9<QÅi n¿¢üLê®xò]-[zìíýtÿ3ûá5׊]59游Ô,Û¾Ï04`aT| tÇ®1Œñ]Ñ£?Ýh—ù+õ¯èy˜©¹»Õ–¯m´³òßï_©êÞ ø[ö]B5K·!•XLÙÈ6Ó8ÂŽ=>˜ôÕg(¨ßîõðO2QJ^ëû΢?‡á¯mèöv‹¦^/-OÉ.áóã×}IÍVª|ÊOÏúÿ€cˆ‡=”wüË><{}SG»±º×0FÌ·P²®6cå dôèO\Ž•Ëˆ”uziòþ»v:p´å͵¯{yëýj|ÞžM:Ø, 'µ2%„A¤ž #è+‚»”¶é×S®(ÇÈáõO m•ŒV“I’AVQ‚ ð9úûqéç9]ûÍÁ4Žšt8ø8Üi¥®-Lƒ!ÑH ÃëZº‘ž‰˜Ó¦àÏ“N¸²“ì¦90¬@r8ë\Ó‹FœÉâ|DŽþÃH™w,ÖÛVIÄxe`23ÐãþÆ©NnhèvóÓ©O•7‡Xø‘ãK’f–Ý3$·eÎåAÎ õÈÆ;â½…YJÓìyN“U9còþ¿SÙ¹ôÇ>Õ2²ŸÈ©'ÍsÎü9ãŸü1½ÔÛÃw?h³ÕŽöÌÊbûF°\Àô>þõì`±i.Nš?ø+§SÌÅa[µEºþµGÞ>øÿ'ˆ4جu¨ •\9l2Œr=†}½kÐ…IÔVzµýlpÕ¢–±û¿¯ëÈöŸ|J¶mVþÛÄ—¶º5”Q­´,Udº`m©ÜÇ^ó^Œ}Ä¢µ±æÖ¤Ó×úò>u—âOŽto‰wº†ôŸùêmÛß6Õ6ÔF%°@œày¥€”¥‡P{›fuÎ[#æ/Ún;?êwº´Úmƽ-ÀU–ÚMÀ…ʆ•݆ÅÑ£;K¡Ã_Z´öÄß |,Ölí|Fú=燮,tØviúžöÑÌX‰$Æà̹ù¹ÈçéR+º¡:êÇ‹VµJu9â}·û<éxsC×ìãRºZ­ÁÒ$8Ýå³ç ÿk<ýO¥wÑ©'J<ÏT­þG›ŠjUœ£»×æzÿˆí ñžÚL·rDÆ@ÂF”œa‡9>‡=ãR‹vl˜MÅjcxŠÖKH4µ[UíÌbRÄȤ“óry8?Ï·•hÝY‡¨“Wz-O͉³ž­s©ßø™4Ù,mšUM«!s׫9 ŽõãNR„tØúÌJUd”¬ßãýzŸ ÏcàKXÖ¯ ¸¶‹KRѼ‰Ÿ2EÈP6¤îÇRN+ 2¼R[ì^&ƒ§')/wî7~þÓÐÙ­¶›ñH—T¶ŒˆáÕôì-ÜöV\"¨Èðú¤èUø½É[uªoÍ?Åßä|ü1u©¦­Íϧ¦ú|§ôÍCCñŒm¬ü>¿ÓµÛ T¶ùóa“Uc¹pÞÐTcžÿî×$éE+¦ií–ß×õó>~ñ‡ìf’élÂG #oî°¬8ì£>ÿáX)·e¿õçýzšórè|uâ;áS ™–xåfî1¹#sÀÆ^€Ö”jƤìÿ¯ ©N=ßáÕÏ„­f¹±ÔK}¹¶Yó´ÓÆ{~•„±*^á݅¯îúÿZ»q¯<âYáA• .L|óŽk’¥K£ºT)¸Y+U¾ªxŠ{«]ETʤ²KÀï}ùüáÅN<ŠLtŒ¬x×¼¬è—¾lZ°76òùŠ«##$p=zsúæ¶Ëqpƒ÷—õýZcðÒœy`ìŸoëúùÃí/ÅÄ—ºí­­Ö—iÁ%™ŽØwàneÏ=:ŽÕöt”b›Û¡ó˜¸ÉͨŸDø'RKø­'5;ˆ5m+J€Íbì»Ä×B¨ùrOLgžµÕ*Þ΋ŠV9¥Cžw‹ÓC§ðŒÚ÷Å_ˆ'ø“ý•s6•¡DÄH÷\m G͆i23÷@®5ES¤ÚêoN¬§QE¿ëúûÍŒþ!Ô•S ÏÉl}3Žž¿Î¶Œª'¹Á(Ó’øKzu•œ³F‹e… òòÁ¸n0:÷#w|Š|ÕŸÂ>Zw÷‘îšUÄún–ÚŽ%HRß}¼vqª‡ 6@ùvŒc=O¦k’pwqŸÜz0©%ÊîŠz¥.¹®Ë¨Ít¶6v߸´‰FN>`ÌHä×óè9÷2êræKfüíó<ü^!͹tK×î7­¼]>“ˆ5Ý9aŸÄQDÐÛ³0iñ’>T ˜ Ïnƒ<ã›6êstÛî'îÂ××s峨ë>-ñMÞ³yæêâÊåMâ^I·x2`uä–Áè8ÁôãZ0§'ùT”œšGë–•:_Ã_„—úŰÐ<3c,rKIJc,§÷ÛÙ@Uôäüݩ͉P“²³_®ßרV£l'Ñõ¿í{ýnû\œB¤»u<ÿ²ùW=sŽ ãJ¼ÓwØê«F-%ÛúêaüOøé¤xzÌhvÐǨê¶Ï-fÚáò89ž ¨=yq˜˜J<¶Óï;²Üµ©9ÊV·õý~æÿí±ñ—Ãúï…¼ðË–pé‘#®©®•„#vŽ3ÇL37_îÜ”iSsRŽÉhýLñS©Ôž½»[oø'æ¦>FÜà¹#?ZíIm´ö*øw\Ö<3ª-î‹©jz=úIû©lgxˆäƒÈ9Çôé[ѯR”›¦ís'8òO_ëúÓð=ãGý£¾.ØYÉgoã ™‘” ÐÆì ÑŠžzºe˜ÎSrq‹~qD}YAY6½èþ ý«>!éÚœW>&ºmJ‘ˆš hTg\ïÇÄB^ìÖž†Žœâ´nþ¬úcWý þZh:φVÏS×ZÖÚuô{DnÛw „úŽÜð1ÀµL%ß™5äõþ½t4Ž6«÷Riùìt><ÍãiìLjäxßǯËcº¢¼×ô¯]Ó~ã´®¾§NNÉI]žÉ/ˆlõíEm!M–äIH€ Üöì@ {òN7¥$¹Þ¦•ðsR¼?¯óþ»F¹|š„wß9†èÊÜíÀuéúé\˜ìÊ3~ïÃêo„ø/yëý[žIe¬ÞI«öe•ã,¯.và¨=@ß§ð5Ñìa§+µÿ_ŸõóG*Ö7þ´9]rïQ·Sq*HÎåÆ08óíšÞŒ}ÞUgý‘’ѧÂjóH,¼&5û×–&”€?>?ÕòRuêiÏeJ7yY“öQøgs%þ‡g§Ê¡âÓnuóS§û%@ã¸}8®¯©byù‹ëøx¶¢íòÓÕ¿áC|`û4Í/†âcV¥ê;¶p>EV'§ùíSõ9ÁsKá4Xú)Zç}®ë? Dº.±á}KIËå~ÕhѼŸ‰n9Îk‡Ø{I]ÛÅ/wúüNÿYOˆz¶Ÿie¥ÝÝË!@ÐÛÛ\Dq¼•œ3è+»+ËãõˆB{]_ïîcŠÇ¸Q—/oÐú"ÿÃ~#Õ´mkGµÒbð燭¥òt¨`ƒÊÀP¸=CŸ©5ön¦”¯ÿß/;9·¼m§õvx‹¼w¡x>ÂgÕRSU¼p4å}²$ €¦N>Rvþ_Z%[÷ŠÊê×ù²]5 Vz‘õD¯À_Ù $ÓÆ—?ˆcQvwO ”1È,HR(û¼zçšœeTãìä,%8;Õë¿Câ |´ñ^¡¬xÞÞ)bÐà“zùÀ%oº¹è0rzgî+žy»öÙ\ÖUम·þ¿¦y„Vm©ø·SºÕ¬%–ÛN%l¸ùWÚ~™ï×ð¯=Írü‰M~—üGÔ£¾ž(êY#´ù@-÷Ÿÿ‘S†N:ÿ_רªÎîÇ—‹ô/ûˆcVà ¸Î+¶Úñž‡aá«Ë¦K»;yîmå’Eb–àïfãxü=**7¤ŠQMÙžƒ¦êz´qÍk¨êÚÞ[DèñC,’Ë å³’vÀúƒYÊ7Õkrá6´Úß×õ©Úï‰#ò-ìï5+¹„jI… !çi*Õ:]‰sª–æÇ‡â½¾¹óuYïØÄŠÊ¾c`¶~ës€8ŸZ%]"Le}d}±¢x»ÃPx6óÃÚ΃¥Ï=ÃÄ-¯-¥q-¨%vƒ‚Œäv8¬– ´ÑšûzŠM§§c“¹¾Mе‹¸ÖX¡g,Sj1ÁÂÿ/|VÍû4ä½?¯¸Úš6~§‘|?–üxZÕî¯d7Ÿ2;Õq¸ðOûDäþä×&&6I +¦îVøK¡k>>ø i-¡¸½½¾IoK¦A8cÈãp$t“íèa¨4´Z#Š¥D¥vÏÙ?Ž>+ð/‡ü ¥øKÅZ4jßed‚ÊIȉ…e';TžÔw5ÉóÊÑø·;"êR¦ç¼^ž½ôûŒ¿ØÖâm?áß5}:'»{+¦e€NK…$+ÏAÀ$סŒ”¨Óç<ȸ΢‹vGCâïÚSÄÖ÷:F‘¦x~C{>ˆ²Í^cEæžr¬6ç àžH÷âœÝÚz%mÜ> $¹·¿ÏúýOMÑîÄ1W… ¢Œn?ç<Ñ·$’ÔSøÑøZ {ë™S+ Hª’A'ß'ÜVU¹£Rè»»³¥Öì-ôv‚Kv o!ÀÆ>SJÂG%©ÑR B¡ŠK˜|Ø”4§8c€Òµm¦gk«ð·Æ2ø[Y°Õ<­ÂÖàyÈÊ2Ê<¿ýzŸÂ~÷ÂÍb¯-ÏÒ]câ'ƒ5—Ñ.|-ªj–À^I [‚w\dsøqJññøÓ›”Z±ê`±“ä\ë_ÈàÄ6k¿ØVóI“î&2=?žïÒ¹aMA\¹ÎN¦»?ò"°Ñ$Õu=NÞ+/³[(#$$ÀçŒt=={×¥Kìè'ÌsV¡Ôj:¤aÝê̒XXè—W+ q’9Îz˜õçk½û7Rþ¿×ôºœVq“^ÇÜkšF‚„Q[YGaöhbb#Œgq8÷ÈéYS®â“ŠI~~g#¥írw5ï/ïæ³Iôö´:à’w±$˜ÏlrzVê{ÛŽ1‚^†>‹â[ËéÞÝìã’d'r†òÛÜà“ž;JÙͨÚá(Ûg¡«â BñžÖºö§körp°ÝD²# ò2§9ãëÏ*P’·oëúûý.Œçh»1øgÀ:Âë~"ð…¼ÖúF©@tÅ>q³ubJîÎBF܃õâ¶Ë[Š•+êÿ/7±¦:—:S¶ßÕÑô¥ÌW·’kRH–Q:™­¼•%›¨bð9—á^¼`”ím¶ÿ#Éç|š9üIø¢øãQ¸×­!Ô-ã‚Tfœ8Ù;*ü¨«Û;>ƒ¦k*j¬”tíý_Ы£Q“þ‘ñíñ{Qñji^µ¾Ž}7G`L*I_5x=sžÜ“ϧzé›Njmì(F0‹Š>Ò"°Ñ¾ è]]Õuˆc™íbFÜŠ“Ôƒh8‘מwÅÃÜPŽmýtþ¬raç']õKòÔùâçˆ4Í.ÙZÎ º€C.ÜÈä3 py$öÅ|ÊÃ7'ôþ´>‡ÚòA9ÝZÞ\HL»Xºüì½A?¨ÿ>µèÆIhrÚã-l&ƒ¼eÊéÅ;®€´GQ YÞ-ãè«“ò“Ÿ¯Ó]«KS¿¶’ánMíŒÍe+'“(Y,˜éœwéÈ®_iȹN—K™óµ)¼9­ézµœ‹{¡/•p€¬€˜7änàZ¸VŠ’æÕÕ¢ù\c£=OUñ 7SêOeec¥Á¨ÉóˆàcNÀqÐgz})ON+–;_×ü1TèÔÒRzíýiý|Ì {¨¬ÖWòUñ-̲¨EÁ üØãŸsíÉ®nw-"t SÜþÃáïˆz£kqk-Öœ|Á6 r  ‘ü=Hƺ+Òr§~¦4«Zi-¶þ´/_ü9ƒA𞦶T#ãÊÙÛ=>lmÛ¿Qœ#Í¿¯ëïèZ›±ì‹ðŸPºøµák˜o¥ÑßÎ{„™!$FòŽŒqÆ8èNs_G€¤éÒ”¼Ÿ©âc*'-UõGÓ?µçˆ­-žÕ”¥û­þ¥ÊqÙ™ÎïLñd“ËÌÀRØío,œŽãúw­c$Ç—CÑ•]lÄ®— á“?s’I—\g¹ç;7®À¬ådOmgß—ªÛJ¯å“»"öV^Ÿ—#ëYªÜ³÷t—oë_AÞÑåû?ÖÇšx»R>Š-WOð?ˆ¹m©éþ´ŸO¶â´²´ºVTn!Âg'g€;â¸ëçXyÍÛªôùlãw¯_øçÇÆ/ ø×BñCÅã/ßèé嬖ë$gËd'r=Ac+%j3ƒŒ^§]jRº“Øðù®aËG¸‰3+5¾rzsùý+µÇ“¯âr9ó½‹Ëúô2í­o–G’èE»!]¤d¯F}~kJ•n½ßêÄBŠŽèϺ՞6öiåÂÇîõ*x¦3ž8÷­!t„ãt6ÒÝYŠP²jnŒ2“}½9ÎO½dãRÓ”'¢þ¿áÎÛÃÚÓé¶©¬k—M=»3%¥”(¹R>v#î¨'¯\Ö5pÑ”ùR±¥CTÛ“5uOGq@Òîìî‡Ít÷®%Ëg¨QêyÎKP°t¡fÝÁâg+¨Fß×Èó=SUÖuoÞß_=û#b8ÉTcXÆëØf»!J4ãËc™×”åy3ìÙ¢mWLÐ5Ym-ÚåÌìʬâ0¿'!O®qíɨÄ7¥º~¡F -O¾>A{¦x‹Kg™-Ø­š:–ÉÈç^œ)Bt¹ã¿õó8ªÆP¬­÷ÿ_×SOà“k£xþh ý‰6WRÛ-›)†xÌ„ t8==ÈÀÇ©)áüµZkærâgìçnÍ3Ì¿k\x[â-߈.4½FÖòâénašg2ÛMÅÁVPÛÎNyîlj†¥œ÷ëøµIÊqŒßkiåßïÓæy7ÆŸÜøKø{¥ÚÄÑÛE£Æ$…fWÃmùˆ8(à€EgN“öóòÐÞ¼Ô(Aunÿ×âzBøŸ…útZAYíÛíšœI™j3ç rA@là‚Ø⸫Úm­¿¯ëó=+ºä]múÿ_ðlx¾¥¬xÃÞñ%׌ÅĤÚCÃám6ÖB.~ÖØcrÙ=9$ çt]Dý›·õتø˜SIJ:õÿùŸJ„äåOÝ"½Y$’±áÓ—N¢Å6ÉÓ.[†¹çw¥ÎªQгHúáÏ«ÿjz~¡rÃÈ0HÓ`Èÿ9ÁëíXÇÉ'³WEµÍmúá¿„ž?Ð. Öá”]ˆYþÏ/1ƒ“éŽyü«™,M:ŽT¢Úü ç£*>Êm|˾&×5;?WК7°¾hLsK!©#;ŽHÿ9®Øâ}¥J{ÿ_–ç ÃòTS‘ð—„üñCñn£ –¯ÚHJpOËžzûÞª‹Êã#)Ѥêó^Ö>CÕþ7|SÑu=BÆ-MíRݶɸí•N?ˆütÿ=…ÖQ)ßV´õ=GÀߵNjm®l Õešeh‚ÜN±€8êsÔäŸÂ…ºê„âž¶Ðý&ðÄ øëGµ¹ó–pv•CÁCÀ$ää ñØqS ·O¿õ÷ÿÁ"­¶7o¼M¦Ùê2ØÉ{¶¹L2’¤ Æ;€Ç~kH.['þ_×õ¡0ƒI_sMuëH ¸“b°uR¥@óvQùÖQŒÑÿNÿר:vgWáoGvâê[¤¶go-xËÿQŸ§á]Ø)Ù­N|e½ /ˆ_ u¯é:íׂvÇ–³1‹ÀlîÏøùÊЄ4ŒvÓî>š“æÖnÿ×õýXú³Nñ>‰zlþÔaÓ 6b‘b,äýìÏ}‡¥qÍòÅr­¯ø$K 8ÍÙü¿à1-§ˆÞK û;][Jcɼ åü½IïÀãò®JUê)rÅtU5{êx/Œ¿g߀ö.¡à=>{S"™M¾è1ß îõçÖ½\-v¾Ûžÿü?ßcR>ìWÏCÎ5oاà_ŒôvŸÀ—š®~êXIæ<¤dw#·õ®Ê˜ºð’TåÌ­³G?³Š¼…½?¯ò> ø›û,ëß ¼S¦mÿ‰ÖŒnÑcº‹%$ ÿ?tòrÆ;W§—æ.¤ùf¬ÿ3,^0‡57txߌ4ytMN Xí®í'dÛ9uÁyy#¯@;ãô®è;úmI/3˜Ki/­nì"œÁtÍ¢ FÐÄýÒ@H>¸íšÖÍY¯ëæf­ª×ȇP’ÉŒw2Ki,,RhÝŽää@ü¿•k}¶1nÖ±ÞFn7Å!2Î[š·±1i½â~†~κN½s è6ö¶¶¡vD±ås°îùÆæsŸ\óÚªœ\ª%ëÿ¹EB“‘÷×ÿÿ>x²Ýiòé¾{õûD~lw!a8¼)lw9Æzô¯g Ré{+½{÷õû3WÚ~ñ%/ëþ æ_´‡‡ÏÃŒžñ†åòl/š B læ(›ÖO›`ýÓõù¿#'HWq¶Ïªèÿá1Š50éß{¯ºßæ{oíQà}Gƺ'„|_ciªMq¤° †5…Wlža#ÂÇÛq=Wž 7N¬¢öü4×õ©¦Zj?Ÿš>Mø¥à‹˜õ†ksiwRé1Á.åUKH\ä•#žxéïÉFIV©ee¿ùž£÷èÓR{iþBøâ…džüqý•¨]%ô3Ì-c…Wv` ó1žNПJÊ”³]:îiY·Q®Ûzÿ‘äÿtÿ‚þ>øõ¬Ýê¥ÆáMWRUÒÅ”H¬Ì6+¹ÝÂ#0r§¨éX`ð²æ•8ÊÝW^ú|Œ±X„©Ær\ÝËC›ñwì©…ÅãxWZ¾Õ´“½íKǽø v¸œÜ€sÔg·Ÿ<~"»R?ÖŸqéÓÀP¬¯J_'¯õsæ)ü1&‰suauŠêÝÈÃãŒÿõù¯Fž!TŠiuL;¥'^±[–ùR.“º>Øõ?N¾þÕœ”7 4tI"• e'÷ƒû¾â±æ²ŠWy–aºNb1¯Þâ*£5t5ô6t_ ÛÝ•YdkpOËrOôÁ3®ïttRÃßIz€µý>éÄWêù¨ÿëqXÕÅÁ«5cZxIÅèô=žÃáÆŸ©éæ8®³õHãù9;Y· ÁíúŠòëãeOet{0œw³>™ýœî.lîWOÕ]¢®`ù‡”GL:ŸA×NzÔU\íJ=Uûþ€JOØò4ô?N4[è-- iîìÑ:º‡“cž9ޏÏéÒ½l=oe£z7Š¡Îï©ò¿Å¤mc_»¾Ó&IÜ`\'Îýãþy®Z5iª²œžÿ×õc¢Tª:j1Ýly…¾üEñ}ޝ}áëdµ³IZÞ9®¥òþeÁÜ£ŸR?ý£'*pRŒy®q¹©Tq––þ¿¯SÌ4Ÿƒ_ 属}Gºv¡urCÏus—–F nbÙ'õúT8¥¢Z¹I=Ï1ñ'ìßá8t×ÔüóÉ’\A/Ü„Èå‡nOøV1çWþ¿áކàÚL‡áΕ­èº¿Øluì×· ØX:îƒ#YÔ¦šR.OCß|Yuc-ž‘£Ëwž¤× ¹Yw1Ç\c¿¿««Ÿ•ZÆ1¥uÍý_Ö§›ø×Áž4–{M_Ã>"°Òõ x0!¸·ßŸ™ORNOßžP¤Óm³Wˆ÷T¯ëõ<ûÁ'ý¡<â{Ÿi‡‹¼;y|>É, "‚7ÉÁ,pW§p~œ×eÙö9ª·;§Ôýð‡‹fÖî®ln¯#žòÙUž;F}ªHÎÜž¸™"¼lÚ꜖«úþ¿ÓÊëû:œ„%ñœžÕ–ÿÆ> 3\·üyZ$;c„ê¬ ÉÉïšñ£uîoý_ðjS·½/ë§ù#ìÿëð’xzËY‚x%PC;¥Êù’ŒôP `zsŒzf¸§‡P“æÓÓÈŠÕ#Íxž«w h!ÒdˆÝH³ìÛ6W‚U6®GoÃÓ½{¸?a:*7÷¿àÿ_ð"U*R©ÍÐñ‹}'Qðš]Eý©ˆHù6‘ŽÜ÷ç=*ã•IÂËTßõÿ ÿõiF,­÷žWã}~îîÕìuí=¤°í>fNÌt<œ¨ë8Í©&´}?¯ëî4«Fœ¢|yãþ]3PÖ4Äž÷^·LB>i¤ÉIŒuÃÉçwN¸ûHJ-ó.¶~—ÿ†>Rq·»ÛM»_úGÈ)§K¬—,ñAsËG$3¨Iq3»ø°Aàztï]j1V±Î¤îû–üMáäÔô¨µcl°jIû–’@?~pÄqƒ€Éÿëç%i]FI®^Ç3¡x\ùˆ°[ÜÌè1aµc眓Óþµ^Ù»+¨(«Ûúÿ€~ì~Ì?t=s¾×u?jÐM§Ê‹ŠÙEåO$kÀ`à³ ·cŠ÷^t%εÓóôÓo¯m¼M©øOQ¶_ìÙàa Í›yaPÎÂ@îg% ÒR[£§N{èÏþ1x/Âþ0±ñn¨Å>Qu¦Þ ‡—"g˜¤ Îs“Àà°µ´’[-ì×uÜè§h·MÞÍ]y3Ð¥×W[ðÇÂHbÚúY·&bÓó$@zíÝÁþsŠæ¯êÉO³µw{£Æ>0øZ Oâ}…Å«Gý› ééåÉ$Ÿ,¨ÊrO\íÂþ]z×— Jî[7oÈõáf •îµô{è>Ñ<_ãO ^Ck©y–ÍQŠÉHÈ뤎ƒçÒ¹¥Nƒ”^¨íç„+.mž‡À^({ Ç:¼|—bÎñ’7™K äp}NÕ¶mÁK©ÅˆJz¶?.ì>#øOJ·Ðíuë»øô‘%ÅË °Ã.ÜîWãæ$çøñXã}ª­.^Ÿæi…”(ÞÚØùïöŽøu¥è7ÖzƳgio%Üå.¥HðÊNHv `’Hô8oc^4°ò§;AÚ纪Bp¼õKCãm{D{+È,´Ë¸2<Äva†±#§×ÚºaQ½dµ8kQIòÇb =ö·*·0-Ä`° ·©$WxŽ*KsÓ,ü}©BuÓ‰‚òJSzqïßò®YÕör´ºtðüñ¼wG#¨xKZ´¸’Xµ.-°_j¾`ôÇáúV«££F50SRºgQánHÂ)•[p”òG¶Jué)lE–V–çßÿõ×B¶Ôm¼5‰®b’Cym7…^7N9þªÅÒ…;:‘¼Z׺þ½McZ¤¢ãr»é}eÒþ7|»ñ–—€õ"g”E%é±Uû;gàÜõ´(åÕåìÓ³õ±ÅUãèÚNétÐöM[Rømuv,lµ fîSòí¶Y<²y8$dtç“üªêáðÑvŒÚkúésˆÄ(ÝÅ[úó>y¸´¸½ñ.¹káÿø‘–7•a[ñ!Q–*Ý~ý«Ä§ B•ó[ËTzÒœ\•ôÛþê¿ üsã+F³Ó°-§µ¶š7’6Šåæß)ïÛ¿µ}- tíË(Y­­ýv<ŠøssSžì~;øý@ÿ®1ÿè¡S„ÿ?ÐÞ·ÂoèÿòÔë„Ö±Än¾f´·^Ÿ¡SÁ?ò_úäô%®z»"ª|,¥ñþF=3þ¾£ÿÙ+uü8üÌiü?3Úôùè?õÔÿ*êÄü_%ù£%Ô»©ÿÇ·ÿai?ô®—¡ÑïüŠß?äwÖ¿ß?ÌQÿ.ÙÓ_yzþ§·üDÿ’e{ÿ^GÿFÇXVÞ_×Bp}ùƒñ¿þFmþ¼òJã¥ü7ýw:ëÿú?ö\ÿ[ÿl—ù%pÔÛïüÙÖÿо_’>ÖÑ?Öê_õí?þ‡5NŸêq?_ÑCñoþA?õêßÈR§ñW§¡óÞ¡ÿÐ×”_úUÃàdTø™§Ç‹ÿ×ä¿É+ë²ÿá/ð¯ÍŸ3_øÓõýño‰?äg¿ÿ¯ûý×sêqSÚŸ¡Ðk?ñó¥ÿ×#ÿ¢ä­jn½ ×ðþfƒ¿ä!uÿ]WÿCZ0ÿ+ñ´¿ä#àŸúãþ‚+é±ùŸ?Sá×SÞ¾‹ò>ñOü‡~%ÿ×­çþŽJëû›ù~g¥_â_×CÖ| ÿ$ƒá‡ý23^-÷¸ÿ…ÿé"Ãÿ»OÕ~lÄñ¿ü„¼Qÿ\£ÿÑMX½—©îa~)‡õgÃÞÿ’»ÿ]ÿBZâÁüsþº•Šþ:õý”þ+ÿÉXñ·ý}AYeÿÀþ»³ wĽäÜߨçþMÿÂÿõâ¿ÈÕËýãîüŽù‡?Ìøóöÿ‘w[ÿ¯qüÅscÿ‹OÔïÁüôÿ#äMGý^ÿ`‘ÿ ŠâŸñ%ê¿3ª_þº iÿ!Û_úê¿ÈQÿ.¾DËãé¿ ÿÈþÙÿí1K1þÏõ=l»àû3‹þ?µ?úêÿú®_³òýN¶þg3¢ýËŸúéþ„k®[£l~€~Îñãgÿ_Iÿ¡WJþßùµ·?È÷¯ù¼OÿÿÐÞ¾iüqõýíCø çùDì´_ù\ÿ×y¿ô1^¥‚?â‘åÖø¿®Ììüÿ 7ýÓüš½z;?Ÿä.[|׿gøþ>lëçúWKøÌ*ï/ë©ÿÙSepia-0.992/sepia.texi000644 000765 000765 00000103362 11657033103 015064 0ustar00seanoseano000000 000000 \input texinfo @c -*-texinfo-*- @c %**start of header @setfilename sepia.info @settitle SEPIA: Simple Emacs Perl Integration @dircategory Emacs @direntry * Sepia: (sepia). Simple Emacs Perl Integration. @end direntry @copying Copyright @copyright{} 2005-2010 Sean O'Rourke. All rights reserved, some wrongs reversed. This module is distributed under the same terms as Perl. @end copying @c %**end of header @titlepage @title Sepia: Simple Emacs Perl Integration @author Sean O'Rourke @end titlepage @macro kbinding{key,cmd} @item \key\ `\cmd\' @kindex \key\ @end macro @macro fitem{name} @item \name\ @findex \name\ @end macro @macro xxx{stuff} @b{XXX: \stuff\} @end macro @node Top, Introduction, (dir), (dir) @ifinfo @top SEPIA @end ifinfo @ifhtml @image{Sepia,,,,jpg} @end ifhtml Sepia is a set of Perl development tools for Emacs supporting code navigation and interactive evaluation. @menu * Introduction:: * Editing:: * Interactive Perl:: * CPAN browsing:: * Customization:: * Internals:: * FAQ:: * Credits:: * Function Index:: * Variable Index:: @end menu @c ============================================================ @node Introduction, Editing, Top, Top @chapter Introduction Sepia is a set of tools for Perl development in Emacs. Its goal is to extend CPerl mode to support fast code navigation and interactive development. It is inspired by Emacs' current support for a number of other languages, including Lisp, Python, and Emacs Lisp. @menu * Getting Started:: * Philosophy:: * Related Work:: @end menu @node Getting Started, Philosophy, Introduction, Introduction @section Getting Started To install Sepia, its Emacs Lisp files must be in Emacs' @code{load-path}, and the @file{lib} directory must be in Perl's @code{@@INC}. Assuming that Sepia has been unpacked in @file{~/sepia}, it can be installed by adding the following lines to @file{~/.emacs}: @example (add-to-list 'load-path "~/sepia") (setq sepia-perl5lib (list (expand-file-name "~/sepia/lib"))) (defalias 'perl-mode 'sepia-mode) (require 'sepia) @end example Then to bring up the interactive Perl prompt, type @kbd{M-x sepia-repl}. @node Philosophy, Related Work, Getting Started, Introduction @section Philosophy A development environment should support three activities: code spelunking, interaction, and customization. Emacs as an environment for developing Emacs Lisp thoroughly supports all of them: It has commands to visit individual functions' code and documentation, commands to evaluate or step through expressions, and an architecture that encourages customization in Emacs Lisp. As an environment for Perl, however, it is lacking: there is limited interactivity with the Perl debugger, and reasonable documentation browsing, but no support for navigating, editing, and re-evaluating code. Sepia attempts to remedy the situation. Modern IDEs also support these three activities, but do so awkwardly. Rather than having functions to visit definitions (@kbd{find-function}) and search for functions (@kbd{apropos}), they clutter the screen with class and file trees. Rather than supporting interactive evaluation of small pieces of code, they perform background semantic checking on whole projects and highlight errors. Rather than allowing minor customizations to grow organically into features, they support limited configuration files and baroque plug-in APIs@footnote{In my brief experience with Visual Studio, I was struck by the fact that I saw several toolbars, a couple of navigation windows, and a tiny view of the actual code. Sometimes a tooltip would obscure part of that tiny window.}. Sepia tries to adhere to the apparent Emacs philosophy that rich semantic information should be unobtrusive, and that the best way to build working code is to start by experimenting with small pieces. Language support packages for Emacs vary widely in the degree to which they make use of or replace existing Emacs features. Minimal modes provide keyword-based syntax highlighting and an unadorned comint buffer as an interpreter. Others provide their own specialized equivalents of comint, eldoc, completion, and other Emacs features. Sepia takes a third approach by trying to do as much as possible with existing Emacs features, even when they are not optimal for Perl. For example, it uses comint to communicate with the subprocess, eldoc to display documentation, and grep to list source locations. This approach has three advantages: First, it maximizes the number of features that can be supported with limited development time. Second, it respects users' settings. A seasoned Emacs user may have changed hundreds of settings, so a mode that reimplements features will have to support equivalent settings, and will force the user to re-specify them. Finally, this approach respects decades of development spent, as Neal Stephenson put it, ``focused with maniacal intensity on the deceptively simple-seeming problem of editing text.'' Many non-obvious choices go into making a polished interface, and while a reimplementation gets rid of accumulated cruft, it must rediscover these hidden trade-offs. Anyways, I hope you enjoy using Sepia. Its development style is strange for someone used Perl's typical mix of one-liners and edit-save-run, but once you are accustomed to it, you may find it very effective. @node Related Work, , Philosophy, Introduction @comment node-name, next, previous, up @section Related Work A number of more-or-less related Emacs extensions are currently under development. Here is a list of the ones I have heard about, along with my brief impression of how they differ from Sepia. Since I use none of them regularly, these impressions should be taken with a grain of salt. @table @cite @item Emacs::PDE PDE is similar to Sepia in offering an interactive Lisp-like development environment interfacing with a long-running Perl process. It seems more ambitious, and therefore a bit more invasive. @url{http://search.cpan.org/dist/Emacs-PDE/} @item Devel::PerlySense Devel::PerlySense offers a more Eclipse-like development environment, with offline code analysis via @acronym{PPI}. @url{http://search.cpan.org/dist/Devel-PerlySense/} @item Emacs::EPL Emacs::EPL is a low-level IPC interface between Emacs and Perl. Sepia was originally based on Emacs::EPL, but the current @command{comint}-based implementation proved more maintainable. @url{http://search.cpan.org/dist/Emacs-EPL/} @item Stylish Stylish is a similar effort with a very different implementation philosophy, requiring maximal rather than minimal dependencies in both Perl and Emacs, and reimplementing @command{comint} in Emacs. @url{http://github.com/jrockway/stylish.git} @end table @c ============================================================ @node Editing, Interactive Perl, Introduction, Top @chapter Editing @findex sepia-mode Sepia's first contribution is a set of commands to explore a Perl codebase. These include commands to browse and display documentation, to find function definitions, and to query a cross-reference database of function and variable uses. Sepia also provides intelligent symbol completion. @menu * Completion:: * Navigation:: * Documentation:: * Other commands:: @end menu @node Completion, Navigation, Editing, Editing @section Completion Sepia implements partial-word completion that communicates with the inferior Perl process. For example, @samp{%S:X:v_u} completes to @samp{%Sepia::Xref::var_use} when Sepia is loaded. This completion only operates on functions and global variables known to the Perl interpreter, so it works best when code and interpreter are in sync. More precisely, completion examines the text before point and tries each of the following in turn, using the first successful approach: @enumerate @item If the text looks like a method call (e.g. @samp{$object->f} or @samp{Class->f}), complete on methods. @item If it looks like a variable (e.g. @samp{%hash} or @samp{$scalar}), complete first on lexical, then global variables. @item Complete on modules and functions. @item Otherwise, complete on Perl built-in operators. @end enumerate For each of the first three cases, completions candidates are first generated by splitting the text on characters @code{[:_]} and matching the resulting word parts. For example, @samp{X:a_b} will complete to all symbols matching @samp{^X[^:]*:+a[^:_]*_b} such as @samp{Xref::a_bug} and @samp{X::always_bites_me}. If the module parts of the input match a module exactly and completions exist, they are not expanded. For example, @samp{X:a} will expand only to @samp{X::aa} when @samp{X::aa} and @samp{Xx::aa} exist. If no matches result, the text is treated as an acronym. For example, @samp{dry} will complete to @samp{dont_repeat_yourself}. @emph{Note: partial-word completion is not currently supported for lexicals.} Completion is performed by the following commands: @table @kbd @item M-x sepia-complete-symbol @findex sepia-complete-symbol Complete the symbol before point as described above. This is always case-sensitive, independent of @code{completion-ignore-case}. @item TAB @itemx M-x sepia-indent-or-complete @findex sepia-indent-or-complete First try to reindent the current line. If its indentation does not change, then try to expand an abbrev at point (unless @code{sepia-indent-expand-abbrev} is @code{nil}). If no abbrev is expanded, then call @code{sepia-complete-symbol}. @end table @node Navigation, Documentation, Completion, Editing @section Navigation Sepia provides several commands for navigating program source. All of them rely on information from the inferior Perl process, so it is important both that it be running, and that its internal representation of the program match the program source. The commands marked (Xref) below also rely on a cross-reference database, which must be explicitly rebuilt by calling @code{xref-rebuild} when the program changes. There are two basic kinds of navigation commands. The first kind jumps directly to the first matching location when possible, prompting only if no such location is found. These commands find only a single location. @c direct-jump commands @table @kbd @item M-. M-. @itemx M-x sepia-dwim @findex sepia-dwim Guess what kind of identifier is at point, and try to do the right thing: for a function, find its definition(s); for a variable, find its uses; for a module, view its documentation; otherwise, prompt for the name of a function to visit. @code{sepia-dwim} automatically goes to the first function definition or variable use found. @item M-. d @itemx M-x sepia-location @findex sepia-location Jump directly to the definition of the function at point, prompting if point is not on a known function. If multiple definitions are found, choose one arbitrarily. This function is similar to @code{sepia-defs}, and the two should probably be merged. @item M-. j @itemx M-x sepia-jump-to-symbol @findex sepia-jump-to-symbol Navigate to a function using ``ido'' interactive completion. Within interactive completion, press @key{:} to descend into a package, @key{DEL} to ascend to a parent package, and @key{RET} to go to the currently-selected function. @item M-. l @itemx M-x sepia-pod-follow-link-at-point @findex sepia-pod-follow-link-at-point Follow the POD link (@code{L<...>}) at point, or prompt for a link if there is none. Go to the appropriate location in the document source or, with a prefix argument, in the rendered documentation. This can be especially useful when writing links in your own documentation. @end table The second kind of navigation commands always prompts the user -- though usually with a sensible default value -- and finds multiple locations. When called with a prefix argument, these commands present their results in a @code{grep-mode} buffer. When called @emph{without} a prefix argument, they place all results on the found-location ring and jump directly to the first. The remaining locations can be cycled through by calls to @code{sepia-next}. @c prompt-and-go commands @table @kbd @item M-. f @var{name} @key{RET} @itemx M-x sepia-defs @findex sepia-defs Find definition(s) of function @var{name}. @item M-. m @var{name} @key{RET} @itemx M-x sepia-module-find @var{name} @key{RET} @findex sepia-module-find Find the source of module @var{name}. @item M-. a @var{regexp} @key{RET} @itemx M-x sepia-apropos @var{regexp} @key{RET} @findex sepia-apropos Find definitions of all functions whose names match @var{regexp}. @item M-x sepia-apropos-module @var{regexp} @key{RET} @findex sepia-apropos-module Find all installed modules matching @var{regexp}. This function may be slow the first time it is called, because it has to build a list of installed modules. @item M-. c @var{name} @key{RET} @itemx M-x sepia-callers @var{name} @key{RET} @findex sepia-callers (Xref) Find calls to function @var{name}. @item M-. C @var{name} @key{RET} @itemx M-x sepia-callees @var{name} @key{RET} @findex sepia-callees (Xref) Find the definitions of functions called by @var{name}. @item M-. v @var{name} @key{RET} @itemx M-x sepia-var-uses @var{name} @key{RET} @findex sepia-var-uses (Xref) Find uses of the global variable @var{name}. @item M-. V @var{name} @key{RET} @itemx M-x sepia-var-defs @var{name} @key{RET} @findex sepia-var-defs (Xref) Find definitions of global variable @var{name}. Since Perl's global variables are not declared, this is rarely useful @c XXX: broken, so don't mention it. @c @item M-. A @var{regexp} @key{RET} @c @itemx M-x sepia-var-apropos @c @findex sepia-var-apropos @c Find definitions of all variables whose names match @var{regexp}. Since @c this function does not handle lexical variables, and since Perl's global @c variables are not declared, this is rarely useful. @end table Finally, there are several other navigation-related commands that do not fit into either of the above categories. @c other commands @table @kbd @item M-, @itemx M-x sepia-next @findex sepia-next Cycle through the definitions found by the previous @key{M-.} search. @item M-. r @itemx M-x sepia-rebuild @findex sepia-rebuild Rebuild the cross-reference database by walking the op-tree and stashes. @item M-. t @itemx M-x find-tag Execute the @code{find-tag} command typically bound to @key{M-.}. @end table @node Documentation, Other commands, Navigation, Editing @section Documentation Sepia can be used to browse installed modules' documentation, to format and display the current buffer's POD, and to browse the list of modules installed on the system. @table @kbd @item M-. p @var{name} @key{RET} @itemx M-x sepia-perldoc-this @findex sepia-perldoc-this View documentation for module @var{name} or Perl manual page @var{name}. @item C-c C-d @itemx M-x sepia-view-pod @findex sepia-view-pod Format and view the current buffer's documentation. @item sepia-package-list @findex sepia-package-list Browse a tree of installed packages. This lists only the top-level packages from installed distributions, so if package @code{My::Stuff} also provides @code{My::Stuff::Details}, it will not be displayed. When Emacs-w3m is available, each module is linked to its documentation. @item sepia-module-list @findex sepia-module-list Browse a tree of both top-level and internal packages, like @code{sepia-package-list}. @end table @findex sepia-install-eldoc Sepia also integrates with eldoc (at least in GNU Emacs >= 22). Documentation for Perl operators and control structures is taken from CPerl mode. Sepia will also display documentation for user-defined functions if their POD is formatted in the standard way, with functions described in a ``=head2'' or ``=item'' entry. To load user documentation, visit the relevant file and type @kbd{M-x sepia-doc-update}. If @code{Module::CoreList} is available, Sepia's eldoc function will also display the first version of Perl with which a module was shipped. This is intended to give the programmer a sense of when he is creating external dependencies. @node Other commands, , Documentation, Editing @section Other commands @table @kbd @item M-x sepia-rename-lexical @findex sepia-rename-lexical Rename a variable in the function at point, querying for each replacement when called with a prefix argument. Currently, this is only a thin wrapper around @code{query-replace}. @end table @c ============================================================ @node Interactive Perl, CPAN browsing, Editing, Top @chapter Interactive Perl @findex sepia-repl Sepia's second main contribution is an interactive interface (REPL) to an inferior Perl process. The interface is based on GUD mode, and inherits many of its bindings; this chapter discusses only the Sepia extensions. To start or switch to the repl, type @kbd{M-x sepia-repl}. As in Sepia mode, @key{TAB} in the REPL performs partial-word completion with @code{sepia-complete-symbol}. @c == REPL behavior == @c - $_/@_ @c - RET & eval/newline @c - eval context Sepia also provides a number of other ways to evaluate pieces of code in Perl, and commands to process buffer text using the inferior process. Finally, Sepia comes with the @kbd{sepl} program, a standalone REPL that can be run from the command-line, and provides many features of the Emacs-based REPL. @menu * Shortcuts:: * Debugger:: * Evaluation:: * Mutilation:: * Scratchpad:: @end menu @node Shortcuts, Debugger, Interactive Perl, Interactive Perl @section Shortcuts ``Shortcuts'' are commands handled specially by the REPL rather than being evaluated as Perl code. They either communicate with the REPL function, or provide a convenient interface to Sepia variables and functions. Shortcuts are prefixed by a comma (@key{,}), and may be abbreviated to the shortest unique prefix. The debugger defines additional shortcuts (@xref{Debugger}.). @table @kbd @item break @var{file}:@var{line} [@var{expr}] Set a breakpoint in @var{file} at @var{line}. If @var{expr} is supplied, stop only if it evaluates to true. @item cd @var{dir} Change Perl's current directory to @var{dir}. @item debug [@var{val}] Turn Sepia debugger hook on or off, or toggle if @var{val} is missing. @item define @var{name} ['@var{doc}'] @var{body...} Define @var{name} as a shortcut for Perl code @var{body}, with optional documentation @var{doc}, surrounded by single quotes. @var{body} is passed the raw command-line text as its first argument. @item format @var{type} Set the output format to @var{type}, either ``dumper'' (using @code{Data::Dumper}), ``dump'' (@code{Data::Dump}), ``yaml'' (@code{YAML}), ``peek'' (@code{Devel::Peek}), ``dumpvar'' (@code{dumpvar.pl}, somewhat rough), or ``plain'' (stringification). Default: ``dumper''. Note that this setting is independent of @code{$COLUMNATE} and @code{$STRINGIFY}. @item help Display a list of shortcuts. @item load [@var{file}] Reload saved variables from @var{file} (or @file{~/.sepia-save}), created by @kbd{save}. @item lsbreak List breakpoints. @item lsmod [@var{pattern}] List currently-loaded modules matching optional @var{pattern}. @item methods @var{name} [@var{regexp}] Display a list of functions defined in package @var{name} and its @code{ISA}-ancestors matching optional pattern @var{regexp}. @item package @var{name} Set the default evaluation package to @var{name}. @item pwd Show the process's current working directory. @item quit Exit the inferior Perl process. @item reload [@var{module} | @var{/pattern/}] Reload @var{module} (but not its dependencies), or all modules matching @var{pattern}. @item freload @var{module} Reload @var{module} and all of its dependencies. @item restart Reload @file{Sepia.pm} and recursively invoke the REPL. This command is mostly of interest when working on Sepia itself, and will fail catastrophically if @file{Sepia.pm} fails to compile. @item save [@var{pattern} [@var{file}]] Save variables matching @var{pattern} (or all variables) to @var{file} (or @file{~/.sepia-save}) in @code{Storable} format. Note that because saving magic variables can have unpredictable results, using @kbd{save} without a pattern argument is risky. Sepia excludes common magic variables and dangerous packages, but its list is not foolproof. @item shell [@var{command}] Execute shell command @var{command}, displaying its standard output and standard error. @item size @var{package} [@var{regexp}] @item size [@var{regexp}] List the variables in @var{package} (or the current package) along with their total sizes. This requires the @code{Devel::Size} module. In strict mode, list lexical variables if no @var{package} is given. @item strict [@var{val}] Set evaluation strictness to @var{val}, or toggle it if @var{val} is not given. Note that turning strictness off and on clears the REPL's lexical environment. @item test [@var{file}] Run tests in the current directory. If @var{file} is given, only run test @var{file} or @file{t/@var{file}} @item time [@var{val}] Set time display to @var{val}, or toggle it if @var{val} is not given. With time display enabled, Sepia will use @code{BSD::Resource} and/or @code{Time::HiRes} to display wall clock time and CPU usage for the previous command as part of the prompt. @item undef @var{name} Undefine shortcut @var{name}. @strong{Warning}: this can equally be used to remove built-in shortcuts. @item wantarray [@var{val}] Set the evaluation context to @var{val}: @code{@@} means array, @code{$} means scalar, and anything else means void. @item who @var{package} [@var{regexp}] @itemx who [@var{regexp}] List identifiers in @var{package} (main by default) matching optional @var{regexp.} In strict mode, list lexical variables if no @var{package} is given. @end table @node Debugger, Evaluation, Shortcuts, Interactive Perl @section Debugger Sepia uses Perl's debugger hooks and GUD mode to support conditional breakpoints and single-stepping, and overrides Perl's @code{die()} to invoke the debugger rather than unwind the stack. This makes it possible to produce a backtrace, inspect and modify global variables, and even continue execution when a program tries to kill itself. If the PadWalker module is available, Sepia also provides functions to inspect and modify lexical variables. The debugger has its own set of shortcuts, also prefixed by a comma. @table @kbd @item backtrace Show a backtrace. @item delete Delete the current breakpoint. @item down @var{n} @itemx up @var{n} Move the current stack frame up or down by @var{n} (or one) frames. @item inspect [@var{n}] Inspect lexicals in the current frame or frame @var{n}, counting upward from 1. @item next [@var{n}] Advance @var{n} (or one) lines, skipping subroutine calls. @item quit @itemx die @itemx warn Continue as the program would have executed without debugger intervention, dying if the debugger was called from @code{die()}. @item return @var{expr} Continue execution as if @code{die()} had returned the value of @var{expr}, which is evaluated in the global environment. @item step [@var{n}] Step forward @var{n} (or one) lines, descending into subroutines. @item xreturn @var{sub} @var{expr} Return @var{expr} from the innermost call to @var{sub}. This is a somewhat dangerous and experimental feature, but is probably more useful than returning a value from @code{die()}. @end table @node Evaluation, Mutilation, Debugger, Interactive Perl @section Evaluation When interactive Perl is running, Sepia can evaluate regions of code in the inferior Perl process. The following commands assume that this process has already been started by calling @code{sepia-repl}. @table @kbd @item C-M-x @itemx M-x sepia-eval-defun @findex sepia-eval-defun Evaluate the function around point in the inferior Perl process. If it contains errors, jump to the location of the first. @item C-c C-l @itemx M-x sepia-load-file @findex sepia-load-file Save the current buffer, then reload its file and if warnings or errors occur, display an error buffer. With a prefix argument, also rebuild the cross-reference index. @item C-c e @itemx M-x sepia-eval-expression @key{RET} @var{expr} @key{RET} @findex sepia-eval-expression Evaluate @var{expr} in scalar context and echo the result. With a prefix argument, evaluate in list context. @item C-c! @itemx sepia-set-cwd @findex sepia-set-cwd Set the REPL's working directory to the current buffer's directory. @end table @node Mutilation, Scratchpad, Evaluation, Interactive Perl @section Mutilation Sepia contains several functions to operate on regions of text using the interactive Perl process. These functions can be used like standard one-liners (e.g. @samp{perl -pe ...}), with the advantage that all of the functions and variables in the interactive session are available. @table @kbd @item M-x sepia-perl-pe-region @key{RET} @var{code} @key{RET} @findex sepia-perl-pe-region Evaluate @var{code} on each line in the region with @code{$_} bound to the line text, collecting the resulting values of @code{$_}. With a prefix argument, replace the region with the result. @item M-x sepia-perl-ne-region @key{RET} @var{code} @key{RET} @findex sepia-perl-ne-region Evaluate @var{code} as above, but collect the results instead. @item M-x sepia-perlize-region @key{RET} @var{code} @key{RET} @findex sepia-perlize-region Evaluate @var{code} once with @code{$_} bound to the entire region, collecting the final value of @code{$_}. With a prefix argument, replace the region. @end table @node Scratchpad, , Mutilation, Interactive Perl @section Scratchpad @findex sepia-scratch Sepia also supports a scratchpad, another form of interaction inspired by Emacs' @code{*scratch*} buffer. To create or switch to the scratchpad, type @kbd{M-x sepia-scratch}. Scratchpad mode is exactly like Sepia mode, except @key{C-j} evaluates the current line and prints the result on the next line. @c ============================================================ @node CPAN browsing, Customization, Interactive Perl, Top @chapter CPAN browsing Sepia has rudimentary support for browsing documentation and installing modules from CPAN. Modules whose names, descriptions, or authors match a query are displayed in a @code{*sepia-cpan*} buffer, in which the following commands are available: @table @kbd @item s @itemx M-x sepia-cpan-search @key{RET} @var{pattern} @key{RET} @findex sepia-cpan-search List modules whose names match @var{pattern}. @item / @itemx M-x sepia-cpan-desc @key{RET} @var{pattern} @key{RET} @findex sepia-cpan-desc List modules whose names or descriptions match @var{pattern}. @item l @itemx M-x sepia-cpan-list @key{RET} @var{name} @key{RET} @findex sepia-cpan-list List modules authored by @var{name}. @item r @itemx M-x sepia-cpan-readme @key{RET} @var{module} @key{RET} @findex sepia-cpan-readme Fetch and display @var{module}'s README file. @item d @itemx M-x sepia-cpan-doc @key{RET} @var{module} @key{RET} @findex sepia-cpan-doc Browse @var{module}'s documentation on @url{http://search.cpan.org}. @item i @itemx M-x sepia-cpan-install @key{RET} @var{module} @key{RET} @findex sepia-cpan-install Install @var{module} and its prerequisites. This feature is not yet well tested. @end table @c ============================================================ @node Customization, Internals, CPAN browsing, Top @chapter Customization While Sepia can be customized in both the Perl and Emacs Lisp, most of the user-accessible configuration is in the latter. @menu * Emacs Customization:: * Perl Customization:: @end menu @node Emacs Customization, Perl Customization, Customization, Customization @section Emacs Customization Since Sepia tries where possible to reuse existing Emacs functionality, its behavior should already be covered by existing customizations. The two variables most likely to need customization are @kbd{sepia-program-name} and @kbd{sepia-perl5lib}. General Sepia mode configuration can be done with @kbd{sepia-mode-hook}, while REPL-specific configuration can be done with @kbd{sepia-repl-mode-hook}. @vtable @kbd @item sepia-complete-methods If non-@code{nil}, @code{sepia-complete-symbol} will complete simple method calls of the form @code{$x->} or @code{Module->}. Since the former requires evaluation of @code{$x}, this can be disabled. Default: @code{t}. @item sepia-eval-defun-include-decls If non-@code{nil}, attempt to generate a declaration list for @code{sepia-eval-defun}. This is necessary when evaluating some code, such as that calling functions without parentheses, because the presence of declarations affects the parsing of barewords. Default: @code{t}. @item sepia-indent-expand-abbrev If non-@code{nil}, @code{sepia-indent-or-complete} will, if reindentation does not change the current line, expand an abbreviation before point rather than performing completion. Only if no abbreviation is found will it perform completion. Default: @code{t}. @item sepia-module-list-function The function to view a tree of installed modules. Default: @code{w3m-find-file} if Emacs-w3m is installed, or @code{browse-url-of-buffer} otherwise. @item sepia-perldoc-function The function called to view installed modules' documentation. Default: @code{w3m-perldoc} if Emacs-w3m is installed, or @code{cperl-perldoc} otherwise. @item sepia-perl5lib A list of directories to include in @code{PERL5LIB} when starting interactive Perl. Default: @code{nil}. @item sepia-prefix-key The prefix to use for for functions in @code{sepia-keymap}. Default: @key{M-.}. @item sepia-program-name The Perl program name for interactive Perl. Default: ``perl''. @item sepia-use-completion If non-@code{nil}, various Sepia functions will generate completion candidates from interactive Perl when called interactively. This may be slow or undesirable in some situations. Default: @code{t}. @item sepia-view-pod-function The function called to view the current buffer's documentation. Default: @code{sepia-w3m-view-pod} if Emacs-w3m is available, or @code{sepia-perldoc-buffer} otherwise. @end vtable @node Perl Customization, , Emacs Customization, Customization @section Perl Customization When Sepia starts up, it evaluates the Perl script in @file{~/.sepiarc}. The following variables in the Sepia package control various aspects of interactive evaluation. @table @code @item $PACKAGE The package in which user input is evaluated, determined automatically when code is evaluated from a buffer. Default: @code{main}. @item $PRINTER The function called to format interactive output, normally set with the @code{printer} shortcut. @item $COLUMNATE If true, columnate simple arrays independent of the value of @code{$PRINTER}. Default: true. @item $STRINGIFY If true, stringify objects that overload the operation independent of the value of @code{$PRINTER}. Default: true. @item $PS1 The trailing end of the prompt string, which should end with ``> ''. Default: @code{"> "}. @item $STOPDIE If true, calls to @code{die} from interactive code will invoke the Sepia debugger. Default: true. @item $STOPWARN If true, calls to @code{warn} from interactive code will invoke the Sepia debugger. Default: false. @item $WANTARRAY If @code{@@}, evaluate interactive expressions in list context, if @code{$}, scalar, otherwise, void. Default: @code{@@}. @end table Additional REPL shortcuts can be defined as follows: @table @code @item Sepia::define_shortcut @var{name}, @var{function} [, @var{shortdoc} [, @var{longdoc}]] Define a shortcut @var{name} to call @var{function}. Also define a short usage message @var{shortdoc} and documentation @var{longdoc}. For example, @example Sepia::define_shortcut time => sub @{ print scalar localtime, "\n" @}, 'time', 'Display the current time.'; @end example defines a shortcut ``time'' that displays the current time. For more examples, see the function @var{define_shortcuts} code in @file{Sepia.pm}. @item Sepia::alias_shortcut @var{new}, @var{old} Make @var{new} an alias for @var{old}. @end table @c ============================================================ @node Internals, FAQ, Customization, Top @chapter Internals Many things remain unexplained except by the code itself, and some details mentioned above should probably be given less prominence. For developer documentation, please see the POD for @code{Sepia} and @code{Sepia::Xref}, and the doc-strings in @file{sepia.el}. @node FAQ, Credits, Internals, Top @chapter FAQ @table @asis @item Can I use @code{Sepia} outside of Emacs? Sepia comes with the @file{sepl} program, a command-line REPL using the @code{Sepia::Readline} module, that provides many features of the Emacs-based REPL. It could be improved, though -- patches welcome! @file{sepl} currently provides completion for @code{Term::ReadLine::Gnu} and @code{Term::ReadLine::Perl}. If you have neither of these, using @file{rlwrap} might be the best option. @item Why is the documentation in TeXInfo format?! TeXInfo is the worst form of documentation, except for all the others. TeX and LaTeX produce beautiful printed output, and Info is the best way to view documentation in Emacs for things that are not themselves part of Emacs (i.e. ``can have docstrings''). It's awful to edit, being both verbose and redundant -- just look at AUCTeX's @code{texinfo-every-node-update} for desperate placation of the suck, then try to figure out what's wrong when @file{makeinfo} complains about @code{texinfo-every-node-update}'s output -- but it's what we have. At least it sucks less than @code{DocBook}, raw HTML, or @file{troff}. @end table @node Credits, Function Index, FAQ, Top @unnumbered Credits @table @asis @item Hilko Bengen Found and motivated me to fix a bunch of bugs, created Debian packages. @item Ævar Arnfjörð Bjarmason Miscellaneous fixes. Tested unicode support. @item Ye Wenbin Found and fixed numerous bugs. @item Free Software Portions of the code were lifted from Emacs-w3m, SLIME, ido, and B::Xref, all of which are Free software. @end table @c ============================================================ @node Function Index, Variable Index, Credits, Top @unnumbered Function Index @printindex fn @node Variable Index, , Function Index, Top @unnumbered Variable Index @printindex vr @bye Sepia-0.992/sepl000755 000765 000765 00000002474 11660357770 014000 0ustar00seanoseano000000 000000 #!/usr/bin/env perl use Sepia::ReadLine; use Getopt::Long; sub usage { print STDERR < \&usage, version => sub { print STDERR "Sepia version $Sepia::VERSION.\n"; exit }, ) or usage; repl(); print "\n"; __END__ =head1 NAME C -- a Term::ReadLine-based Sepia interactive shell. =head1 SYNOPSIS $ sepl Type ",h" for help, or ",q" to quit. main @> substr "hello, japh", 7 'japh' main @> =head1 DESCRIPTION C uses L to provide an interactive Perl shell with many of the L features available in Emacs, including completion and all shortcuts. It is not well-tested or frequently used, and should be considered experimental. =head1 SEE ALSO L, L. Most of C's documentation is installed in Emacs' C format. On most systems it can be read from the command-line by typing "C". =head1 AUTHOR Sean O'Rourke, Eseano@cpan.orgE Bug reports welcome, patches even more welcome. =head1 COPYRIGHT Copyright (C) 2010-2011 Sean O'Rourke. All rights reserved, some wrongs reversed. This module is distributed under the same terms as Perl itself. =cut Sepia-0.992/t/000755 000765 000765 00000000000 11661034124 013325 5ustar00seanoseano000000 000000 Sepia-0.992/t/01basic.t000644 000765 000765 00000002447 11525347166 014757 0ustar00seanoseano000000 000000 #!/usr/bin/env perl use Test::Simple tests => 15; require Data::Dumper; require Sepia; require Sepia::Xref; require Sepia::Debug; ok(1, 'loaded'); # XXX: this segfaults, so skip it. # Sepia::Xref::rebuild(); ok(1, 'rebuild'); sub all { my $ok = 1; $ok &&= $_ for @_; $ok; } my @loc1 = Sepia::location('Sepia::location'); ok($loc1[0][0] =~ /Sepia\.pm$/, 'location'); ok((grep { $_ eq 'Sepia::location' } Sepia::apropos('location')), 'apropos'); # 4 to here sub apply_to_loc # 3 tests per call. { my $f = shift; my $loc1 = $f->('location'); ok($loc1, 'location 1'); my $loc2 = $f->('Sepia::location'); ok($loc2, 'fullname location'); my $ok = 1; ok(all(map { $loc1->[$_] eq $loc2->[$_] } 0..$#{$loc1}), 'sameness'); $loc1; } apply_to_loc(\&Sepia::Xref::callers); apply_to_loc(\&Sepia::Xref::callees); # 10 tests to here. my @subs = Sepia::mod_subs('Sepia'); ok(all(map { defined &{"Sepia::$_"} } @subs), 'mod_subs'); if (eval 'use Module::Info; 1') { ok(Sepia::module_info('Sepia', 'name') eq 'Sepia'); ok(Sepia::module_info('Sepia', 'version') eq $Sepia::VERSION); ok(Sepia::module_info('Sepia', 'file') =~ /Sepia\.pm$/); ok(Sepia::module_info('Sepia', 'is_core') == 0); } else { ok(1, 'skipped -- no Module::Info') for 1..4; } exit; Sepia-0.992/t/02completion.t000644 000765 000765 00000003406 11230430574 016031 0ustar00seanoseano000000 000000 #!/usr/bin/env perl use Test::Simple tests => 14; use Data::Dumper; require Sepia; # use warnings; no warnings; ## Set up some symbols to complete on: package Z::A; sub a_function { } sub a_nother_function { } sub xx { } $a_var = 0; @a_var2 = (); %a_var3 = (); sub Zz::A::xx { } sub Zz::Aa::xx { } package Z::Another; sub a_function { } sub a_nother_function { } $a_var = 0; @a_var2 = (); %a_var3 = (); package Z::A::Nother; sub a_function { } sub a_nother_function { } $a_var = 0; @a_var2 = (); %a_var3 = (); package Z::Blah; sub a_function { } sub a_nother_function { } $a_var = 0; @a_var2 = (); %a_var3 = (); ## Whew! package main; sub ok_comp { my ($type, $str) = splice @_, 0, 2; my $res = Dumper([sort(Sepia::completions($type, $str))]); my $expect = Dumper([sort @_]); my $ok = $res eq $expect; ok($ok, $ok ? $str : "$type/$str\n$res\n$expect\n"); } ok_comp(qw'CODE Z:A:x', qw'&Z::A::xx'); ok_comp(qw'CODE Z:Aa:x', qw'&Zz::Aa::xx'); ok_comp(qw'CODE Zz::A:x', qw'&Zz::A::xx'); ok_comp(qw'SCALAR Z:A:a_v', qw($Z::A::a_var)); ok_comp(qw'ARRAY Z:A:a_v', qw(@Z::A::a_var2)); ok_comp(qw'HASH Z:A:a_v', qw(%Z::A::a_var3)); ok_comp(qw'HASH z:a:a_v', qw(%Z::A::a_var3 %Z::Another::a_var3)); ok_comp(qw'HASH z:a:a_', qw(%Z::A::a_var3 %Z::Another::a_var3)); ok_comp(qw'HASH z:a:a', qw(%Z::A::a_var3 %Z::Another::a_var3)); ok_comp(qw'CODE Z:A:a_v'); ok_comp(qw'CODE Z:A:a', qw(&Z::A::a_nother_function &Z::A::a_function)); ok_comp(qw'CODE z:a:a', qw(&Z::A::a_nother_function &Z::Another::a_nother_function &Z::A::a_function &Z::Another::a_function)); ok_comp(qw'CODE zaa', qw(&Z::A::a_nother_function &Z::Another::a_nother_function &Z::A::a_function &Z::Another::a_function)); ok_comp('', 'za', qw(Z::A:: Z::Another:: Zz::A:: Zz::Aa::)); Sepia-0.992/t/03without.t000644 000765 000765 00000001122 11442524243 015357 0ustar00seanoseano000000 000000 #!/usr/bin/env perl use Test::Simple tests => 2; if (!eval q{ require Test::Without::Module;1 }) { ok(1, 'Test::Without::Module not installed.'); ok(2, 'Test::Without::Module not installed.'); exit 0; } my $str; $str .= "use Test::Without::Module '$_';" for qw{ Devel::Peek Devel::Size IO::Scalar Lexical::Persistence LWP::Simple Module::CoreList Module::Info PadWalker BSD::Resource Time::HiRes }; eval $str; my $res = eval q{use Time::HiRes;1}; ok(!$res, "Test::Without::Module works."); $res = eval "use Sepia;1"; ok($res && !$@, "loads without optional prereqs? ($res, $@)"); Sepia-0.992/t/50expect.t000644 000765 000765 00000006211 11657301701 015152 0ustar00seanoseano000000 000000 #!/usr/bin/env perl BEGIN { eval 'use Test::Expect'; if ($@) { print "# requires Test::Expect\n1..1\nok 1\n"; exit 0; } else { eval 'use Test::Simple tests => 36'; } } use FindBin '$Bin'; use Sepia; use Sepia::Xref; expect_run command => "$^X -Mblib -MSepia -MSepia::Xref -e Sepia::repl", prompt => [-re => 'main @[^>]*> '], quit => ',quit'; expect_handle()->log_file('/tmp/b') if exists $ENV{USER} && $ENV{USER} eq 'seano'; expect ",help", q!REPL commands (prefixed with ','): break [F:N [E]] Set a breakpoint in F at line N (or at current position), enabled if E evalutes to true. cd DIR Change directory to DIR debug [0|1] Enable or disable debugging. delete Delete current breakpoint. format [dumper|dump|yaml|plain] Set output formatter (default: dumper) help Display this message lsbreak List breakpoints. methods X [RE] List methods for reference or package X, matching optional pattern RE. package PACKAGE Set evaluation package to PACKAGE quit Quit the REPL reload Reload Sepia.pm and relaunch the REPL. shell CMD ... Run CMD in the shell. strict [0|1] Turn 'use strict' mode on or off wantarray [0|1] Set or toggle evaluation context who PACKAGE [RE] List variables and subs in PACKAGE matching optional pattern RE.! if 0; expect_send ",wh Sepia::Xref xref"; expect_like qr/xref \s+ xref_definitions \s+ xref_main \s+ xref_cv \s+ xref_exclude \s+ xref_object \s* /x; expect_send '{ package A; sub a {}; package X; @ISA = qw(A); sub x {} };'; expect ",wh X", 'X::// @ISA x', 'package list'; expect ",me X", 'a x', 'methods 1'; expect '$x = bless {}, X;', '$x = bless {}, X;'; # XXX: stupid expect. expect ',me $x', ",me \$x\na x", 'methods 2'; # XXX: stupid expect. ###################################################################### ## Debugger expect ',lsb', ''; expect_send ',debug 1'; expect_send "do '$Bin/testy.pl';", 'get testy'; expect 'fib1 10', '55', 'plain fib'; expect ',br testy.pl:6', "break testy.pl:6 if 1", 'break?'; expect_send 'fib1 10'; # sleep 1; expect_like qr|_<$Bin/testy.pl:6>|, 'break in fib'; # XXX AGAIN STUPID EXPECT! expect '$n = 3', "\$n = 3\n3", 'munge lexicals'; expect '$n = 3', "\$n = 3\n3", 'munge lexicals'; # Solaris has different whitespace output here. # Also, / */ doesn't seem to work. expect_send ',in', 'munged'; expect_like qr{\[3\] DB::DB:\n[ \t]\$n = \\3}, 'munged'; # qr{\[3\] DB::DB:\n? *\$n = \\3.*}; expect ',del', ''; expect ',con', '2', 'return from fib'; expect_send 'fib2 10', 'bad fib'; expect_like qr/_<$Bin\/testy.pl:12>/; expect_send ',q', 'quit'; # expect_like qr/_<$Bin\/testy.pl:12>/; expect_like qr/error: asdf/, 'saw die message'; print <<'EOS' if 0; # for debugging ,help ,wh Sepia::Xref xref { package A; sub a {}; package X; @ISA = qw(A); sub x {} }; ,wh X ,me X $x = bless {}, X; ,me $x ,lsb ,debug 1 do 'testy.pl'; fib1 10 ,br testy.pl:6 fib1 10 $n = 3 ,in ,del ,con fib2 10 ,q EOS Sepia-0.992/t/testy.pl000644 000765 000765 00000001144 11227170500 015027 0ustar00seanoseano000000 000000 sub fib1 { my $n = shift; if ($n < 2) { return $n } else { return fib1($n-1) + fib1($n-2) } } sub fib2 { my $n = shift; die "asdf\n" if $n <= 0; if ($n < 2) { return $n } else { return fib2($n-1) + fib2($n-2) } } sub rec { my $n = shift; print "rec($n)\n"; my $ret; if ($n == 0) { $ret = 0; } else { $ret = rec($n - 1); } print $ret+1, " = rec($n)\n"; return $ret + 1; } sub crec { print STDERR "crec(@_)\n"; my $ret = rec(@_); print STDERR "$ret = crec(@_)\n"; return $ret; } Sepia-0.992/lib/Sepia/000755 000765 000765 00000000000 11661034124 014671 5ustar00seanoseano000000 000000 Sepia-0.992/lib/Sepia.pm000644 000765 000765 00000144450 11661034051 015236 0ustar00seanoseano000000 000000 package Sepia; =head1 NAME Sepia - Simple Emacs-Perl Interface =head1 SYNOPSIS From inside Emacs: M-x load-library RET sepia RET M-x sepia-repl RET At the prompt in the C<*sepia-repl*> buffer: main @> ,help For more information, please see F or F, which come with the distribution. =head1 DESCRIPTION Sepia is a set of features to make Emacs a better tool for Perl development. This package contains the Perl side of the implementation, including all user-serviceable parts (for the cross-referencing facility see L). This document is aimed as Sepia developers; for user documentation, see L or L. Though not intended to be used independent of the Emacs interface, the Sepia module's functionality can be used through a rough procedural interface. =cut $VERSION = '0.992'; BEGIN { if ($] >= 5.012) { eval 'no warnings "deprecated"'; # undo some of the 5.12 suck. } # Not as useful as I had hoped... sub track_requires { my $parent = caller; (my $child = $_[1]) =~ s!/!::!g; $child =~ s/\.pm$//; push @{$REQUIRED_BY{$child}}, $parent; push @{$REQUIRES{$parent}}, $child; } BEGIN { sub TRACK_REQUIRES () { $ENV{TRACK_REQUIRES}||0 } }; unshift @INC, \&Sepia::track_requires if TRACK_REQUIRES; } use strict; use B; use Sepia::Debug; # THIS TURNS ON DEBUGGING INFORMATION! use Cwd 'abs_path'; use Scalar::Util 'looks_like_number'; use Text::Abbrev; use File::Find; use Storable qw(store retrieve); use vars qw($PS1 %REPL %RK %REPL_DOC %REPL_SHORT %PRINTER @res $REPL_LEVEL $REPL_QUIT $PACKAGE $SIGGED $WANTARRAY $PRINTER $STRICT $COLUMNATE $ISEVAL $STRINGIFY $LAST_INPUT $READLINE @PRE_EVAL @POST_EVAL @PRE_PROMPT %REQUIRED_BY %REQUIRES); BEGIN { eval q{ use List::Util 'max' }; if ($@) { *Sepia::max = sub { my $ret = shift; for (@_) { $ret = $_ if $_ > $ret; } $ret; }; } } =head2 Hooks Like Emacs, Sepia's behavior can be modified by placing functions on various hooks (arrays). Hooks can be manipulated by the following functions: =over =item C -- Add C<@functions> to C<@hook>. =item C -- Remove named C<@functions> from C<@hook>. =item C -- Run the functions on the named hook. Each function is called with no arguments in an eval {} block, and its return value is ignored. =back Sepia currently defines the following hooks: =over =item C<@PRE_PROMPT> -- Called immediately before the prompt is printed. =item C<@PRE_EVAL> -- Called immediately before evaluating user input. =item C<@POST_EVAL> -- Called immediately after evaluating user input. =back =cut sub run_hook(\@) { my $hook = shift; no strict 'refs'; for (@$hook) { eval { $_->() }; } } sub add_hook(\@@) { my $hook = shift; for my $h (@_) { push @$hook, $h unless grep $h eq $_, @$hook; } } sub remove_hook(\@@) { my $hook = shift; @$hook = grep { my $x = $_; !grep $_ eq $x, @$hook } @$hook; } =head2 Completion Sepia tries hard to come up with a list of completions. =over =item C<$re = _apropos_re($pat)> Create a completion expression from user input. =cut sub _apropos_re($;$) { # Do that crazy multi-word identifier completion thing: my $re = shift; my $hat = shift() ? '' : '^'; return qr/.*/ if $re eq ''; if (wantarray) { map { s/(?:^|(?<=[A-Za-z\d]))(([^A-Za-z\d])\2*)/[A-Za-z\\d]*$2+/g; qr/$hat$_/; } split /:+/, $re, -1; } else { if ($re !~ /[^\w\d_^:]/) { $re =~ s/(?<=[A-Za-z\d])(([^A-Za-z\d])\2*)/[A-Za-z\\d]*$2+/g; } qr/$re/; } } my %sigil; BEGIN { %sigil = qw(ARRAY @ SCALAR $ HASH %); } =item C<$val = filter_untyped> Return true if C<$_> is the name of a sub, file handle, or package. =item C<$val = filter_typed $type> Return true if C<$_> is the name of something of C<$type>, which should be either a glob slot name (e.g. SCALAR) or the special value "VARIABLE", meaning an array, hash, or scalar. =cut sub filter_untyped { no strict; local $_ = /^::/ ? $_ : "::$_"; defined *{$_}{CODE} || defined *{$_}{IO} || (/::$/ && %$_); } ## XXX: Careful about autovivification here! Specifically: ## defined *FOO{HASH} # => '' ## defined %FOO # => '' ## defined *FOO{HASH} # => 1 sub filter_typed { no strict; my $type = shift; local $_ = /^::/ ? $_ : "::$_"; if ($type eq 'SCALAR') { defined $$_; } elsif ($type eq 'VARIABLE') { defined $$_ || defined *{$_}{HASH} || defined *{$_}{ARRAY}; } else { defined *{$_}{$type} } } =item C<$re_out = maybe_icase $re_in> Make C<$re_in> case-insensitive if it looks like it should be. =cut sub maybe_icase { my $ch = shift; return '' if $ch eq ''; $ch =~ /[A-Z]/ ? $ch : '['.uc($ch).$ch.']'; } =item C<@res = all_abbrev_completions $pattern> Find all "abbreviated completions" for $pattern. =cut sub all_abbrev_completions { use vars '&_completions'; local *_completions = sub { no strict; my ($stash, @e) = @_; my $ch = '[A-Za-z0-9]*'; my $re1 = "^".maybe_icase($e[0]).$ch.join('', map { '_'.maybe_icase($_).$ch } @e[1..$#e]); $re1 = qr/$re1/; my $re2 = maybe_icase $e[0]; $re2 = qr/^$re2.*::$/; my @ret = grep !/::$/ && /$re1/, keys %{$stash}; my @pkgs = grep /$re2/, keys %{$stash}; (map("$stash$_", @ret), @e > 1 ? map { _completions "$stash$_", @e[1..$#e] } @pkgs : map { "$stash$_" } @pkgs) }; map { s/^:://; $_ } _completions('::', split //, shift); } sub apropos_re { my ($icase, $re) = @_; $re =~ s/_/[^_]*_/g; $icase ? qr/^$re.*$/i : qr/^$re.*$/; } sub all_completions { my $icase = $_[0] !~ /[A-Z]/; my @parts = split /:+/, shift, -1; my $re = apropos_re $icase, pop @parts; use vars '&_completions'; local *_completions = sub { no strict; my $stash = shift; if (@_ == 0) { map { "$stash$_" } grep /$re/, keys %{$stash}; } else { my $re2 = $icase ? qr/^$_[0].*::$/i : qr/^$_[0].*::$/; my @pkgs = grep /$re2/, keys %{$stash}; map { _completions "$stash$_", @_[1..$#_] } @pkgs } }; map { s/^:://; $_ } _completions('::', @parts); } =item C<@res = filter_exact_prefix @names> Filter exact matches so that e.g. "A::x" completes to "A::xx" when both "Ay::xx" and "A::xx" exist. =cut sub filter_exact_prefix { my @parts = split /:+/, shift, -1; my @res = @_; my @tmp; my $pre = shift @parts; while (@parts && (@tmp = grep /^\Q$pre\E(?:::|$)/, @res)) { @res = @tmp; $pre .= '::'.shift @parts; } @res; } =item C<@res = lexical_completions $type, $str, $sub> Find lexicals of C<$sub> (or a parent lexical environment) of type C<$type> matching C<$str>. =cut sub lexical_completions { eval q{ use PadWalker 'peek_sub' }; # "internal" function, so don't warn on failure return if $@; *lexical_completions = sub { my ($type, $str, $sub) = @_; $sub = "$PACKAGE\::$sub" unless $sub =~ /::/; # warn "Completing $str of type $type in $sub\n"; no strict; return unless defined *{$sub}{CODE}; my $pad = peek_sub(\&$sub); if ($type) { map { s/^[\$\@&\%]//;$_ } grep /^\Q$type$str\E/, keys %$pad; } else { map { s/^[\$\@&\%]//;$_ } grep /^.\Q$str\E/, keys %$pad; } }; goto &lexical_completions; } =item C<@compls = completions($string [, $type [, $sub ] ])> Find a list of completions for C<$string> with glob type C<$type>, which may be "SCALAR", "HASH", "ARRAY", "CODE", "IO", or the special value "VARIABLE", which means either scalar, hash, or array. Completion operates on word subparts separated by [:_], so e.g. "S:m_w" completes to "Sepia::my_walksymtable". If C<$sub> is given, also consider its lexical variables. =item C<@compls = method_completions($expr, $string [,$eval])> Complete among methods on the object returned by C<$expr>. The C<$eval> argument, if present, is a function used to do the evaluation; the default is C, but for example the Sepia REPL uses C. B: Since it has to evaluate C<$expr>, method completion can be extremely problematic. Use with care. =cut sub completions { my ($type, $str, $sub) = @_; my $t; my %h = qw(@ ARRAY % HASH & CODE * IO $ SCALAR); my %rh; @rh{values %h} = keys %h; $type ||= ''; $t = $type ? $rh{$type} : ''; my @ret; if ($sub && $type ne '') { @ret = lexical_completions $t, $str, $sub; } if (!@ret) { @ret = grep { $type ? filter_typed $type : filter_untyped } all_completions $str; } if (!@ret && $str !~ /:/) { @ret = grep { $type ? filter_typed $type : filter_untyped } all_abbrev_completions $str; } @ret = map { s/^:://; "$t$_" } filter_exact_prefix $str, @ret; # ## XXX: Control characters, $", and $1, etc. confuse Emacs, so # ## remove them. grep { length $_ > 0 && !/^\d+$/ && !/^[^\w\d_]$/ && !/^_("ref($x)"))) || $eval->('%'.$x.'::'); unless ($@) { my $re = _apropos_re $fn; ## Filter out overload methods "(..." return sort { $a cmp $b } map { s/.*:://; $_ } grep { defined *{$_}{CODE} && /::$re/ && !/\(/ } methods($x, 1); } } =item C<@matches = apropos($name [, $is_regex])> Search for function C<$name>, either in all packages or, if C<$name> is qualified, only in one package. If C<$is_regex> is true, the non-package part of C<$name> is a regular expression. =cut sub my_walksymtable(&*) { no strict; my ($f, $st) = @_; local *_walk = sub { local ($stash) = @_; &$f for keys %$stash; _walk("$stash$_") for grep /(? Find subs in package C<$pack>. =cut sub mod_subs { no strict; my $p = shift; my $stash = \%{"$p\::"}; if (%$stash) { grep { defined &{"$p\::$_"} } keys %$stash; } } =item C<@decls = mod_decls($pack)> Generate a list of declarations for all subroutines in package C<$pack>. =cut sub mod_decls { my $pack = shift; no strict 'refs'; my @ret = map { my $sn = $_; my $proto = prototype(\&{"$pack\::$sn"}); $proto = defined($proto) ? "($proto)" : ''; "sub $sn $proto;"; } mod_subs($pack); return wantarray ? @ret : join '', @ret; } =item C<$info = module_info($module, $type)> Emacs-called function to get module information. =cut sub module_info { eval q{ require Module::Info; import Module::Info }; if ($@) { undef; } else { no warnings; *module_info = sub { my ($m, $func) = @_; my $info; if (-f $m) { $info = Module::Info->new_from_file($m); } else { (my $file = $m) =~ s|::|/|g; $file .= '.pm'; if (exists $INC{$file}) { $info = Module::Info->new_from_loaded($m); } else { $info = Module::Info->new_from_module($m); } } if ($info) { return $info->$func; } }; goto &module_info; } } =item C<$file = mod_file($mod)> Find the likely file owner for module C<$mod>. =cut sub mod_file { my $m = shift; $m =~ s/::/\//g; while ($m && !exists $INC{"$m.pm"}) { $m =~ s#(?:^|/)[^/]+$##; } $m ? $INC{"$m.pm"} : undef; } =item C<@mods = package_list> Gather a list of all distributions on the system. =cut our $INST; sub inst() { unless ($INST) { require ExtUtils::Installed; $INST = new ExtUtils::Installed; } $INST; } sub package_list { sort { $a cmp $b } inst()->modules; } =item C<@mods = module_list> Gather a list of all packages (.pm files, really) installed on the system, grouped by distribution. XXX UNUSED =cut sub inc_re { join '|', map quotemeta, sort { length $b <=> length $a } @INC; } sub module_list { @_ = package_list unless @_; my $incre = inc_re; $incre = qr|(?:$incre)/|; my $inst = inst; map { [$_, sort map { s/$incre\///; s|/|::|g;$_ } grep /\.pm$/, $inst->files($_)] } @_; } =item C<@paths = file_list $module> List the absolute paths of all files (except man pages) installed by C<$module>. =cut sub file_list { my @ret = eval { grep /\.p(l|m|od)$/, inst->files(shift) }; @ret ? @ret : (); } =item C<@mods = doc_list> Gather a list of all documented packages (.?pm files, really) installed on the system, grouped by distribution. XXX UNUSED =back =cut sub doc_list { @_ = package_list unless @_; my $inst = inst; map { [$_, sort map { s/.*man.\///; s|/|::|g;s/\..?pm//; $_ } grep /\..pm$/, $inst->files($_)] } @_; } =head2 Miscellaneous functions =over =item C<$v = core_version($module)> =cut sub core_version { eval q{ require Module::CoreList }; if ($@) { '???'; } else { *core_version = sub { Module::CoreList->first_release(@_) }; goto &core_version; } } =item C<[$file, $line, $name] = location($name)> Return a [file, line, name] triple for function C<$name>. =cut sub location { no strict; map { if (my ($pfx, $name) = /^([\%\$\@]?)(.+)/) { if ($pfx) { warn "Sorry -- can't lookup variables."; } else { # XXX: svref_2object only seems to work with a package # tacked on, but that should probably be done elsewhere... $name = 'main::'.$name unless $name =~ /::/; my $cv = B::svref_2object(\&{$name}); if ($cv && defined($cv = $cv->START) && !$cv->isa('B::NULL')) { my ($file, $line) = ($cv->file, $cv->line); if ($file !~ /^\//) { for (@INC) { if (!ref $_ && -f "$_/$file") { $file = "$_/$file"; last; } } } my ($shortname) = $name =~ /^(?:.*::)([^:]+)$/; return [Cwd::abs_path($file), $line, $shortname || $name] } } } [] } @_; } =item C Return a list of C<$subname>'s lexical variables. Note that this includes all nested scopes -- I don't know if or how Perl distinguishes inner blocks. =cut sub lexicals { my $cv = B::svref_2object(\&{+shift}); return unless $cv && ($cv = $cv->PADLIST); my ($names, $vals) = $cv->ARRAY; map { my $name = $_->PV; $name =~ s/\0.*$//; $name } grep B::class($_) ne 'SPECIAL', $names->ARRAY; } =item C<$lisp = tolisp($perl)> Convert a Perl scalar to some ELisp equivalent. =cut sub tolisp($) { my $thing = @_ == 1 ? shift : \@_; my $t = ref $thing; if (!$t) { if (!defined $thing) { 'nil' } elsif (looks_like_number $thing) { ''.(0+$thing); } else { ## XXX Elisp and perl have slightly different ## escaping conventions, so we do this crap instead. $thing =~ s/["\\]/\\$1/g; qq{"$thing"}; } } elsif ($t eq 'GLOB') { (my $name = $$thing) =~ s/\*main:://; $name; } elsif ($t eq 'ARRAY') { '(' . join(' ', map { tolisp($_) } @$thing).')' } elsif ($t eq 'HASH') { '(' . join(' ', map { '(' . tolisp($_) . " . " . tolisp($thing->{$_}) . ')' } keys %$thing).')' } elsif ($t eq 'Regexp') { "'(regexp . \"" . quotemeta($thing) . '")'; # } elsif ($t eq 'IO') { } else { qq{"$thing"}; } } =item C Print C<@res> appropriately on the current filehandle. If C<$ISEVAL> is true, use terse format. Otherwise, use human-readable format, which can use either L, L, or L. =cut %PRINTER = ( dumper => sub { eval q{ require Data::Dumper }; local $Data::Dumper::Deparse = 1; local $Data::Dumper::Indent = 0; local $_; my $thing = @res > 1 ? \@res : $res[0]; eval { $_ = Data::Dumper::Dumper($thing); }; if (length $_ > ($ENV{COLUMNS} || 80)) { $Data::Dumper::Indent = 1; eval { $_ = Data::Dumper::Dumper($thing); }; } s/\A\$VAR1 = //; s/;\Z//; $_; }, plain => sub { "@res"; }, dumpvar => sub { if (eval q{require 'dumpvar.pl';1}) { dumpvar::veryCompact(1); $PRINTER{dumpvar} = sub { dumpValue(\@res) }; goto &{$PRINTER{dumpvar}}; } }, yaml => sub { eval q{ require YAML }; if ($@) { $PRINTER{dumper}->(); } else { YAML::Dump(\@res); } }, dump => sub { eval q{ require Data::Dump }; if ($@) { $PRINTER{dumper}->(); } else { Data::Dump::dump(\@res); } }, peek => sub { eval q{ require Devel::Peek; require IO::Scalar; }; if ($@) { $PRINTER{dumper}->(); } else { my $ret = new IO::Scalar; my $out = select $ret; Devel::Peek::Dump(@res == 1 ? $res[0] : \@res); select $out; $ret; } } ); sub ::_() { if (wantarray) { @res } else { $_ } } sub printer { local *res = shift; my $res; @_ = @res; $_ = @res == 1 ? $res[0] : @res == 0 ? undef : [@res]; my $str; if ($ISEVAL) { $res = "@res"; } elsif (@res == 1 && !$ISEVAL && $STRINGIFY && UNIVERSAL::can($res[0], '()')) { # overloaded? $res = "$res[0]"; } elsif (!$ISEVAL && $COLUMNATE && @res > 1 && !grep ref, @res) { $res = columnate(@res); print $res; return; } else { $res = $PRINTER{$PRINTER}->(); } if ($ISEVAL) { print ';;;', length $res, "\n$res\n"; } else { print "$res\n"; } } BEGIN { $PS1 = "> "; $PACKAGE = 'main'; $WANTARRAY = '@'; $PRINTER = 'dumper'; $COLUMNATE = 1; $STRINGIFY = 1; } =item C -- Print the REPL prompt. =cut sub prompt() { run_hook @PRE_PROMPT; "$PACKAGE $WANTARRAY$PS1" } sub Dump { eval { Data::Dumper->Dump([$_[0]], [$_[1]]); }; } =item C<$flowed = flow($width, $text)> -- Flow C<$text> to at most C<$width> columns. =cut sub flow { my $n = shift; my $n1 = int(2*$n/3); local $_ = shift; s/(.{$n1,$n}) /$1\n/g; $_ } =back =head2 Persistence =over =item C -- Load persisted data in C<@keyvals>. =item C<$ok = saveable $name> -- Return whether C<$name> is saveable. Saving certain magic variables leads to badness, so we avoid them. =item C<\@kvs = save $re> -- Return a list of name/value pairs to save. =back =cut sub load { my $a = shift; no strict; for (@$a) { *{$_->[0]} = $_->[1]; } } my %BADVARS; undef @BADVARS{qw(%INC @INC %SIG @ISA %ENV @ARGV)}; # magic variables sub saveable { local $_ = shift; return !/^.[^c-zA-Z]$/ # single-letter stuff (match vars, $_, etc.) && !/^.[\0-\060]/ # magic weirdness. && !/^._[0] " for @save; print STDERR "\n"; \@save; } =head2 REPL shortcuts The function implementing built-in REPL shortcut ",X" is named C. =over =item C Define $name as a shortcut for function $sub. =cut sub define_shortcut { my ($name, $doc, $short, $fn); if (@_ == 2) { ($name, $fn) = @_; $short = $name; $doc = ''; } elsif (@_ == 3) { ($name, $fn, $doc) = @_; $short = $name; } else { ($name, $fn, $short, $doc) = @_; } $REPL{$name} = $fn; $REPL_DOC{$name} = $doc; $REPL_SHORT{$name} = $short; abbrev \%RK, keys %REPL; } =item C Alias $new to do the same as $old. =cut sub alias_shortcut { my ($new, $old) = @_; $REPL{$new} = $REPL{$old}; $REPL_DOC{$new} = $REPL_DOC{$old}; ($REPL_SHORT{$new} = $REPL_SHORT{$old}) =~ s/^\Q$old\E/$new/; abbrev %RK, keys %REPL; } =item C Define the default REPL shortcuts. =cut sub define_shortcuts { define_shortcut 'help', \&Sepia::repl_help, 'help [CMD]', 'Display help on all commands, or just CMD.'; define_shortcut 'cd', \&Sepia::repl_chdir, 'cd DIR', 'Change directory to DIR'; define_shortcut 'pwd', \&Sepia::repl_pwd, 'Show current working directory'; define_shortcut 'methods', \&Sepia::repl_methods, 'methods X [RE]', 'List methods for reference or package X, matching optional pattern RE'; define_shortcut 'package', \&Sepia::repl_package, 'package PKG', 'Set evaluation package to PKG'; define_shortcut 'who', \&Sepia::repl_who, 'who PKG [RE]', 'List variables and subs in PKG matching optional pattern RE.'; define_shortcut 'wantarray', \&Sepia::repl_wantarray, 'wantarray [0|1]', 'Set or toggle evaluation context'; define_shortcut 'format', \&Sepia::repl_format, 'format [TYPE]', "Set output formatter to TYPE (one of 'dumper', 'dump', 'yaml', 'plain'; default: 'dumper'), or show current type."; define_shortcut 'strict', \&Sepia::repl_strict, 'strict [0|1]', 'Turn \'use strict\' mode on or off'; define_shortcut 'quit', \&Sepia::repl_quit, 'Quit the REPL'; alias_shortcut 'exit', 'quit'; define_shortcut 'restart', \&Sepia::repl_restart, 'Reload Sepia.pm and relaunch the REPL.'; define_shortcut 'shell', \&Sepia::repl_shell, 'shell CMD ...', 'Run CMD in the shell'; define_shortcut 'eval', \&Sepia::repl_eval, 'eval EXP', '(internal)'; define_shortcut 'size', \&Sepia::repl_size, 'size PKG [RE]', 'List total sizes of objects in PKG matching optional pattern RE.'; define_shortcut define => \&Sepia::repl_define, 'define NAME [\'DOC\'] BODY', 'Define NAME as a shortcut executing BODY'; define_shortcut undef => \&Sepia::repl_undef, 'undef NAME', 'Undefine shortcut NAME'; define_shortcut test => \&Sepia::repl_test, 'test FILE...', 'Run tests interactively.'; define_shortcut load => \&Sepia::repl_load, 'load [FILE]', 'Load state from FILE.'; define_shortcut save => \&Sepia::repl_save, 'save [PATTERN [FILE]]', 'Save variables matching PATTERN to FILE.'; define_shortcut reload => \&Sepia::repl_reload, 'reload [MODULE | /RE/]', 'Reload MODULE, or all modules matching RE.'; define_shortcut freload => \&Sepia::repl_full_reload, 'freload MODULE', 'Reload MODULE and all its dependencies.'; define_shortcut time => \&Sepia::repl_time, 'time [0|1]', 'Print timing information for each command.'; define_shortcut lsmod => \&Sepia::repl_lsmod, 'lsmod [PATTERN]', 'List loaded modules matching PATTERN.'; } =item C Toggle strict mode. Requires L and L. =cut sub repl_strict { eval q{ use PadWalker qw(peek_sub set_closed_over); use Devel::LexAlias 'lexalias'; }; if ($@) { print "Strict mode requires PadWalker and Devel::LexAlias.\n"; } else { *repl_strict = sub { my $x = as_boolean(shift, $STRICT); if ($x && !$STRICT) { $STRICT = {}; } elsif (!$x) { undef $STRICT; } }; goto &repl_strict; } } sub repl_size { eval q{ require Devel::Size }; if ($@) { print "Size requires Devel::Size.\n"; } else { *Sepia::repl_size = sub { my ($pkg, $re) = split ' ', shift, 2; if ($re) { $re =~ s!^/|/$!!g; } elsif (!$re && $pkg =~ /^\/(.*?)\/?$/) { $re = $1; undef $pkg; } elsif (!$pkg) { $re = '.'; } my (@who, %res); if ($STRICT && !$pkg) { @who = grep /$re/, keys %$STRICT; for (@who) { $res{$_} = Devel::Size::total_size($Sepia::STRICT->{$_}); } } else { no strict 'refs'; $pkg ||= 'main'; @who = who($pkg, $re); for (@who) { next unless /^[\$\@\%\&]/; # skip subs. next if $_ eq '%SIG'; $res{$_} = eval "no strict; package $pkg; Devel::Size::total_size \\$_;"; } } my $len = max(3, map { length } @who) + 4; my $fmt = '%-'.$len."s%10d\n"; # print "$pkg\::/$re/\n"; print 'Var', ' ' x ($len + 2), "Bytes\n"; print '-' x ($len-4), ' ' x 9, '-' x 5, "\n"; for (sort { $res{$b} <=> $res{$a} } keys %res) { printf $fmt, $_, $res{$_}; } }; goto &repl_size; } } =item C Toggle command timing. =cut my ($time_res, $TIME); sub time_pre_prompt_bsd { printf "(%.2gr, %.2gu, %.2gs) ", @{$time_res} if defined $time_res; }; sub time_pre_prompt_plain { printf "(%.2gs) ", $time_res if defined $time_res; } sub repl_time { $TIME = as_boolean(shift, $TIME); if (!$TIME) { print STDERR "Removing time hook.\n"; remove_hook @PRE_PROMPT, 'Sepia::time_pre_prompt'; remove_hook @PRE_EVAL, 'Sepia::time_pre_eval'; remove_hook @POST_EVAL, 'Sepia::time_post_eval'; return; } print STDERR "Adding time hook.\n"; add_hook @PRE_PROMPT, 'Sepia::time_pre_prompt'; add_hook @PRE_EVAL, 'Sepia::time_pre_eval'; add_hook @POST_EVAL, 'Sepia::time_post_eval'; my $has_bsd = eval q{ use BSD::Resource 'getrusage';1 }; my $has_hires = eval q{ use Time::HiRes qw(gettimeofday tv_interval);1 }; my ($t0); if ($has_bsd) { # sweet! getrusage! my ($user, $sys, $real); *time_pre_eval = sub { undef $time_res; ($user, $sys) = getrusage(); $real = $has_hires ? [gettimeofday()] : $user+$sys; }; *time_post_eval = sub { my ($u2, $s2) = getrusage(); $time_res = [$has_hires ? tv_interval($real, [gettimeofday()]) : $s2 + $u2 - $real, ($u2 - $user), ($s2 - $sys)]; }; *time_pre_prompt = *time_pre_prompt_bsd; } elsif ($has_hires) { # at least we have msec... *time_pre_eval = sub { undef $time_res; $t0 = [gettimeofday()]; }; *time_post_eval = sub { $time_res = tv_interval($t0, [gettimeofday()]); }; *time_pre_prompt = *time_pre_prompt_plain; } else { *time_pre_eval = sub { undef $time_res; $t0 = time; }; *time_post_eval = sub { $time_res = (time - $t0); }; *time_pre_prompt = *time_pre_prompt_plain; } } sub repl_help { my $width = $ENV{COLUMNS} || 80; my $args = shift; if ($args =~ /\S/) { $args =~ s/^\s+//; $args =~ s/\s+$//; my $full = $RK{$args}; if ($full) { my $short = $REPL_SHORT{$full}; my $flow = flow($width - length $short - 4, $REPL_DOC{$full}); $flow =~ s/(.)\n/"$1\n".(' 'x (4 + length $short))/eg; print "$short $flow\n"; } else { print "$args: no such command\n"; } } else { my $left = 1 + max map length, values %REPL_SHORT; print "REPL commands (prefixed with ','):\n"; for (sort keys %REPL) { my $flow = flow($width - $left, $REPL_DOC{$_}); $flow =~ s/(.)\n/"$1\n".(' ' x $left)/eg; printf "%-${left}s%s\n", $REPL_SHORT{$_}, $flow; } } } sub repl_define { local $_ = shift; my ($name, $doc, $body); if (/^\s*(\S+)\s+'((?:[^'\\]|\\.)*)'\s+(.+)/) { ($name, $doc, $body) = ($1, $2, $3); } elsif (/^\s*(\S+)\s+(\S.*)/) { ($name, $doc, $body) = ($1, $2, $2); } else { print "usage: define NAME ['doc'] BODY...\n"; return; } my $sub = eval "sub { do { $body } }"; if ($@) { print "usage: define NAME ['doc'] BODY...\n\t$@\n"; return; } define_shortcut $name, $sub, $doc; # %RK = abbrev keys %REPL; } sub repl_undef { my $name = shift; $name =~ s/^\s*//; $name =~ s/\s*$//; my $full = $RK{$name}; if ($full) { delete $REPL{$full}; delete $REPL_SHORT{$full}; delete $REPL_DOC{$full}; abbrev \%RK, keys %REPL; } else { print "$name: no such shortcut.\n"; } } sub repl_format { my $t = shift; chomp $t; if ($t eq '') { print "printer = $PRINTER, columnate = @{[$COLUMNATE ? 1 : 0]}\n"; } else { my %formats = abbrev keys %PRINTER; if (exists $formats{$t}) { $PRINTER = $formats{$t}; } else { warn "No such format '$t' (dumper, dump, yaml, plain).\n"; } } } sub repl_chdir { chomp(my $dir = shift); $dir =~ s/^~\//$ENV{HOME}\//; $dir =~ s/\$HOME/$ENV{HOME}/; if (-d $dir) { chdir $dir; my $ecmd = '(cd "'.Cwd::getcwd().'")'; print ";;;###".length($ecmd)."\n$ecmd\n"; } else { warn "Can't chdir\n"; } } sub repl_pwd { print Cwd::getcwd(), "\n"; } =item C List variables and functions in C<$package> matching C<$re>, or all variables if C<$re> is absent. =cut sub who { my ($pack, $re_str) = @_; $re_str ||= '.?'; my $re = qr/$re_str/; no strict; if ($re_str =~ /^[\$\@\%\&]/) { ## sigil given -- match it sort grep /$re/, map { my $name = $pack.'::'.$_; (defined *{$name}{HASH} ? '%'.$_ : (), defined *{$name}{ARRAY} ? '@'.$_ : (), defined *{$name}{CODE} ? $_ : (), defined ${$name} ? '$'.$_ : (), # ? ) } grep !/::$/ && !/^(?:_<|[^\w])/ && /$re/, keys %{$pack.'::'}; } else { ## no sigil -- don't match it sort map { my $name = $pack.'::'.$_; (defined *{$name}{HASH} ? '%'.$_ : (), defined *{$name}{ARRAY} ? '@'.$_ : (), defined *{$name}{CODE} ? $_ : (), defined ${$name} ? '$'.$_ : (), # ? ) } grep !/::$/ && !/^(?:_<|[^\w])/ && /$re/, keys %{$pack.'::'}; } } =item C<$text = columnate(@items)> Format C<@items> in columns such that they fit within C<$ENV{COLUMNS}> columns. =cut sub columnate { my $len = 0; my $width = $ENV{COLUMNS} || 80; for (@_) { $len = length if $len < length; } my $nc = int($width / ($len+1)) || 1; my $nr = int(@_ / $nc) + (@_ % $nc ? 1 : 0); my $fmt = ('%-'.($len+1).'s') x ($nc-1) . "%s\n"; my @incs = map { $_ * $nr } 0..$nc-1; my $str = ''; for my $r (0..$nr-1) { $str .= sprintf $fmt, map { defined($_) ? $_ : '' } @_[map { $r + $_ } @incs]; } $str =~ s/ +$//m; $str } sub repl_who { my ($pkg, $re) = split ' ', shift, 2; if ($re) { $re =~ s!^/|/$!!g; } elsif (!$re && $pkg =~ /^\/(.*?)\/?$/) { $re = $1; undef $pkg; } elsif (!$pkg) { $re = '.'; } my @x; if ($STRICT && !$pkg) { @x = grep /$re/, keys %$STRICT; $pkg = '(lexical)'; } else { $pkg ||= $PACKAGE; @x = who($pkg, $re); } print($pkg, "::/$re/\n", columnate @x) if @x; } =item C<@m = methods($package [, $qualified])> List method names in C<$package> and its parents. If C<$qualified>, return full "CLASS::NAME" rather than just "NAME." =cut sub methods { my ($pack, $qualified) = @_; no strict; my @own = $qualified ? grep { defined *{$_}{CODE} } map { "$pack\::$_" } keys %{$pack.'::'} : grep { defined &{"$pack\::$_"} } keys %{$pack.'::'}; if (exists ${$pack.'::'}{ISA} && *{$pack.'::ISA'}{ARRAY}) { my %m; undef @m{@own, map methods($_, $qualified), @{$pack.'::ISA'}}; @own = keys %m; } @own; } sub repl_methods { my ($x, $re) = split ' ', shift; $x =~ s/^\s+//; $x =~ s/\s+$//; if ($x =~ /^\$/) { $x = $REPL{eval}->("ref $x"); return 0 if $@; } $re ||= '.?'; $re = qr/$re/; print columnate sort { $a cmp $b } grep /$re/, methods $x; } sub as_boolean { my ($val, $cur) = @_; $val =~ s/\s+//g; length($val) ? $val : !$cur; } sub repl_wantarray { $WANTARRAY = shift || $WANTARRAY; $WANTARRAY = '' unless $WANTARRAY eq '@' || $WANTARRAY eq '$'; } sub repl_package { chomp(my $p = shift); $PACKAGE = $p; } sub repl_quit { $REPL_QUIT = 1; last repl; } sub repl_restart { do $INC{'Sepia.pm'}; if ($@) { print "Restart failed:\n$@\n"; } else { $REPL_LEVEL = 0; # ok? goto &Sepia::repl; } } sub repl_shell { my $cmd = shift; print `$cmd 2>& 1`; } # Stolen from Lexical::Persistence, then simplified. sub call_strict { my ($sub) = @_; # steal any new "my" variables my $pad = peek_sub($sub); for my $k (keys %$pad) { unless (exists $STRICT->{$k}) { if ($k =~ /^\$/) { $STRICT->{$k} = \(my $x); } elsif ($k =~ /^\@/) { $STRICT->{$k} = [] } elsif ($k =~ /^\%/) { $STRICT->{$k} = +{}; } } } # Grab its lexials lexalias($sub, $_, $STRICT->{$_}) for keys %$STRICT; $sub->(); } sub repl_eval { my ($buf) = @_; no strict; # local $PACKAGE = $pkg || $PACKAGE; if ($STRICT) { my $ctx = join(',', keys %$STRICT); $ctx = $ctx ? "my ($ctx);" : ''; if ($WANTARRAY eq '$') { $buf = 'scalar($buf)'; } elsif ($WANTARRAY ne '@') { $buf = '$buf;1'; } $buf = eval "sub { package $PACKAGE; use strict; $ctx $buf }"; if ($@) { print "ERROR\n$@\n"; return; } call_strict($buf); } else { $buf = "do { package $PACKAGE; no strict; $buf }"; if ($WANTARRAY eq '@') { eval $buf; } elsif ($WANTARRAY eq '$') { scalar eval $buf; } else { eval $buf; undef } } } sub repl_test { my ($buf) = @_; my @files; if ($buf =~ /\S/) { $buf =~ s/^\s+//; $buf =~ s/\s+$//; if (-f $buf) { push @files, $buf; } elsif (-f "t/$buf") { push @files, $buf; } } else { find({ no_chdir => 1, wanted => sub { push @files, $_ if /\.t$/; }}, Cwd::getcwd() =~ /t\/?$/ ? '.' : './t'); } if (@files) { # XXX: this is cribbed from an EU::MM-generated Makefile. system $^X, qw(-MExtUtils::Command::MM -e), "test_harness(0, 'blib/lib', 'blib/arch')", @files; } else { print "No test files for '$buf' in ", Cwd::getcwd, "\n"; } } sub repl_load { my ($file) = split ' ', shift; $file ||= "$ENV{HOME}/.sepia-save"; load(retrieve $file); } sub repl_save { my ($re, $file) = split ' ', shift; $re ||= '.'; $file ||= "$ENV{HOME}/.sepia-save"; store save($re), $file; } sub modules_matching { my $pat = shift; if ($pat =~ /^\/(.*)\/?$/) { $pat = $1; $pat =~ s#::#/#g; $pat = qr/$pat/; grep /$pat/, keys %INC; } else { my $mod = $pat; $pat =~ s#::#/#g; exists $INC{"$pat.pm"} ? "$pat.pm" : (); } } sub full_reload { my %save_inc = %INC; local %INC; for my $name (modules_matching $_[0]) { print STDERR "full reload $name\n"; require $name; } my @ret = keys %INC; while (my ($k, $v) = each %save_inc) { $INC{$k} ||= $v; } @ret; } sub repl_full_reload { chomp (my $pat = shift); my @x = full_reload $pat; print "Reloaded: @x\n"; } sub repl_reload { chomp (my $pat = shift); # for my $name (modules_matching $pat) { # delete $INC{$PAT}; # eval "require $name"; # if (!$@) { # (my $mod = $name) =~ s/ if ($pat =~ /^\/(.*)\/?$/) { $pat = $1; $pat =~ s#::#/#g; $pat = qr/$pat/; my @rel; for (keys %INC) { next unless /$pat/; if (!do $_) { print "$_: $@\n"; } s#/#::#g; s/\.pm$//; push @rel, $_; } } else { my $mod = $pat; $pat =~ s#::#/#g; $pat .= '.pm'; if (exists $INC{$pat}) { delete $INC{$pat}; eval 'require $mod'; import $mod unless $@; print "Reloaded $mod.\n" } else { print "$mod not loaded.\n" } } } sub repl_lsmod { chomp (my $pat = shift); $pat ||= '.'; $pat = qr/$pat/; my $first = 1; my $fmt = "%-20s%8s %s\n"; # my $shorten = join '|', sort { length($a) <=> length($b) } @INC; # my $ss = sub { # s/^(?:$shorten)\/?//; $_ # }; for (sort keys %INC) { my $file = $_; s!/!::!g; s/\.p[lm]$//; next if /^::/ || !/$pat/; if ($first) { printf $fmt, qw(Module Version File); printf $fmt, qw(------ ------- ----); $first = 0; } printf $fmt, $_, (UNIVERSAL::VERSION($_)||'???'), $INC{$file}; } if ($first) { print "No modules found.\n"; } } =item C Collect C<$warning> for later printing. =item C Print and clear accumulated warnings. =cut my @warn; sub sig_warn { push @warn, shift } sub print_warnings { if (@warn) { if ($ISEVAL) { my $tmp = "@warn"; print ';;;'.length($tmp)."\n$tmp\n"; } else { for (@warn) { # s/(.*) at .*/$1/; print "warning: $_\n"; } } } } sub repl_banner { print < Execute a command interpreter on standard input and standard output. If you want to use different descriptors, localize them before calling C. The prompt has a few bells and whistles, including: =over 4 =item Obviously-incomplete lines are treated as multiline input (press 'return' twice or 'C-c' to discard). =item C is overridden to enter a debugging repl at the point C is called. =back Behavior is controlled in part through the following package-globals: =over 4 =item C<$PACKAGE> -- evaluation package =item C<$PRINTER> -- result printer (default: dumper) =item C<$PS1> -- the default prompt =item C<$STRICT> -- whether 'use strict' is applied to input =item C<$WANTARRAY> -- evaluation context =item C<$COLUMNATE> -- format some output nicely (default = 1) Format some values nicely, independent of $PRINTER. Currently, this displays arrays of scalars as columns. =item C<$REPL_LEVEL> -- level of recursive repl() calls If zero, then initialization takes place. =item C<%REPL> -- maps shortcut names to handlers =item C<%REPL_DOC> -- maps shortcut names to documentation =item C<%REPL_SHORT> -- maps shortcut names to brief usage =back =back =cut sub repl_setup { $| = 1; if ($REPL_LEVEL == 0) { define_shortcuts; -f "$ENV{HOME}/.sepiarc" and eval qq#package $Sepia::PACKAGE; do "$ENV{HOME}/.sepiarc"#; warn ".sepiarc: $@\n" if $@; } Sepia::Debug::add_repl_commands; repl_banner if $REPL_LEVEL == 0; } $READLINE = sub { print prompt(); }; sub repl { repl_setup; local $REPL_LEVEL = $REPL_LEVEL + 1; my $in; my $buf = ''; $SIGGED = 0; my $nextrepl = sub { $SIGGED++; }; local (@_, $_); local *CORE::GLOBAL::die = \&Sepia::Debug::die; local *CORE::GLOBAL::warn = \&Sepia::Debug::warn; my @sigs = qw(INT TERM PIPE ALRM); local @SIG{@sigs}; $SIG{$_} = $nextrepl for @sigs; repl: while (defined(my $in = $READLINE->())) { if ($SIGGED) { $buf = ''; $SIGGED = 0; print "\n"; next repl; } $buf .= $in; $buf =~ s/^\s*//; local $ISEVAL; if ($buf =~ /^<<(\d+)\n(.*)/) { $ISEVAL = 1; my $len = $1; my $tmp; $buf = $2; while ($len && defined($tmp = read STDIN, $buf, $len, length $buf)) { $len -= $tmp; } } ## Only install a magic handler if no one else is playing. local $SIG{__WARN__} = $SIG{__WARN__}; @warn = (); unless ($SIG{__WARN__}) { $SIG{__WARN__} = 'Sepia::sig_warn'; } if (!$ISEVAL) { if ($buf eq '') { # repeat last interactive command $buf = $LAST_INPUT; } else { $LAST_INPUT = $buf; } } if ($buf =~ /^,(\S+)\s*(.*)/s) { ## Inspector shortcuts my $short = $1; if (exists $Sepia::RK{$short}) { my $ret; my $arg = $2; chomp $arg; $Sepia::REPL{$Sepia::RK{$short}}->($arg, wantarray); } else { if (grep /^$short/, keys %Sepia::REPL) { print "Ambiguous shortcut '$short': ", join(', ', sort grep /^$short/, keys %Sepia::REPL), "\n"; } else { print "Unrecognized shortcut '$short'\n"; } $buf = ''; next repl; } } else { ## Ordinary eval run_hook @PRE_EVAL; @res = $REPL{eval}->($buf); run_hook @POST_EVAL; if ($@) { if ($ISEVAL) { ## Always return results for an eval request Sepia::printer \@res, wantarray; Sepia::printer [$@], wantarray; # print_warnings $ISEVAL; $buf = ''; } elsif ($@ =~ /(?:at|before) EOF(?:$| at)/m) { ## Possibly-incomplete line if ($in eq "\n") { print "Error:\n$@\n*** cancel ***\n"; $buf = ''; } else { print ">> "; } } else { print_warnings; # $@ =~ s/(.*) at eval .*/$1/; # don't complain if we're abandoning execution # from the debugger. unless (ref $@ eq 'Sepia::Debug') { print "error: $@"; print "\n" unless $@ =~ /\n\z/; } $buf = ''; } next repl; } } if ($buf !~ /;\s*$/ && $buf !~ /^,/) { ## Be quiet if it ends with a semicolon, or if we ## executed a shortcut. Sepia::printer \@res, wantarray; } $buf = ''; print_warnings; } exit if $REPL_QUIT; wantarray ? @res : $res[0] } sub perl_eval { tolisp($REPL{eval}->(shift)); } =head2 Module browsing =over =item C<$status = html_module_list([$file [, $prefix]])> Generate an HTML list of installed modules, looking inside of packages. If C<$prefix> is missing, uses "about://perldoc/". If $file is given, write the result to $file; otherwise, return it as a string. =item C<$status = html_package_list([$file [, $prefix]])> Generate an HTML list of installed top-level modules, without looking inside of packages. If C<$prefix> is missing, uses "about://perldoc/". $file is the same as for C. =back =cut sub html_module_list { my ($file, $base) = @_; $base ||= 'about://perldoc/'; my $inst = inst(); return unless $inst; my $out; open OUT, ">", $file || \$out or return; print OUT ""; my $pfx = ''; my %ns; for (package_list) { push @{$ns{$1}}, $_ if /^([^:]+)/; } # Handle core modules. my %fs; undef $fs{$_} for map { s/.*man.\///; s|/|::|g; s/\.\d(?:pm)?$//; $_ } grep { /\.\d(?:pm)?$/ && !/man1/ && !/usr\/bin/ # && !/^(?:\/|perl)/ } $inst->files('Perl'); my @fs = sort keys %fs; print OUT qq{

Core Modules

    }; for (@fs) { print OUT qq{
  • $_}; } print OUT '

Installed Modules

    '; # handle the rest for (sort keys %ns) { next if $_ eq 'Perl'; # skip Perl core. print OUT qq{
  • $_
      } if @{$ns{$_}} > 1; for (sort @{$ns{$_}}) { my %fs; undef $fs{$_} for map { s/.*man.\///; s|/|::|g; s/\.\d(?:pm)?$//; $_ } grep { /\.\d(?:pm)?$/ && !/man1/ } $inst->files($_); my @fs = sort keys %fs; next unless @fs > 0; if (@fs == 1) { print OUT qq{
    • $fs[0]}; } else { print OUT qq{
    • $_
        }; for (@fs) { print OUT qq{
      • $_}; } print OUT '
      '; } } print OUT qq{
    } if @{$ns{$_}} > 1; } print OUT "
\n"; close OUT; $file ? 1 : $out; } sub html_package_list { my ($file, $base) = @_; return unless inst(); my %ns; for (package_list) { push @{$ns{$1}}, $_ if /^([^:]+)/; } $base ||= 'about://perldoc/'; my $out; open OUT, ">", $file || \$out or return; print OUT "
    "; my $pfx = ''; for (sort keys %ns) { if (@{$ns{$_}} == 1) { print OUT qq{
  • $ns{$_}[0]}; } else { print OUT qq{
  • $_
      }; print OUT qq{
    • $_} for sort @{$ns{$_}}; print OUT qq{
    }; } } print OUT "
\n"; close OUT; $file ? 1 : $out; } sub apropos_module { my $re = _apropos_re $_[0], 1; my $inst = inst(); my %ret; my $incre = inc_re; for ($inst->files('Perl', 'prog'), package_list) { if (/\.\d?(?:pm)?$/ && !/man1/ && !/usr\/bin/ && /$re/) { s/$incre//; s/.*man.\///; s|/|::|g; s/^:+//; s/\.\d?(?:p[lm])?$//; undef $ret{$_} } } sort keys %ret; } sub requires { my $mod = shift; my @q = $REQUIRES{$mod}; my @done; while (@q) { my $m = shift @q; push @done, $m; push @q, @{$REQUIRES{$m}}; } @done; } sub users { my $mod = shift; @{$REQUIRED_BY{$mod}} } 1; __END__ =head1 TODO See the README file included with the distribution. =head1 SEE ALSO Sepia's public GIT repository is located at L. There are several modules for Perl development in Emacs on CPAN, including L and L. For a complete list, see L. =head1 AUTHOR Sean O'Rourke, Eseano@cpan.orgE Bug reports welcome, patches even more welcome. =head1 COPYRIGHT Copyright (C) 2005-2011 Sean O'Rourke. All rights reserved, some wrongs reversed. This module is distributed under the same terms as Perl itself. =cut Sepia-0.992/lib/Sepia/CPAN.pm000644 000765 000765 00000007210 11307225127 015752 0ustar00seanoseano000000 000000 package Sepia::CPAN; use CPAN (); sub init { CPAN::HandleConfig->load; CPAN::Shell::setup_output; CPAN::Index->reload; } sub interesting_parts { my $mod = shift; # XXX: stupid CPAN.pm functions die for some modules... +{ map { $_ => scalar eval { $mod->$_ } } qw(id cpan_version inst_version fullname cpan_file)}; } # Only list the "root" module of each package, meaning either (1) the # module matching the dist name or (2) the module with the shortest # name, whichever comes first. # XXX: this is hacky. sub group_by_dist { my %h; for (@_) { my $cf = $_->{cpan_file}; if (!exists $h{$cf}) { $h{$_->{cpan_file}} = $_; } else { (my $tmp = $cf) =~ s/-/::/g; if ($tmp =~ /^\Q$h{$cf}{id}\E/) { next; # already perfect } elsif ($tmp =~ /^\Q$_->{id}\E/) { $h{$cf} = $_; # perfect } # elsif (length $h{$cf}{id} > length $_->{id}) { # $h{$cf} = $_; # short, at least... # } } } sort { $a->{id} cmp $b->{id} } values %h; } sub _list { CPAN::Shell->expand('Module', shift || '/./'); } sub list { group_by_dist map { interesting_parts $_ } _list @_ } sub _ls { my $want = shift; grep { # XXX: key to test in this order, because inst_file is slow. $_->userid eq $want } CPAN::Shell->expand('Module', '/./') } sub ls { group_by_dist map { interesting_parts $_ } _ls @_ } sub _desc { my $pat = qr/$_[0]/i; grep { $_->description && ($_->description =~ /$pat/ || $_->id =~ /$pat/) } CPAN::Shell->expand('Module', '/./'); } sub desc { group_by_dist map { interesting_parts $_ } _desc @_; } sub outdated { grep !$_->uptodate, list @_; } ## stolen from CPAN::Shell... sub readme { my $dist = CPAN::Shell->expand('Module', shift); return unless $dist; my $wantfile = shift; $dist = $dist->cpan_file; # my ($dist) = $self->id; my ($sans, $suffix) = $dist =~ /(.+)\.(tgz|tar[\._-]gz|tar\.Z|zip)$/; my ($local_file); my ($local_wanted) = File::Spec->catfile( $CPAN::Config->{keep_source_where}, "authors", "id", split(/\//,"$sans.readme")); $local_file = CPAN::FTP->localize("authors/id/$sans.readme", $local_wanted); ## Return filename rather than contents to avoid Elisp reader issues... if ($wantfile) { $local_file; } else { local (*IN, $/); open IN, $local_wanted; my $ret = ; close IN; $ret; } } sub perldoc { eval q{ use LWP::Simple; }; if ($@) { print STDERR "Can't get perldocs: LWP::Simple not installed.\n"; "Can't get perldocs: LWP::Simple not installed.\n"; } else { *perldoc = sub { get($CPAN::Defaultdocs . shift) }; goto &perldoc; } } sub install { my $dist = CPAN::Shell->expand('Module', shift); $dist->install if $dist; } # Based on CPAN::Shell::_u_r_common sub _recommend { my $pat = shift || '/./'; my (@result, %seen, %need); $version_undefs = $version_zeroes = 0; for my $module (CPAN::Shell->expand('Module',$pat)) { my $file = $module->cpan_file; next unless defined $file && $module->inst_file; $file =~ s!^./../!!; my $latest = $module->cpan_version; my $have = $module->inst_version; local ($^W) = 0; next unless CPAN::Version->vgt($latest, $have); push @result, $module; next if $seen{$file}++; $need{$module->id}++; } @result; } sub recommend { group_by_dist map { interesting_parts $_ } _recommend @_; } 1; Sepia-0.992/lib/Sepia/Debug.pm000644 000765 000765 00000031337 11445145021 016263 0ustar00seanoseano000000 000000 package Sepia::Debug; # use Sepia; use Carp (); # old Carp doesn't export shortmess. use Text::Abbrev; use strict; use vars qw($pack $file $line $sub $level $STOPDIE $STOPWARN); sub define_shortcut; *define_shortcut = *Sepia::define_shortcut; BEGIN { ## Just leave it on -- with $DB::trace = 0, there doesn't seem ## to be a performance penalty! ## ## Flags we use are (see PERLDBf_* in perl.h): ## 0x1 Debugging sub enter/exit (call DB::sub if defined) ## 0x2 per-line debugging (keep line numbers) ## 0x8 "preserve more data" (call DB::postponed??) ## 0x10 keep line ranges for sub definitions in %DB::sub ## 0x100 give evals informative names ## 0x200 give anon subs informative names ## 0x400 save source lines in %{"_<$filename"} $^P = 0x01 | 0x02 | 0x10 | 0x100 | 0x200; $STOPDIE = 1; $STOPWARN = 0; } sub peek_my { eval q{ require PadWalker }; if ($@) { +{ } } else { *peek_my = \&PadWalker::peek_my; goto &peek_my; } } # set debugging level sub repl_debug { debug(@_); } sub repl_backtrace { for (my $i = 0; ; ++$i) { my ($pack, $file, $line, $sub) = caller($i); last unless $pack; $Sepia::SIGGED && do { $Sepia::SIGGED--; last }; # XXX: 4 is the magic number... print($i == $level+4 ? "*" : ' ', " [$i]\t$sub ($file:$line)\n"); } } # return value from die sub repl_return { if ($Sepia::WANTARRAY) { @Sepia::REPL_RESULT = $Sepia::REPL{eval}->(@_); } else { $Sepia::REPL_RESULT[0] = $Sepia::REPL{eval}->(@_); } last repl; } use vars qw($DIE_TO @DIE_RETURN $DIE_LEVEL); $DIE_LEVEL = 0; sub xreturn { eval q{ use Scope::Upper ':all' }; if ($@) { print "xreturn requires Sub::Uplevel.\n"; return; } else { *xreturn = eval <<'EOS'; sub { my $exp = shift; $exp = '""' unless defined $exp; my $ctx = CALLER($level+4); # XXX: ok? local $Sepia::WANTARRAY = want_at $ctx; my @res = eval_in_env($exp, peek_my($level + 4)); print STDERR "unwind(@res)\n"; unwind @res, SUB UP $ctx; }; EOS goto &xreturn; } } sub repl_xreturn { print STDERR "XRETURN(@_)\n"; xreturn(shift); # XXX: doesn't return. Problem? print STDERR "XRETURN: XXX\n"; # ($DB::DIE_TO, $DB::DIE_RETURN[0]) = split ' ', $_[0], 2; # $DB::DIE_RETURN[0] = $Sepia::REPL{eval}->($DB::DIE_RETURN[0]); # last SEPIA_DB_SUB; } # { package DB; # no strict; sub sub { no strict; local $DIE_LEVEL = $DIE_LEVEL + 1; ## Set up a dynamic catch target SEPIA_DB_SUB: { return &$DB::sub; }; # we're dying! last SEPIA_DB_SUB if $DIE_LEVEL > 1 && defined $DIE_TO && $DB::sub !~ /(?:^|::)\Q$DIE_TO\E$/; undef $DIE_TO; wantarray ? @DIE_RETURN : $DIE_RETURN[0] } # } sub repl_dbsub { my $arg = shift; if ($arg) { *DB::sub = \⊂ } else { undef &DB::sub; } } sub repl_lsbreak { no strict 'refs'; for my $file (sort grep /^_ $b } @pts) { print "\t$_\t${$file}{$_}\n" } } } # evaluate EXPR in environment ENV sub eval_in_env { my ($expr, $env) = @_; local $Sepia::ENV = $env; my $str = ''; for (keys %$env) { next unless /^([\$\@%])(.+)/; $str .= "local *$2 = \$Sepia::ENV->{'$_'}; "; } $str = "do { no strict; package $Sepia::PACKAGE; $str $expr }"; return $Sepia::WANTARRAY ? eval $str : scalar eval $str; } sub tie_class { my $sig = substr shift, 0, 1; return $sig eq '$' ? 'Tie::StdScalar' : $sig eq '@' ? 'Tie::StdArray' : $sig eq '%' ? 'Tie::StdHash' : die "Sorry, can't tie $sig\n"; } ## XXX: this is a better approach (the local/tie business is vile), ## but it segfaults and I'm not sure why. sub eval_in_env2 { my ($expr, $env, $fn) = @_; local $Sepia::ENV = $env; my @vars = grep /^([\$\@%])(.+)/, keys %$env; my $body = 'sub { my ('.join(',', @vars).');'; for (@vars) { $body .= "Devel::LexAlias::lexalias(\$Sepia::ENV, '$_', \\$_);" } $body .= "$expr }"; print STDERR "---\n$body\n---\n"; $body = eval $body; $@ || $body->(); } # evaluate EXP LEV levels up the stack # # NOTE: We need to act like &repl_eval here and consider e.g. $WANTARRAY sub repl_upeval { # if ($Sepia::WANTARRAY) { return eval_in_env(shift, peek_my(4+$level)); # } else { # return scalar eval_in_env(shift, peek_my(4+$level)); # } } # inspect lexicals at level N, or current level sub repl_inspect { my $i = shift; if ($i =~ /\d/) { $i = 0+$i; } else { $i = $level + 3; } my $sub = (caller $i)[3]; if ($sub) { my $h = peek_my($i+1); print "[$i] $sub:\n"; for (sort keys %$h) { local @Sepia::res = $h->{$_}; print "\t$_ = ", $Sepia::PRINTER{$Sepia::PRINTER}->(), "\n"; } } } sub debug { my $new = Sepia::as_boolean(shift, $DB::trace); print "debug ", $new ? "ON" : "OFF"; if ($new == $DB::trace) { print " (unchanged)\n" } else { print "\n"; } $DB::trace = $new; } sub breakpoint_file { my ($file) = @_; return \%{$main::{"_<$file"}} if exists $main::{"_<$file"}; if ($file !~ /^\//) { ($file) = grep /^_<.*\/\Q$file\E$/, keys %main::; return \%{$main::{$file}} if $file; } return undef; } sub breakpoint { my ($file, $line, $cond) = @_; my $h = breakpoint_file $file; if (defined $h) { $h->{$line} = $cond || 1; return $cond ? "$file\:$line if $cond" : "$file\:$line"; } return undef; } sub repl_break { my $arg = shift; $arg =~ s/^\s+//; $arg =~ s/\s+$//; my ($f, $l, $cond) = $arg =~ /^(.+?):(\d+)\s*(.*)/; $cond = 1 unless $cond =~ /\S/; $f ||= $file; $l ||= $line; return unless defined $f && defined $l; my $bp = breakpoint($f, $l, $cond); print "break $bp\n" if $bp; } sub update_location { # XXX: magic numberage. ($pack, $file, $line, $sub) = caller($level + shift); } sub show_location { print "_<$file:$line>\n" if defined $file && defined $line; } sub repl_list { my @lines = eval shift; @lines = $line - 5 .. $line + 5 unless @lines; printf '%-6d%s', $_, ${"::_<$file"}[$_-1] for @lines; } sub repl_delete { my ($f, $l) = split /:/, shift; $f ||= $file; $l ||= $line; my $h = breakpoint_file $f; delete $h->{$l} if defined $h; } sub repl_finish { # XXX: doesn't handle recursion, but oh, well... my $sub = (caller $level + 4)[3]; if (exists $DB::sub{$sub}) { my ($file, $start, $end) = $DB::sub{$sub} =~ /(.*):(\d+)-(\d+)/; print STDERR "finish($sub): will stop at $file:$end\n"; # XXX: $end doesn't always work, since it may not have an # executable statement on it. breakpoint($file, $end-1, 'finish'); last repl; } else { print STDERR "yikes: @{[keys %DB::sub]}\n"; } } sub repl_toplevel { local $STOPDIE; die(bless [], __PACKAGE__); } sub add_repl_commands { define_shortcut 'delete', \&repl_delete, 'Delete current breakpoint.'; define_shortcut 'debug', \&repl_debug, 'debug [0|1]', 'Enable or disable debugging.'; define_shortcut 'break', \&repl_break, 'break [F:N [E]]', 'Break at file F, line N (or at current position) if E is true.'; define_shortcut 'lsbreak', \&repl_lsbreak, 'List breakpoints.'; # define_shortcut 'dbsub', \&repl_dbsub, '(Un)install DB::sub.'; %Sepia::RK = abbrev keys %Sepia::REPL; } sub add_debug_repl_commands { define_shortcut quit => \&repl_toplevel, 'quit', 'Quit the debugger, returning to the top level.'; define_shortcut toplevel => \&repl_toplevel, 'toplevel', 'Return to the top level.'; define_shortcut up => sub { $level += shift || 1; update_location(4); show_location; }, 'up [N]', 'Move up N stack frames.'; define_shortcut down => sub { $level -= shift || 1; $level = 0 if $level < 0; update_location(4); show_location; }, 'down [N]', 'Move down N stack frames.'; define_shortcut continue => sub { $level = 0; $DB::single = 0; last repl; }, 'Yep.'; define_shortcut next => sub { my $n = shift || 1; $DB::single = 0; breakpoint $file, $line + $n, 'next'; last repl; }, 'next [N]', 'Advance N lines, skipping subroutines.'; define_shortcut step => sub { $DB::single = shift || 1; last repl; }, 'step [N]', 'Step N statements forward, entering subroutines.'; define_shortcut finish => \&repl_finish, 'finish', 'Finish the current subroutine.'; define_shortcut list => \&repl_list, 'list EXPR', 'List source lines of current file.'; define_shortcut backtrace => \&repl_backtrace, 'show backtrace'; define_shortcut inspect => \&repl_inspect, 'inspect [N]', 'inspect lexicals in frame N (or current)'; define_shortcut return => \&repl_return, 'return EXPR', 'return EXPR'; # define_shortcut xreturn => \&repl_xreturn, 'xreturn EXPR', # 'return EXPR from the current sub.'; define_shortcut eval => \&repl_upeval, 'eval EXPR', 'evaluate EXPR in current frame'; # DANGER! } sub repl { show_location; local %Sepia::REPL = %Sepia::REPL; local %Sepia::REPL_DOC = %Sepia::REPL_DOC; add_debug_repl_commands; map { define_shortcut @$_ } @_; local %Sepia::RK = abbrev keys %Sepia::REPL; # local $Sepia::REPL_LEVEL = $Sepia::REPL_LEVEL + 1; local $Sepia::PS1 = "*$Sepia::REPL_LEVEL*> "; Sepia::repl(); } sub DB::DB { return if $Sepia::ISEVAL; local $level = 0; local ($pack, $file, $line, $sub) = caller($level); ## Don't do anything if we're inside an eval request, even if in ## single-step mode. return unless $DB::single || exists $main::{"_<$file"}{$line}; if ($DB::single) { return unless --$DB::single == 0; } else { my $cond = $main::{"_<$file"}{$line}; if ($cond eq 'next') { delete $main::{"_<$file"}{$line}; } elsif ($cond eq 'finish') { # remove temporary breakpoint and take one more step. delete $main::{"_<$file"}{$line}; $DB::single = 1; return; } else { return unless $Sepia::REPL{eval}->($cond); } } repl(); } my $MSG = "('\\C-c' to exit, ',h' for help)"; sub die { ## Protect us against people doing weird things. if ($STOPDIE && !$SIG{__DIE__}) { my @dieargs = @_; local $level = 0; local ($pack, $file, $line, $sub) = caller($level); my $tmp = "@_"; $tmp .= "\n" unless $tmp =~ /\n\z/; print "$tmp\tin $sub\nDied $MSG\n"; my $trace = $DB::trace; $DB::trace = 1; repl( [die => sub { local $STOPDIE=0; CORE::die @dieargs }, 'Continue dying.'], [quit => sub { local $STOPDIE=0; CORE::die @dieargs }, 'Continue dying.']); $DB::trace = $trace; } else { CORE::die(Carp::shortmess @_); } 1; } sub warn { ## Again, this is above our pay grade: if ($STOPWARN && $SIG{__WARN__} eq 'Sepia::sig_warn') { my @dieargs = @_; my $trace = $DB::trace; $DB::trace = 1; local $level = 0; local ($pack, $file, $line, $sub) = caller($level); print "@_\n\tin $sub\nWarned $MSG\n"; repl( [warn => sub { local $STOPWARN=0; CORE::warn @dieargs }, 'Continue warning.'], [quit => sub { local $STOPWARN=0; CORE::warn @dieargs }, 'Continue warning.']); $DB::trace = $trace; } else { ## Avoid showing up in location information. CORE::warn(Carp::shortmess @_); } } sub oops { my $sig = shift; if ($STOPDIE) { my $trace = $DB::trace; $DB::trace = 1; local $level = 0; local ($pack, $file, $line, $sub) = caller($level); print "@_\n\tin $sub\nCaught signal $sig\n"; repl( [die => sub { local $STOPDIE=0; CORE::die "Caught signal $sig; exiting." }, 'Just die.'], [quit => sub { local $STOPWARN=0; CORE::die "Caught signal $sig; exiting." }, 'Just die.']); $DB::trace = $trace; } else { Carp::confess "Caught signal $sig: continue at your own risk."; } } 1; Sepia-0.992/lib/Sepia/ReadLine.pm000644 000765 000765 00000002500 11651022662 016712 0ustar00seanoseano000000 000000 package Sepia::ReadLine; use Term::ReadLine; use Sepia; require Exporter; @ISA='Exporter'; @EXPORT='repl'; sub rl_complete { my ($text, $line, $start) = @_; my @xs; if (substr($line, 0, $start) =~ /^\s*$/ && $text =~ /^,(\S*)$/) { my $x = qr/^\Q$1\E/; @xs = map ",$_", grep /$x/, keys %Sepia::REPL; } else { my ($type, $str) = (substr $line, $start ?(($start-1), length($text)+1) : ($start, length($text))) =~ /^([\$\@\%\&]?)(.*)/; my %h = qw(@ ARRAY % HASH & CODE * IO $ VARIABLE); @xs = Sepia::completions $h{$type||'&'}, $str; } @xs; } sub repl { { package main; do $_ for @ARGV } $TERM = new Term::ReadLine $0; my $rl = Term::ReadLine->ReadLine; if ($rl =~ /Gnu/) { my $attr = $TERM->Attribs; $attr->{completion_function} = \&rl_complete; } elsif ($rl =~ /Perl/) { $readline::rl_completion_function = \&rl_complete; $readline::var_TcshCompleteMode = 1; # XXX: probably helpful... # } elsif (grep -x "$_/rlwrap", split ':', $ENV{PATH}) { # warn "Sepia::ReadLine: Falling back to rlwrap.\n"; } else { warn "Sepia::ReadLine: No completion with $rl.\n"; } $Sepia::READLINE = sub { $TERM->readline(Sepia::prompt()) }; goto &Sepia::repl; } 1; Sepia-0.992/lib/Sepia/Xref.pm000644 000765 000765 00000042260 11541416742 016146 0ustar00seanoseano000000 000000 package Sepia::Xref; =head1 NAME Sepia::Xref - Generates cross reference database for use by Perl programs. =head1 SYNOPSIS use Sepia::Xref qw(rebuild defs callers); rebuild; for (defs 'foo') { printf "%s:%d: sub %s\::foo() defined\n", @{$_}[0..2]; } for (callers 'foo') { printf "%s:%d: sub foo() called by %s\::%s().\n", @{$_}[0..3]; } =head1 DESCRIPTION C is intended as a programmatic interface to the information supplied by L. It is intended to be a component for interactive Perl development, with other packages providing a friendly interface to the raw information it extracts. C could be seen as an example of this sort of user-level tool, if it weren't for the fact that this module was created later, and stole most of its code. =cut # use Sepia '_apropos_re'; require Sepia; BEGIN { *_apropos_re = *Sepia::_apropos_re; } $VERSION = '0.65'; use strict; use Config; use Cwd 'abs_path'; use B qw(peekop class comppadlist main_start svref_2object walksymtable OPpLVAL_INTRO SVf_POK OPpOUR_INTRO OPf_MOD OPpDEREF_HV OPpDEREF_AV cstring); # stupid warnings... no warnings 'uninitialized'; =head2 Variables =over =item C<%call> A map of subs to call locations and callers =item C<%callby> A map of subs to subs called. =item C<%var_use> A map of global/package variables to uses. =item C<%var_def> A map of global/package variables to definitions (usually empty, since it only picks up local (...) declarations. =back =cut our %call; our %callby; our %var_def; our %var_use; require Exporter; our @ISA = 'Exporter'; my @most = qw(redefined forget rebuild callers callees var_defs var_uses var_apropos); our @EXPORT_OK = (@most, qw(xref_definitions xref_object xref_main %call %callby %var_use %var_def)); our %EXPORT_TAGS = (':all' => \@EXPORT_OK, ':most' => \@most); ###################################################################### ## Xref state variables: sub UNKNOWN { ["?", "?", "?"] } my @pad; # lexicals in current pad # as ["(lexical)", type, name] my @padval; our %done; # keyed by $$op: set when each $op is done my $top = UNKNOWN; # shadows top element of stack as # [pack, type, name] (pack can be "(lexical)") our $file; # shadows current filename my $line; # shadows current line number our $subname; # shadows current sub name our @todo = (); # List of CVs that need processing my $lastclass; # last bareword seen after entersub. our $DEBUG = 0; sub dprint { my $type = shift; my $res = "@_"; $res =~ s/%//g; # XXX: work around EPL's misuse of (message) print STDERR "@_" if $DEBUG =~ /$type/; } my %code = (intro => "i", used => "", subdef => "s", subused => "&", formdef => "f", meth => "->"); =over 4 =head2 Functions =item C XXX: it turns out that rooting around trying to figure out the file ourselves is more reliable than what we grab from the op. Are we doing this wrong? =cut sub guess_module_file { my ($pack, $ofile) = @_; my $file; # XXX: is this why we get the bogus defs? return undef if $ofile =~ /Exporter\.pm$/; # Try for standard translation in %INC: (my $fn = $pack) =~ s/::/\//g; return unless $fn; # stupid warnings... if (exists $INC{"$fn.pm"}) { return $INC{"$fn.pm"}; } # Try what they told us: chomp $ofile; return $ofile if -f $ofile; # Try "parent" packages: while ($fn =~ s|/?[^/]+$|| && !$file) { $file ||= $INC{"$fn.pm"}; } if ($file && $file !~ /^\//) { $file = abs_path($file); } if (!$file || !-f $file) { undef $file; } $file; } # XXX: should weed through the code below so it only generates decent # package names, but this will fix it for now. sub realpack { my $p = shift; if (!defined $p || $p eq '?' || $p eq '(method)') { return undef; } elsif ($p eq '') { return 'main'; } else { return $p; } } # Turn a possibly-qualified name into a package and basename. sub split_name { local $_ = shift; my ($p, $s); if (/^(.*)::(.+)$/) { ($p, $s) = ($1, $2); } else { ($p, $s) = ('main', $_); } undef $s if $s eq '?'; ($p, $s); } sub process { my ($var, $event) = @_; my ($pack, $type, $name) = @$var; $pack = realpack($pack); dprint 'loud', "Processing $event: @$var ($subname)"; if ($type eq "*") { if ($event eq "used" || $event eq 'set') { return; } elsif ($event eq "subused") { $type = "&"; } elsif ($event eq "meth") { $type = '->'; } } $type =~ s/(.)\*$/$1/g; $file = guess_module_file($pack, $file); if (($type eq '&' || $type eq '->') && $subname ne '(definitions)') { # Handle caller/callee relations my ($spack, $sname) = split_name($subname); $call{$name}{$pack}{$subname} = 1; $callby{$sname}{$spack}{"$pack\::$name"} = 1; } elsif ($type eq 's' || $subname eq '(definitions)') { # definition } elsif ($name !~ /^[\x00-\x1f^] | ^\d+$ | ^[\W_]$ | ^(?:ENV|INC|STD(?:IN|OUT|ERR)|SIG)$ /x && realpack($pack)) { # Variables, but ignore specials and lexicals my ($spack, $sname) = split_name($subname); if ($event eq 'intro') { $var_def{$name}{$pack} = { file => $file, package => $spack, line => $line, sub => $sname, }; } elsif ($event eq 'used' || $event eq 'set') { push @{$var_use{$name}{$pack}}, { file => $file, package => $spack, line => $line, sub => $sname, assign => ($event eq 'set'), }; } else { dprint 'ignore', "Ignoring var event $event"; } } else { dprint 'ignore', "Ignoring $type event $event"; } } sub load_pad { my $padlist = shift; my ($namelistav, $vallistav, @namelist, $ix); @pad = (); @padval = (); return if class($padlist) eq "SPECIAL"; ($namelistav,$vallistav) = $padlist->ARRAY; @namelist = $namelistav->ARRAY; for ($ix = 1; $ix < @namelist; $ix++) { my $namesv = $namelist[$ix]; next if class($namesv) eq "SPECIAL"; my ($type, $name) = $namesv->PV =~ /^(.)([^\0]*)(\0.*)?$/; $pad[$ix] = [undef, $type, $name]; } if ($Config{useithreads}) { my (@vallist); @vallist = $vallistav->ARRAY; for ($ix = 1; $ix < @vallist; $ix++) { my $valsv = $vallist[$ix]; next unless class($valsv) eq "GV"; # these pad GVs don't have corresponding names, so same @pad # array can be used without collisions # XXX: for some reason, on 5.10 $valsv->STASH can be a # B::SPECIAL, which doesn't have a name. # XXX: this segfaults on 5.10 for some reason while # traversing File::Find::contract_name from main next if ref $valsv->STASH eq 'B::SPECIAL'; $pad[$ix] = [$valsv->STASH->NAME, "*", $valsv->NAME]; } } @padval = $vallistav->ARRAY; } sub xref { my $start = shift; my $op; for ($op = $start; $$op; $op = $op->next) { last if $done{$$op}++; my $opname = $op->name; if ($opname =~ /^(or|and|mapwhile|grepwhile|range|cond_expr)$/) { xref($op->other); } elsif ($opname eq "match" || $opname eq "subst") { xref($op->pmreplstart); } elsif ($opname eq "substcont") { xref($op->other->pmreplstart); $op = $op->other; redo; } elsif ($opname eq "enterloop") { xref($op->redoop); xref($op->nextop); xref($op->lastop); } elsif ($opname eq "subst") { xref($op->pmreplstart); } else { no strict 'refs'; my $ppname = "pp_$opname"; &$ppname($op) if defined(&$ppname); } } } sub xref_cv { my $cv = shift; my $pack = $cv->GV->STASH->NAME; local $subname = ($pack eq "main" ? "" : "$pack\::") . $cv->GV->NAME; load_pad($cv->PADLIST); xref($cv->START); } sub xref_object { my $cvref = shift; local (@todo, %done); my $cv = svref_2object($cvref); xref_cv($cv); dprint 'todo', "todo = (@todo)"; my $gv = $cv->GV; process([$gv->STASH->NAME, '&', $gv->NAME], 'subdef'); } sub xref_main { $subname = "(main)"; load_pad(comppadlist); xref(main_start); while (@todo) { xref_cv(shift @todo); } } sub pp_pushmark { my $op = shift; my ($class, $meth); if (($class = $op->next)->name eq 'const') { my $sv = $class->sv; my $classname; # constant could be in the pad (under useithreads) if (class($sv) ne "SPECIAL" && $sv->FLAGS & SVf_POK) { $classname = $sv->PV; } else { my $pv = $padval[$class->targ]; if (class($pv) =~ /^PV/ && class($sv) eq 'SPECIAL' ## bareword flag -- should use this? # && ($op->private & 64) ) { $classname = $pv->PV; } } $lastclass = $classname; } } sub pp_nextstate { my $op = shift; $file = $op->file; die "pp_nextstate: $file" if $file =~ /::/; $line = $op->line; $top = UNKNOWN; } sub use_type($) { my ($op) = @_; if ($op->private & (OPpLVAL_INTRO | OPpOUR_INTRO)) { 'intro'; } elsif ($op->flags & OPf_MOD && !($op->private & (OPpDEREF_HV | OPpDEREF_AV))) { 'set'; } else { 'used'; } } sub pp_padsv { my $op = shift; $top = $pad[$op->targ]; # process($top, $op->private & OPpLVAL_INTRO ? "intro" : "used"); } sub pp_padav { pp_padsv(@_) } sub pp_padhv { pp_padsv(@_) } sub deref { my ($op, $var, $as) = @_; $var->[1] = $as . $var->[1]; process($var, use_type $op); } sub pp_rv2cv { deref(shift, $top, "&"); } sub pp_rv2hv { deref(shift, $top, "%"); } sub pp_rv2sv { deref(shift, $top, "\$"); } sub pp_rv2av { deref(shift, $top, "\@"); } sub pp_rv2gv { deref(shift, $top, "*"); } sub pp_gvsv { my $op = shift; my $gv; if ($Config{useithreads}) { $top = $pad[$op->padix]; $top = UNKNOWN unless $top; $top->[1] = '$'; } else { $gv = $op->gv; $top = [$gv->STASH->NAME, '$', $gv->SAFENAME]; } process($top, use_type $op); } sub pp_gv { my $op = shift; my $gv; if ($Config{useithreads}) { $top = $pad[$op->padix]; $top = UNKNOWN unless $top; $top->[1] = '*'; } else { $gv = $op->gv; $top = [$gv->STASH->NAME, "*", $gv->SAFENAME]; } process($top, use_type $op); } sub pp_method { my $op = shift; $top = [$lastclass || "(method)", "->".$top->[1], $top->[2]]; dprint 'method', "pp_method($top->[1])"; undef $lastclass; } sub pp_method_named { use Data::Dumper; my $op = shift; my $sv = $op->sv; my $pviv = $padval[$op->targ]; if ($pviv && class($pviv) =~ /^PV/) { my $name = $pviv->PV; dprint 'method_named', $op->targ.": $name"; undef $top->[2] if $top->[2] eq '?'; $top = [$lastclass || "(method)", '->', $name]; undef $lastclass; } else { dprint 'method_named', "method_named: wtf: sizeof padval = ".@padval; } } sub pp_entersub { my $op = shift; if ($top->[1] =~ /^(?:m$|->)/) { dprint 'method', "call to (@$top) from $subname"; process($top, "meth"); } else { process($top, "subused"); } undef $lastclass; $top = UNKNOWN; } # # Stuff for cross referencing definitions of variables and subs # sub B::GV::xref { my $gv = shift; my $cv = $gv->CV; $file = $gv->FILE; # XXX: sometimes the "file" is a module. Why? $line = $gv->LINE; if ($$cv) { #return if $done{$$cv}++; process([$gv->STASH->NAME, "&", $gv->NAME], "subdef"); push(@todo, $cv); } my $form = $gv->FORM; if ($$form) { return if $done{$$form}++; process([$gv->STASH->NAME, "", $gv->NAME], "formdef"); } } ## Exclude all pragmatic modules (lowercase first letter) and the ## following problematic things, which tend to cause more harm than ## good when they get xref'd: my %exclude; BEGIN { undef $exclude{"$_\::"} for qw(B O AutoLoader DynaLoader XSLoader Config DB VMS FileHandle Exporter Carp PerlIO::Layer); } sub xref_exclude { my $x = shift; $x =~ /^[a-z]/ || exists $exclude{$x}; } sub xref_definitions { my ($pack, %exclude); $subname = "(definitions)"; no strict qw(vars refs); walksymtable(\%{"main::"}, "xref", sub { !xref_exclude($_[0]) }); } =item C Rebuild the Xref database. =cut sub rebuild { %call = (); %callby = (); %var_def = (); %var_use = (); local (@todo, %done); xref_definitions; xref_main; 1; } sub unmention { my ($h, $K, $V, $pack) = @_; dprint 'unmention', "Unmentioning $K => $V"; while (my ($k, $v) = each %$h) { while (my ($k2, $v2) = each %$v) { if (ref $v2 eq 'ARRAY') { $v->{$k2} = [grep { $_->{$K} ne $V || !$pack || $pack ne $_->{package} } @$v2]; delete $v->{$k2} unless @{$v->{$k2}}; } else { delete $v->{$k2} if $k2 eq $V; } } delete $h->{$k} unless keys %{$h->{$k}}; } } sub unmention_sub { my ($h, $sub, $pack) = @_; dprint 'unmention', "Unmentioning $pack\::$sub"; if ($pack) { delete $h->{$sub}{$pack}; delete $h->{$sub} unless keys %{$h->{$sub}}; } else { delete $h->{$sub}; } } =item C Forget that C<$func> was defined. =cut sub forget { my ($obj, $pack) = @_; unmention_sub \%callby, @_; unmention \%call, 'sub', @_; unmention \%var_use, 'sub', @_; unmention \%var_def, 'sub', @_; } =item C Recompute xref info for C<$func>, or C<$pack::$func> if C<$pack> given. =cut sub redefined { forget @_; { no strict 'refs'; my ($sub, $pack) = @_; $pack ||= 'main'; $sub = $pack eq 'main' ? $sub : "$pack\::$sub"; local $subname = '(definitions)'; xref_object \&$sub; } } ###################################################################### # Apropos and definition-finding: sub _ret_list { my ($h, $sub, $mod) = @_; if ($sub =~ /^(.*)::([^:]+)$/) { $sub = $2; $mod = $1; } $h = $h->{$sub}; my @r; if ($mod) { @r = keys %{$h->{$mod}}; } else { # @r = map { @$_ } values %$h; my %h; @h{keys %$_} = 1 for values %$h; @r = keys %h; } @r = sort @r; return wantarray ? @r : \@r; } sub _var_ret_list { my ($h, $v, $mod, $assign) = @_; if ($v =~ /^(.*)::([^:]+)$/) { $mod = $1; $v = $2; } $h = $h->{$v}; my @r; if ($mod) { @r = exists $h->{$mod} ? @{$h->{$mod}} : (); } else { ## XXX: Need to revisit when this is/isn't an array! @r = map { ref $_ eq 'ARRAY' ? @$_ : $_ } values %$h; } @r = grep $_->{assign}, @r if $assign; @r = map { [@{$_}{qw(file line sub package)}] } @r; return wantarray ? @r : \@r; } =item C List callers of C<$func>. =cut sub callers { _ret_list \%call, @_; } =item C List callees of C<$func>. =cut sub callees { _ret_list \%callby, @_; } =item C Find locations where C<$var> is defined. =cut sub var_defs { return _var_ret_list \%var_def, @_; } =item C Find locations where C<$var> is used. =cut sub var_uses { return _var_ret_list \%var_use, @_; } =item C Find locations where C<$var> is assigned to. =cut sub var_assigns { my ($v, $pack) = @_; return _var_ret_list \%var_use, $v, $pack, 1; } =item C List the modules defined in file C<$file>. =cut sub file_modules { my $file = shift; eval { require Module::Info; my $mod = Module::Info->new_from_file(abs_path($file)); if ( $mod ) { return $mod->packages_inside(); } } } =item C Find variables matching C<$expr>. =cut sub _apropos { my ($h, $re, $mod) = @_; my @r = do { if($re) { $re = _apropos_re($re); sort grep /$re/, keys %$h; } else { sort keys %$h; } }; if ($mod) { $mod = _apropos_re($mod); my %r; for (@r) { my $sn = $_; for (keys %{$h->{$_}}) { $r{$_ eq 'main' ? $sn : "$_\::$sn"} = 1 if /$mod/; } } @r = sort keys %r; } return wantarray ? @r : \@r; } sub var_apropos { _apropos \%var_use, @_; } 1; __END__ =back =head1 EXPORTS Nothing by default, but all sub and variable described above can be imported. C also defines the tags C<:most> for the above-listed functions, and C<:all> for those and the variables as well. =head1 BUGS =over 4 =item See L. =item module names are ignored when looking up a sub. =item file and line number guessing is evil Both should be done more cleanly and effectively. This is a hack because I don't quite understand what perl saves. We should be able to do as well as its warning messages. =item Some packages are not xref'd. Some "internal" packages are deliberately not cross-referenced, either because they are hairy and cause us problems, or because they are so commonly included as to be uninteresting. The current list includes all pragmatic modules, plus: B, O, AutoLoader, DynaLoader, XSLoader, Config, DB, VMS, FileHandle, Exporter, Carp, PerlIO::Layer. =item Tree-view is not fully functional Ideally, clicking the function names in tree view would take you to that function. This doesn't work. Also, more keys (like "q" to quit) should be implemented. =back =head1 SEE ALSO C, of which C is a bastard child. =head1 AUTHOR L by Malcolm Beattie, m(angl|odifi)ed by Sean O'Rourke (seano@cpan.org). =cut