NAME
Devel::PerlySense - IntelliSense for Perl
DESCRIPTION
PerlySense is an IntelliSense style utility for editors.
Conveniently navigate and browse the code and documentation of your
project and Perl installation.
SYNOPSIS
From Emacs
C-p C-c -- Class Overview -- Show information about the Class at point
or the current Class.
C-p C-d -- Smart docs -- Show docs (POD/signature/etc) for the symbol
(module/method/sub) at point. A doc hint is displayed in the message
area (for methods and subs), or a new POD buffer is created (for
modules).
C-p C-g -- Smart go to -- Open file at proper location for module,
method/sub declaration for the symbol (module/method/sub) at point. If
no sub declaration is available (like for generated getters/setters),
any appropriate POD is used instead.
C-p m f -- Perl Module open File -- Open the source file of the module
at point.
As you can see, PerlySense duplicates some of the functionality in
cperl-mode, and does more in certain areas.
From Vim
There is no integraton with Vim available. Well, yet.
Someone may want to write it.
From other editors
Any editor that is programmable and that can call a shell script could
take advantage of PerlySense to implement something similar to the Emacs
functionality. And most editors are programmable by the authors, if not
by the users.
From the command line
This is not very convenient unless you let your editor do it. See the
"perly_sense" in bin script on how to do this.
There is one useful command though; cache all the modules in @INC:
perly_sense process_inc
From Perl
See the source of the "perly_sense" in bin script, or the t directory.
INSTALLATION
Install required modules from CPAN.
Emacs installation
Copy the file editors/emacs/perly-sense.el to your Emacs script dir
(which should be in the load-path), and add this to the end of your
.emacs config file:
; PerlySense
(load "perly-sense")
(global-unset-key "\C-p")
(global-set-key (kbd "\C-p \C-d") 'perly-sense-smart-docs-at-point)
(global-set-key (kbd "\C-p \C-g") 'perly-sense-smart-go-to-at-point)
Adjust according to preference: the key mappings will replace the C-p
command which obviously be fantastically annoying for you if you don't
use the arrow keys to move around. This is just how I use Emacs, and I
expect this will make you go *&&*%!
Calm down. The default key bindings will be changed before the first
real release. Suggestions welcome.
GETTING STARTED WITH EMACS
Open one of your Perl source files.
Class Overview
Pressing C-p C-c will bring up the Class Overview of the Class name at
point, or otherwise the current Class (the active Package).
The Inheritance section shows all Base classes of the Class.
The NeighbourHood section shows three columns (1: parent dir, 2: current
dir, 3: subdirectories) with Classes located nearby.
When in the Class Overview buffer:
g -- Go to the thing at point. RET does the same.
d -- Documentation for the thing at point.
c -- Class Overview for the thing at point.
I -- Move point to the Inheritance heading in the buffer.
H -- Move point to the NeighbourHood (mnemonic: 'Hood) heading.
M -- Move point to the Methods heading.
N -- Move point to the 'new' method in the buffer (if any).
q -- Quit the Class Overview buffer.
Smart docs
C-p C-d is the "Smart docs" command. It brings up documentation for
what's at point.
Put the cursor on the "method" word of a $self->method call and press
C-p C-d and wait until a documentation hint for the method call is
displayed briefly in the message buffer. PerlySense will look in base
classes if the method can't be found in the current class.
Put the cursor on the "method" word of an $object->method call and press
C-p C-d to see the docs hint. PerlySense will look through all your
"use" modules (and their base classes) for the method call and try to
identify the best match.
Note! The first time each module is parsed this will take a second or
two, and the very first time you run the command with lots of "use"
modules it's bound to take longer than that.
Put the cursor on a module name and press C-p C-d to bring up a new
buffer with the POD for that module (this is similar to the cperl-mode
feature, only a) not as good, but b) it works on Windows).
Press C-p C-d with nothing under the cursor brings up a POD buffer for
the current file.
Smart go to
C-p C-g is the "Smart go to" command. It's similar to Smart Docs, but
instead of bringing the docs to you, it brings you to the definition of
what's at point.
The definition can be either the sub declaration, or if the declaration
can't be found (like for auto-generated getters/setters, autoloaded subs
etc), the POD documentation for the sub.
Before you go anywhere the mark is set. Go back to earlier marks
globally with C-x C-SPC, or locally with C-u C-SPC.
ON PARSING PERL
Oh, that old topic again...
Well, since Perl is so dynamic, a perfect static analysis of the source
is impossible. But not unusably so. Well, hopefully.
Because of this PerlySense is not about exact rules, but about
heuristics and a 90% solution that isn't perfect, but good-enough.
Sometimes when PerlySense can't make a decision, you're expected to chip
in and tell it what you meant.
If it works for you, brilliant, use it to be more productive.
PerlySense tries to take advantage of the fact that Perl code is more
than the plain source. The source lives in a context of POD and a
directory structure and... well, oher source code.
SEE ALSO
sepia - similar effort
PPI - excellent for parsing Perl
CPANXR - also uses PPI for cross referencing the CPAN
<http://www.DarSerMan.com/Perl/Oasis/> - Win32 class browser/IDE.
Earlier (a lot) work by me.
AUTHOR
Johan Lindström, "<johanl[ÄT]DarSerMan.com>"
BUGS AND CAVEATS
BUG REPORTS
Please report any bugs or feature requests to
"bug-devel-perlysense@rt.cpan.org", or through the web interface at
<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Devel-PerlySense>. I
will be notified, and then you'll automatically be notified of progress
on your bug as I make changes.
CAVEATS
Tab/space isn't supported by PPI yet, but it's supposed to be. So using
Tab instead of spaces won't work properly.
KNOWN BUGS
PPI is kinda slow for large documents. Lots of objects being created
etc.
There are certainly edge cases. Bug reports with failing tests
appreciated :)
ACKNOWLEDGEMENTS
Peter Liljenberg for his elisp fu.
COPYRIGHT & LICENSE
Copyright 2007 Johan Lindström, All Rights Reserved.
This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
*** THE FOLLOWING IS DEVELOPER DOCUMENTATION ***
PROPERTIES
oCache
Cache::Cache object, or undef if no cache is active.
Default: undef
API METHODS
new()
Create new PerlySense object.
oDocumentParseFile($file)
Parse $file into a new PerlySense::Document object.
Return the new object.
Die on errors (like if the file wasn't found).
podFromFile(file => $file)
Return the pod in $file as text, or die on errors.
Die if $file doesn't exist.
oLocationSmartGoTo(file => $fileOrigin, row => $row, col => $row)
Look in $file at location $row/$col and determine what is there.
Depending on what's there, find the source declaration/whatever, find it
and return an Devel::PerlySense::Document::Location object.
Currently supported:
$self->method, look in current file and base classes. If no sub can
be found, look for POD.
$object->method, look in current file and used modules. If no sub
can be found, look for POD.
Module::Name (bareword)
Module::Name (as the only contents of a string literal)
If there's nothing at $row/col, or if the source can't be found, return
undef.
Die if $file doesn't exist, or on other errors.
oLocationSmartDoc(file => $fileOrigin, row => $row, col => $row)
Look in $file at location $row/$col and determine what is there.
Depending on what's there, find the documentation for it and return a
Document::Location object with the following rhProperty keys set:
text - the docs text
found - "method" | "module"
docType - "hint" | "document"
name - the name of the thing found
Currently supported:
Same as for oLocationSmartGoTo
If there's nothing at $row/col, use the current document.
Die if $file doesn't exist, or on other errors.
classNameAt(file => $fileOrigin, row => $row, col => $row)
Look in $file at location $row/$col and determine what class name that
is.
Return the class name or "" if it's package main.
Die if $file doesn't exist, or on other errors.
classAt(file => $fileOrigin, row => $row, col => $row)
Look in $file at location $row/$col and determine what PerlySelse::Class
that is.
Return the Class object or undef if it's package main.
Die if $file doesn't exist, or on other errors.
classByName(name => $name, dirOrigin => $dirOrigin)
Find the file that contains the Class $name, starting at $dirOrigin.
Return the Class object or undef if it couldn't be found.
Die on errors.
fileFindModule(nameModule => $nameModule, dirOrigin => $dirOrigin)
Find the file containing the $nameModule given the $dirOrigin.
Return the absolute file name, or undef if none could be found. Die on
errors.
oDocumentFindModule(nameModule => $nameModule, dirOrigin => $dirOrigin)
Find the file containing the $nameModule given the $dirOrigin.
Return a parsed PerlySense::Document, or undef if none could be found.
Die on errors.
IMPLEMENTATION METHODS
fileFindLookingAround($fileModuleBase, $dirOrigin)
Find the file containing the $nameModule given the $dirOrigin.
Return the file name relative to $dirOrigin, or undef if none could be
found. Die on errors.
fileFindLookingInInc($fileModuleBase)
Find the file containing the $nameModule in @INC.
Return the absolute file name, or undef if none could be found. Die on
errors.
fileFromModule($nameModule)
Return the $nameModule converted to a file name (i.e. with dirs and .pm
extension).
fileFoundInDir($dir, $fileModuleBase)
Look if $fileModuleBase is located in $dir. If it is, return the file
name relative to $dirOrigin.
Return the absolute file name, or "" if not found at $dir.
textFromPod($pod)
Return $pod rendered as text, or die on errors.
oLocationRenderPodToText($oLocation)
Render the $oLocation->rhProperty->{pod} and put it in
rhProperty->{text}.
Return the same (modified) $oLocation object, or undef if no
rhProperty->{pod} property ended up as text (after this operation, there
is content in rhProperty->{text}).
Return undef if $oLocation is undef.
Die on errors.
aDocumentFindModuleWithInterface(raNameModule => $raNameModule, raMethodRequired => $raMethodRequired, raMethodNice => $raMethodNice, dirOrigin => $dirOrigin)
Return a list with Devel::PerlySense::Document objects that support all
of the methods in $raMethodRequired and possibly the methods in
$raMethodNice. Look in modules in $raNameModule.
The list is sorted with the best match first.
If the document APIs have one or more base classes, look in the @ISA
(depth-first, just like Perl (see perldoc perltoot)).
Warn on some failures to find the location. Die on errors.
aApiOfClass(file => $fileOrigin, row => $row, col => $row)
Look in $file at location $row/$col and determine what package is there.
Return a two item array with (Package name,
Devel::PerlySense::Document::Api object with the likely API of that
class), or () if none was found.
Die if $file doesn't exist, or on other errors.
aDocumentGrepInDir(dir => $dir, rsGrepFile => $rsGrepFile, rsGrepDocument => $rsGrepDocument)
Return a list with Devel::PerlySense::Document objects found under the
$dir, and that return true for the grep sub $rsGrepFile and
$rsGrepDocument.
If any found file couldn't be parsed, skip it silently from the list.
CACHE METHODS
cacheSet(file => $file, key => $key, value => $valuex)
If the oCache isn't undef, store the $value in the cache under the total
key of ($file, $file's timestamp, $key, and the PerlySense VERSION).
$value should be a scalar or reference which can be freezed.
$file must be an existing file.
Return 1 if the $value was stored, else 0. Die on errors.
cacheGet(file => $file, key => $key)
If the oCache isn't undef, get the value in the cache under the total
key of ($file, $file's timestamp, $key) and return it.
$file must be an existing file.
Return the value, or undef if the value could not be fetched. Die on
errors.
cacheKeyTotal($file, $key)
If oCache is undef, return undef.
Otherwise, return the total key of ($file, $file's timestamp, $key, and
the PerlySense VERSION).
$file must be an existing file.
Die on errors.