NAME Devel::PerlySense - Perl IDE with Emacs frontend DESCRIPTION PerlySense is a Perl IDE backend that integrates with editor frontends, currently Emacs. Conveniently navigate and browse the code and documentation of your project and Perl installation. Run tests and scripts and syntax check source with easy navigation to errors/warnings/failing tests. Automate common editing tasks. Highlight syntax errors, warnings and Perl::Critic complaints in the source while editing. SYNOPSIS From Emacs C-o C-o -- Overview -- Show information about the Class at point or the current Class. C-o C-d -- Docs -- Show docs (POD/signature/etc) for the symbol (module/method/sub) at point. A doc hint is displayed in the echo area (for methods and subs), or a new POD buffer is created (for modules). C-o d i -- Document Inheritance -- Show the Inheritance hierarchy for the current Class in the echo area. C-o d u -- Document 'use Module' statements in the echo area. C-o C-g -- 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-o g u -- Go to the 'use Module' section of the current buffer. C-o g n -- Go To 'new' -- Go to the 'new' method of the current class. C-o g b -- Go To Base Class -- Open the file of the base class of the current class. This will take you up one level in the inheritance hierarchy. C-o g m -- Go To Module -- Open the source file of the module at point. C-o g v -- Go To Version Control -- Go to the Project view of the current Version Control system. C-o C-r -- Run file -- Run the current file using the Compilation mode and the settings appropriate for the source type (Test, Module, etc.). Highlight errors and jump to source with C-c C-c. C-o e m u -- Edit - Move Use Statement -- Move the 'use Module' statement at point to the 'use Module' section at the top. C-o e t c -- Edit Test Count -- Increase the test count (e.g. "tests => 43") C-o a t -- Assist With Test Count -- Synchronize invalid test count in .t file with the *compilation* buffer. Flymake may be used to highlight syntax errors and warnings in the source while editing (continously or at every save). From Vim There is no integraton with Vim available. Well, not properly anyway. If you pass the option --io_type=editor_vim to perly_sense, the output format will use the Vim serializer. But not all commands use this format, and the Vim side of things aren't done quite yet. From other editors Any editor that is programmable and that can call a shell script could take advantage of at least some parts 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 * Create Project perly_sense create_project [--dir=DIR] Create a PerlySense project in DIR (default is current dir). If there is already a project.yml file, back it up with a datestamp first. (Note that you don't need to create a project before start using PerlySense. Read more below). * Process Project Source Files perly_sense process_project Cache all modules in the project. (not implemented) * Process Source Files in @INC perly_sense process_inc Cache all the modules in @INC. This is a useful thing to do after installation (and after each upgrade), but it will take a wile so put it in the background and let it churn away at those modules. * Unix perly_sense process_inc & # (well, you knew that already) * Windows start /MIN perly_sense process_inc * Get Info perly_sense info Display useful information about what the current project directory, user home directory, etc. is. INSTALLATION perly_sense installation Install required modules from CPAN. Emacs installation Make sure the Devel::PerlySense CPAN module is installed, it contains the required elisp files which will be loaded automatically with the following in your .emacs config file: ;; *** PerlySense Config *** ;; ** PerlySense ** ;; The PerlySense prefix key (unset only if needed, like for \C-o) (global-unset-key "\C-o") (setq perly-sense-key-prefix "\C-o") ;; ** Flymake ** ;; Load flymake if t ;; Flymake must be installed. ;; It is included in Emacs 22 ;; (or http://flymake.sourceforge.net/, put flymake.el in your load-path) (setq perly-sense-load-flymake t) ;; Note: more flymake config below, after loading PerlySense ;; *** PerlySense load (don't touch) *** (setq perly-sense-external-dir (shell-command-to-string "perly_sense external_dir")) (if (string-match "Devel.PerlySense.external" perly-sense-external-dir) (progn (message "PerlySense elisp files at (%s) according to perly_sense, loading..." perly-sense-external-dir) (setq load-path (cons (expand-file-name (format "%s/%s" perly-sense-external-dir "emacs") ) load-path)) (load "perly-sense") ) (message "Could not identify PerlySense install dir. Is Devel::PerlySense installed properly? Does 'perly_sense external_dir' give you a proper directory? (%s)" perly-sense-external-dir) ) ;; ** Flymake Config ** ;; If you only want syntax check whenever you save, not continously (setq flymake-no-changes-timeout 9999) (setq flymake-start-syntax-check-on-newline nil) ;; ** Color Config ** ;; Emacs named colors: http://www.geocities.com/kensanata/colors.html ;; These colors work fine with a white X11 background. They may not look ;; that great on a console with the default color scheme. (set-face-background 'flymake-errline "antique white") (set-face-background 'flymake-warnline "lavender") (set-face-background 'dropdown-list-face "lightgrey") (set-face-background 'dropdown-list-selection-face "grey") ;; *** PerlySense End *** The load path is handled automatically by asking "perly_sense external_dir" where the elisp source was installed (that way, Devel::PerlySense and the elisp is always in sync). Emacs Configuration The most important config you can change is the prefix key. The default, \C-o, seemed to have a rater low useful-to-keystroke ratio and so was a strong candidate for stealing for this much more important purpose :) If you want to use flymake to do background syntax and Perl::Critic checks, set perly-sense-load-flymake to t (this is a very nifty thing, so yes you want to do this) and configure the colors to your liking. Note: This also needs to be enabled on a per-project basis (see below). GETTING STARTED WITH EMACS Smart docs C-o 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-o C-d and wait until a documentation hint for the method call is displayed briefly in the echo area. 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-o 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-o 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-o C-d with nothing under the cursor brings up a POD buffer for the current file. Document Inheritance C-o d i will briefly display the Inheritance hierarchy for the current Class in the echo area. This is similar to the Class Overview (see below). Document Used Modules C-o d u will briefly display the list of modules used from the current buffer in the echo area. This is similar to the Class Overview (see below). Smart go to C-o 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. Go to Base Class C-o g b takes you up one level in the inheritance hierarchy. If the current class has many base classes, you'll have to choose which one to go to. If the current method is implemented in that base class, go to the sub definition. After going to the Base Class, the Inheritance tree of that class is displayed in the echo area. Go to the 'new' method C-o g n takes you to the definition of the 'new' method of the current class (in this class, or a parent class). Go To 'use Module' section C-o g u takes you to the line below the last 'use Module' statement in the the current buffer. Edit Move 'use Module' Statement C-o e m u -- If point is on a line with a single 'use Module' statement, set mark and move that statement to the end of the 'use Module' section at the top of the file. This is typically useful when you realize you need a module, e.g. Data::Dumper, in the middle of the file, but you don't want to leave where you are just to fiddle with adding it. So type the 'use Module' statement, hit C-o e m u to move it, see that it got moved to a good place and hit C-u C-SPC to return to where you were, and continue doing what you where doing. Go to Module C-o g m -- Go to Module at point. Go to Version Control C-o g v -- Go to the Project view for the current Version Control system. This typically displays the change status of the files in the project. A dired of the Project dir is used in lieu of a VCS. First, try to go to an existing VC project buffer. If there is no VC buffer open, find out what VCS is used, and display the Project view. Supported VC systems: * Subversion -- Quick intro to *svn-status* _ (underscore) - display only the changed files (toggle) n, p, m, u -- next, previous, mark, unmark E -- diff the changes in the current file c -- commit file(s) r -- revert file(s) X v -- resolve conflict (or X X, I'm not sure what the difference is) etc, etc, etc, do a C-h m to see all the goodies. See also: * , * Class Overview Pressing C-o C-o will bring up the Class Overview of the Class name at point (not yet implemented), or otherwise the current Class (the active Package). Example class CatalystX::FeedMe::Controller::Feed * Inheritance * [ Class::Accessor ] +> [ Class::Accessor::Fast ] <-----+ | [ Catalyst::AttrContainer ] ------+---------------------------+ | | | v +- [ Catalyst::Base ] --> [ Catalyst::Component ] --> [ Class::Data::Inheritable ] [ Catalyst::Controller ] [] * Uses * [ Data::Dumper ] [ XML::Atom::Syndication::Content ] [ XML::Atom::Syndication::Feed ] [ Template::Filters ] [ XML::Atom::Syndication::Entry ] [ XML::Atom::Syndication::Link ] * NeighbourHood * [ CatalystX::FeedMe::DBIC ] [] -none- [ CatalystX::FeedMe::Controller::FeedItem ] [ CatalystX::FeedMe::Controller::Homepage ] [ CatalystX::FeedMe::Controller::Root ] * Bookmarks * - Todo Feed.pm:83: remove duplication * API * \>mutator_name_for ->new ->path_prefix ... The Inheritance section shows all Base classes of the Class. Inheriting from something like Catalyst is hopefully the hairiest you'll see. Classes inherit from their parents upwards in the diagram unless there is an arrow pointing elsewhere. The Uses section shows all used modules in the Class. The NeighbourHood section shows three columns (1: parent dir, 2: current dir, 3: subdir for the current class) with Classes located nearby (this can be bizarrely huge (and take a long time) if you browse your site_lib or similar). The Bookmarks section shows matches for bookmark definitions you have defined in the Project config (see below). the API section shows things that look like methods and properties of the class (sub declarations, $self method calls, $self->{hash_ref_keys}): ->method_in_this_class \>method_in_base_class (note the arrow coming from above) Private methods (named with a leading _) are displayed as regular methods. Same goes for private methods in base classes, except when the base class is outside of your Project (like for CPAN modules). Why is this? If it's your code base you're interested in everything, but if you inherit from a CPAN module, you don't care (you even shouldn't care) about the implementation of that module. Note that you can still see the private methods of those modules by doing a Class Overview on them, or any of the modules outside your current Project (thereby changing the current Project to the directory where those modules are installed). When in the Class Overview buffer: g -- Go to the file of the thing at point (Module/Method/Bookmark) d -- Documentation for the thing at point (Module/Method) c -- Class Overview for the thing at point. RET does the same. I -- Move point to the Inheritance heading in the buffer. U -- Move point to the Uses heading in the buffer. H -- Move point to the NeighbourHood heading (mnemonic: 'Hood). B -- Move point to the Bookmarks heading. A -- Move point to the API heading. N -- Move point to the '->new' method in the buffer (if any). q -- Quit the Class Overview buffer. Run File C-o C-r -- Run the file of the current buffer using the Compilation mode. Files are run according to the source type, which is determined by the file name (see the config file). The default for .t files is to run "prove -v", for .pm files "perl -c", etc. This can be configured per Project (see below). The file is run from the Project root directory or from the file directory depending on the file type, and the @INC is set appropriately. You can also specify additional @INC directories in the Project config. (Note that you can configure whatever type of run profile you like, not just Perl source files. As a taste of what's possible, imagine that you have a test framework with .yml acceptance test data files and a corresponding yml-runner.pl script. With the x option (not implemented) you can edit the .yml file and type C-o C-r to run the acceptance test the same way as a regular test.) If any warnings, errors or test failures are encountered, they are highlighted in the *compilation* buffer. Use C-c C-c to move from one error to the next. Or press RET on a highlighted line. If you wish to start many runs at the same time, rename the compilation buffer with "M-x rename-buffer". Re-run File Invoke C-o C-r from within the *compilaton* buffer to re-run (M-x recompile) the file. Useful when you have skipped around the source fixing errors and the .t file isn't visible. C-o r r -- If not even the *compilation* buffer is visible, issue Re-Run File from anywhere to bring it up and re-run. Edit Test Count C-o e t c -- Increase the test count number in the line resembling use Test::More tests => 43; without moving point. The current and new test count is reported in the echo area. Increase with the numeric argument (C-u 18 C-o e t c), or default 1. Assist With Test Count C-o a t -- If the test count in a .t file is out of sync with what's correctly reported when running the test in the *compilation* buffer (see Run File), use this command to update the .t file. This updates the use Test::More tests => 43; line in the current buffer, so be sure to only run this when the *compilation* buffer contains the run result of this buffer. Go to Error line If you run tests in a regular shell (inside Emacs or in a terminal window), this may be handy. C-o g e -- If point is located on an error line from a syntax error, or a stack trace from the debugger or similar, go to that file+line. If no file name can be found, prompt for a piece of text that contains the file+line spec. The kill ring or clipboard text is used as default if available (so it's easy to just copy the error line from the terminal, run this command and hit return to accept the default text). Flymake Introduction "Flymake performs on-the-fly syntax checks of the files being edited using the external syntax check tool (usually the compiler). Highlights erroneous lines and displays associated error messages." Flymake is included in Emacs 22 (or available from http://flymake.sourceforge.net/, put flymake.el somewhere in your load-path. [[[explain how to fix brokenness?]]] ). PerlySense uses flymake to check syntax, Perl Critic, etc. Three inconveniences with vanilla Flymake are fixed: no proper @INC, only .pl files, and "perl -c" warns about redefined subs for recursively used modules (which is perfectly fine Perl). Syntax errors and warnings both use the error face. Perl Critic violations use the warning face. Enabling Flymake First off, flymake itself needs to be enabled. Refer to the Emacs Installation description above. This will enable Flymake for all cperl-mode buffers, causing Emacs to call perly_sense for each check. PerlySense won't do anything at this point though. You still need to configure what should happen during a flymake. Create a PerlySense Project directory (see below) and look in the project.yml file for instructions on how to configure Flymake activities. Set "syntax" / "critic" to 1 to enable them. The primary reason "syntax" is turned off by default is that it's a potential security hole; running "perl -c" on a file will not only check the syntax; BEGIN and CHECK blocks are also executed. Doing that on random code may be considered... baaad. This way you can have Flymake enabled globally and still not run "perl -c" on everything that happens to be in a buffer. Using Flymake In the Project config file there are some hints on how to customize Flymake, when it should run, etc. You can also customize it with "M-x customize-group flymake". (Personally I find the nagging while I type very distracting, but I welcome the immediate feedback whenever I save the file. YMMV.) Look in the mode line for hints on whether there are any errors or warnings. C-o s n -- Go to the next Source error/warning. Display the error in the minibuffer. If the warning is from a Perl::Critic module, copy the module name into the kill-ring, so you easily can yank it into the .perlcritic config file to disable it. (not implemented) C-o s p -- Go to the previous Source error/warning. C-o s s -- Display the error/warning text of the current line. Assist With -- Regex Hit C-o a r to bring up the Regex Tool which will let you compose a Perl regular expression interactively with matching text highlighed. The Regex Tool appears in a new frame with three buffers: *Regex*, *Text* and *Groups*. If point is on a regular expression in the source code, that regex will be used to pre-populate the *Regex* buffer. (Not yet implemented) If there is a comment block just above the regex, it will be used to pre-populate the *Text* buffer. Note that it is very handy to document the regex with some sample input, so this is a good idea in general. (Not yet implemented) The contents of the *Regex* buffer should look e.g. like this: / part \s (\w+) \s no:(\d) /xgm * You can use all the usual delimiters, such as / | {} () ", etc. * You can put Perl comments below the regex to temporarily store chunks of regex code during prototyping. * The modifiers work as expected, including /x and /g . The results in the *Groups* buffer are updated as you type in either the *Regex* or *Text* buffer. Use C-c C-c to force an update. Use C-c C-k to quit all the regex-tool buffers and remove the frame. THE PERLYSENSE USER DIRECTORY PerlySense keeps a per-user directory to store cache files, logs, etc. The ".PerlySense" user directory is located under the first available of these environment variables: $APPDATA $ALLUSERSPROFILE $USERPROFILE $HOME $TEMP $TMP Run perly_sense info to see which directory is actually being used. PROJECTS PerlySense has the concept of a Project root directory. Basically, this is where all the source lives, and where your program can go to find modules that are used. This is from where tests are run and files are found. You can specify the Project root dir explicitly for your applications. But if you don't, PerlySense will try and figure out what the Project root directory is from the context of the surrounding code. This means you can browse source code anywhere on your hard drive (e.g. @INC) without any special setup or configuration. Most things will just work, without any hassle. If you follow the standard directory structure for CPAN modules, the Project directory is typically the one which contains the Makefile.PL, the lib, bin, and t directory, etc. Identifying a Project root directory The fastest and most solid way for PerlySense to know which is the Project directory is to create a ".PerlySenseProject" directory with a config file in it. This is highly recommended for all of your own projects. The complete project identification strategy is as follows: * First, if there is any directory upwards in the dirctory path with a ".PerlySenseProject" dir in it, that is the Project directory. * Second, PerlySense will try figure out from where the current file (if any) was being required/used given the contained package names or used modules. * Third, if that doesn't work, PerlySense will look for "lib" and "t" directories. If that doesn't work, PerlySense is lost and you really do need to create an explicit Project directory by running the following command in your intended Project root directory (that would typically be the directory which has a "lib" directory in it): perly_sense create_project Any existing ".PerlySenseProject/project.yml" config file will be renamed. Note that this all means that the current Project depends on which file you are looking at. If it's a file within the directory tree under a ".PerlySenseProject" directory, that's what the current Project is. But if you from that file do a Class Overview on an installed CPAN module, the current Project is deduced from that .pm file, typically making the current Project be the "lib" or "site_lib" of your local CPAN installation. Project Configuration The Project has a .PerlySenseProject/project.yml config file. Here you can change the name of the Project, add extra @INC directories, etc. There is a yaml-mode for Emacs, but I haven't got it to work properly (unless an infinite loop counts as "properly" these days). The shell-script-mode is good enough. The config file documentation is where it belongs, in the config file, so just take a look at it. perly_sense Project commands perly_sense create_project [--dir=DIR] Create a PerlySense project in DIR (default is current dir). perly_sense process_project Cache all modules in the project. (not implemented) BOOKMARKS Bookmarks are regexes that may match against a single line. Each bookmark definition has a name/moniker under which the matches are grouped in the Class Overview display. The primary point of Bookmarks is to highlight unusual things in the source. The secondary to make it easy for you go navigate to them. This can be anything you like, but things that come to mind are: * TODO comments * FIXME/XXX/HACK comments * Things you don't want left in the code, like Breakpoints ($DB::single = 1) Debugging warn/print statements Configuration Bookmarks are defined in the Project Config file (technical details are documented there). KEY BINDING CONVENTIONS There is a system behind the chosen key bindings in PerlySense. Knowing the conventions will make it easier to remember everything. Convention: Action based The first level after the prefix key (C-o by default) is always an Action, e.g. Run, or Document. (In the case of C-o C-d for Document you can either think of it as "Document this for me!" or "Give me Documentation!".) With a verb at the first level rather than a noun, the Action can be context sensitive, "smart", or DWIMy. Smart Goto goes to whatever is under the cursor, be it a module name, a method call, a file name, or an error message. Run runs the file differently depending on what kind of file is open (tests are "proved", modules are syntax checked, scripts are run, etc). Convention: The Action as a Gateway The first level indicates the Action to perform, and has the Ctrl modifier as a "Smart" / DWIMy modifier. This is both so it's easy to type C-o C-r without releasing the Ctrl key, and to provide a gateway to more specific actions when typing the key without Ctrl. E.g. C-o C-r means "Run file", C-o r r means "Run - Re-run". E.g. C-o C-g means "Smart Goto", C-o g b means "Goto - Base Class", C-o g s means "Goto - SUPER Method". The Main Actions Areas (some of the main areas have no implementations yet) * r -- Run Run files in various ways. * g -- Go to Navigate to various locations in the source. * d -- Document Bring up documentation. * f -- Find Find/search and display things in the source. * o -- Overview Bring up an overview of things. * m -- forMat Reformat source. * e -- Edit Perform smaller convenience editing task. * E -- rEfactor Perform restructuring edits that don't impact functionality/behaviour. Explore Emacs key bindings Remember that you can use the usual Emacs feature to display possible key stroke completions by hitting C-h whenever in the key stroke sequence. E.g. Hitting C-o g C-h will list all available key strokes starting wiht C-o g. Changing key bindings Some key bindings may change over time as I figure out what works and what doesn't. Some key bindings may be reorganized to make more sense or to just work better. IN CLOSING -- ON PARSING PERL Since Perl is so dynamic, a perfect static analysis of the source is impossible. But not unusably so. Well, hopefully. Most of the time. Because of this PerlySense is not about exact rules, but about heuristics and a 90% solution that isn't perfect, but good-enough. PerlySense tries to take advantage of the fact that Perl code is more than the plain source file. The source lives in a context of POD and a directory structure and common Perl idioms. Sometimes when PerlySense can't make a decision, you're expected to chip in and tell it what you meant. Sometimes it won't work at all. Such is the way of dynamic languages. If it works for you, brilliant, use it to be more productive. If not... well, there's always Java >:) MORE DOCUMENTATION Devel::PerlySense::Cookbook SEE ALSO sepia - similar effort PPI - excellent for parsing Perl CPANXR - also uses PPI for cross referencing the CPAN - Win32 class browser/IDE. Earlier (a lot) work by me. - Article "Perl Needs Better Tools" - Article "Software Archeology" - Regex Tool - Vim native data structure AUTHOR Johan Lindström, "" 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 . 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 and Phil Jackson for their elisp fu. Jonathan Rockway for cool ideas: John Wiegley for the regex-tool Jaeyoun Chung for dropdown-list 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 oProject Devel::PerlySense::Project object. Default: A Devel::PerlySense::Project::Unknown object. oHome Devel::PerlySense::Home object. Default: A newly created Home object. rhConfig Hash ref with the current config. If there is a known Project, it reflects the Project's config, otherwise it's the default config. Readonly. Note that the _entire_ data structure is readonly. Each time you change/add/remove a value from it, a kitten is slain. So, dude, just don't go there! oBookmarkConfig Devel::PerlySense::BookmarkConfig object. API METHODS new() Create new PerlySense object. setFindProject([file => $file], [dir => $dir]) Identify a project given the $file or $dir, and set the oProject property. If there is already a project defined, don't change it. If no project was found, don't change oProject. Return 1 if there is a valid project, else 0. Die on errors. oDocumentParseFile($file) Parse $file into a new PerlySense::Document object. Return the new object. If $file was already parsed by this PerlySense object, cache that instance of the Document and return that instead of parsing it again. 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. oLocationMethodDocFromDocument($oDocument, $method) Look in $oDocument and 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 If possible, also set "pod" and "podHeading". Return undef if no doc could be found. Currently, only POD is regarded as documentation. Todo: fail to listing an example/abstracted invocation of the method. Die on errors. oLocationMethodDefinitionFromDocument(oDocument => $oDocument, nameClass => $nameClass, nameMethod => $method) Look in $oDocument and find the declaration for $nameMmethod and return a Document::Location object. Return undef if no declaration could be found. Die on errors. rhRegexExample(file => $fileOrigin, row => $row, col => $row) Look in $file at location $row/$col and find the regex located there, and possibly the example comment preceeding it. Return hash ref with (keys: regex, example; values: source string). The source string is an empty string if nothing found. If there is an example string in a comment, return the example without the comment # Die if $file doesn't exist, or on other errors. rhRunFile(file => $fileSource) Figure out what type of source file $fileSource is, and how it should be run. The settings in the Project's config->{run_file} is used to determine the details. Return hash ref with (keys: "dir_run_from", "command_run", "type_source_file"), or die on errors (like if no Project could be found). dir_run_from is an absolute file name which should be the cwd when command_run is executed. type_source_file is something like "Test", "Module". flymakeFile(file => $fileSource) Do a flymake run with $fileSource according to the flymake config and output the result to STDOUT and STDERR. createProject(dir => $dir) Create a new PerlySense Project in $dir. Return 1 on success, or die on 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. isFileInProject(file => $fileSource, fileProjectOf => $fileProjectOf) Determine whether $fileSource is located within the current Project. If there is no current Project, figure it out using $fileProjectOf (that file should be located in the current project). Return true if $fileSource is in the project, else false. Die on errors. IMPLEMENTATION METHODS fileFindLookingAround($fileModuleBase, $dirOrigin) Find the file containing the $fileModuleBase given the $dirOrigin. Return the file name relative to $dirOrigin, or undef if none could be found. Die on errors. dirFindLookingAround($fileModuleBase, $dirOrigin, [$raDirSub = [".", "lib", "bin"]]) Find the dir containing the $fileModuleBase (relative file path) given the $dirOrigin. For all directories, also look in subdirectories in $raDirSub. Return the absolute dir name, 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) Check if $fileModuleBase is located in $dir. 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.