/* * Copyright (c) 2007 Ali Rantakari * * fromjeditflexlangrefmacro.20.hasseg@spamgourmet.com * http://hasseg.org * * Based on macros by VeryVito from turdhead.com : * http://www.turdhead.com/2007/09/30/more-actionscript-magic-for-jedit-context-sensitive-reference-material/ * * thanks! * * --------------------------------------------------------------------------- * * DESCRIPTION: * * A jEdit macro for displaying Flex SDK language reference documentation * for a selected class, package or method. * * Developed and tested only on OS X, no guarantee of this working on * other platforms. * * --------------------------------------------------------------------------- * * REQUIRES: * * - jEdit * * - OPTIONAL: InfoViewer plugin for jEdit * * --------------------------------------------------------------------------- * * USAGE: * * 1) Change the settings below to correspond to your system * * 2) Add this to your macros folder ( ~/.jedit/macros ) * * 3) Bind it to a keyboard shortcut ( utilities -> global options -> * shortcuts -> macros ) * * 4) Place your pointer on the search term or select the search * term (an AS3/Flex class, package or method name) * * 5) Run the macro by pressing the shortcut you assigned (or from * the macros menu) * * --------------------------------------------------------------------------- * * Licensed under the MIT License: * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ import java.util.regex.*; import java.text.MessageFormat; // SETTINGS: -------------------------------------- /* * Paths to AsDoc folders to search (in this order) * (with trailing slashes) */ String[] foldersToCheck = new String[] { "/Flex/flex201_documentation/langref/", "/Flex/SVN_working_copies/SSGUI-Flex/asdoc-output/"}; /* * The files in the AsDoc folders to check (in this order) * (if they don't exist in all of the folders, no worries) */ String[] filesToCheck = new String[] { "all-classes.html", "class-list.html", "package-summary.html"}; /* * Whether to display the found documentation page * in the InfoViewer plugin or not (if not, the * openCommand (below) will be run in the console) */ displayInInfoViewer = false; /* * The command to run in the console for opening * the found documentation file in, for example, * a web browser * * {0} will be substituted with the filename to open, * surrounded by double quotes (so don't add the * double quotes here) */ openCommand = "open -a Safari {0}"; // /settings - - - - - - - - - - - - - - - - - - - // Macro implementation begins here: ------------ // functions ------------------------------------- Vector searchDirForFilesMatching(File aDirectory, String aRegEx) { Vector retVal = new Vector(); if (aDirectory != null) { if (aDirectory.exists()) { if (aDirectory.isDirectory()) { File[] files = aDirectory.listFiles(); for (int i = 0; i < files.length; i++) { if (files[i].isFile() && !files[i].isHidden()) { if (files[i].getName().matches(aRegEx)) retVal.add(files[i]); } } }else{ Macros.error(view, "\""+aDirectory.getPath()+"\" is not a directory"); } }else{ Macros.error(view, "\""+aDirectory.getPath()+"\" does not exist!"); } } return retVal; } /** * Returns a Vector of HashMaps. Each HashMap contains a match, where * the keys are the specified group numbers and the values are the * corresponding strings. * * Returns null if no matches. */ Vector regExSearchFile(String aRegEx, String aFilePath, int[] aGroupsToReturn) { Vector retVal = new Vector(); Pattern regPat = Pattern.compile(aRegEx); Matcher matcher; BufferedReader bufr; File f = new File(aFilePath); if (f.exists()) { try { bufr = new BufferedReader (new FileReader (aFilePath)); while ( (record = bufr.readLine()) != null ) { matcher = regPat.matcher(record); if (matcher.find()) { HashMap thisRetEntry = new HashMap(); for (int j = 0; j < aGroupsToReturn.length; j++) { thisRetEntry.put(aGroupsToReturn[j], matcher.group(aGroupsToReturn[j])); } retVal.add(thisRetEntry); } } } catch (java.io.IOException e) { Macros.error(view, "An error occurred while trying to parse \""+aFilePath+"\""); } } return retVal; } /** * Searches for the specified class or package name (aWordToFind) in * the AsDoc folders and files specified in the settings. * * Returns the documentation file path or null if not found. */ String searchForDocs(String aWordToFind) { String retVal = null; String regEx = "a.*href\\s*=\\s*\"(.*?)\".*>("+aWordToFind+")<"; Pattern regPat = Pattern.compile(regEx); Matcher matcher; BufferedReader bufr; int j = 0; while ((retVal == null) && (j < foldersToCheck.length)) { int i = 0; while ((retVal == null) && (i < filesToCheck.length)) { String thisFile = foldersToCheck[j]+filesToCheck[i]; File f = new File(thisFile); if (f.exists()) { try { bufr = new BufferedReader (new FileReader (thisFile)); while ( (record = bufr.readLine()) != null ) { matcher = regPat.matcher(record); if (matcher.find()) retVal = foldersToCheck[j] + matcher.group(1); } } catch (java.io.IOException e) { Macros.error(view, "An error occurred while trying to parse \""+thisFile+"\""); } } i++; } j++; } return retVal; } /** * Give this a variable name and the path to the file where * it appears, and get the class name of the type * of the variable, or null if not found. */ String findTypeOfVarFromFile(String aVarName, String aFilePath) { String retVal = null; File f = new File(aFilePath); if (f.exists()) { if (f.isFile()) { returnCurrentClassName = false; if (aVarName == null) returnCurrentClassName = true; else if (aVarName == "this" || aVarName.trim() == "") returnCurrentClassName = true; if (returnCurrentClassName == true) { // find first class name from specified file Vector results = regExSearchFile("\\b(class)\\s+\\b(\\w+)\\b", aFilePath, new int[]{2}); if (!results.isEmpty()) retVal = results.get(0).get(2); }else{ // find definition of specified variable from specified file Vector results = regExSearchFile((".*("+aVarName+")\\s*:\\s*(.*?)[;,=\\s\\)]+"), aFilePath, new int[]{2}); if (!results.isEmpty()) { retVal = results.get(0).get(2).trim(); // if file classname+"class.as" exists, prefer that class name Vector codeBehindMatches = searchDirForFilesMatching(f.getParentFile(), ("^"+retVal+"Class\\.as$")); if (!codeBehindMatches.isEmpty()) retVal = retVal+"Class"; } // if nothing found... if (retVal == null) { // find superclass name (if there is one) Vector results = regExSearchFile(("class\\s+(.*?)\\s+extends\\s+(.*?)[;\\s]+"), aFilePath, new int[]{2}); if (!results.isEmpty()) { String superClassName = results.get(0).get(2).trim(); // find source file for superclass (in the same dir) File superClassFile = null; Vector straightMatches = searchDirForFilesMatching(f.getParentFile(), ("^"+superClassName+"\\.as$")); Vector codeBehindMatches = searchDirForFilesMatching(f.getParentFile(), ("^"+superClassName+"Class\\.as$")); if (!codeBehindMatches.isEmpty()) superClassFile = codeBehindMatches.get(0); else if (!straightMatches.isEmpty()) superClassFile = straightMatches.get(0); if (superClassFile != null) retVal = findTypeOfVarFromFile(aVarName, superClassFile.getPath()); } } } }else{ Macros.error(view, "\""+aFilePath+"\" is not a file!"); } }else{ Macros.error(view, "File \""+aFilePath+"\" does not exist!"); } return retVal; } String getMethodOwner(String functionName, String lineWhereItAppears) { String retVal = null; String methodRegEx = "((.+)\\s*\\.\\s*)?("+functionName+")\\s*\\((.*?)\\)"; Pattern methodRegPat = Pattern.compile(methodRegEx); Matcher methodMatcher = methodRegPat.matcher(lineWhereItAppears); if (methodMatcher.find()) { retVal = methodMatcher.group(2); if (retVal != null) { retVal = retVal.trim(); // if using a cast (e.g. "MyClass(event.target).methodToSearchFor();")... if ((retVal.length() > 0) && (retVal.matches(".*\\(.*\\)$"))) retVal = retVal.substring(0,(retVal.lastIndexOf("("))); // if 'inline' methodRegPat = Pattern.compile(".+\\b(\\w+)$"); methodMatcher = methodRegPat.matcher(retVal); if (methodMatcher.find()) retVal = methodMatcher.group(1); if (retVal != null) retVal = retVal.trim(); //Macros.message(view, "method owner variable is '"+retVal+"'"); } } return retVal; } // /functions - - - - - - - - - - - - - - - - - - - - - String foundDocFilePath = null; // the path to the documentation html file to display // run search on the word under cursor or the selected text if (textArea.selectedText == null) { textArea.goToPrevCharacter(false); textArea.selectWord(); } String wordToFind = textArea.selectedText; foundDocFilePath = searchForDocs(wordToFind); // if nothing found, see if the selection is defined as a variable. // If it is, take variable's type and run a search on that if (foundDocFilePath == null) { String typeOfVar = findTypeOfVarFromFile(wordToFind, buffer.getPath()); if (typeOfVar != null) foundDocFilePath = searchForDocs(typeOfVar); } // if still nothing found... if (foundDocFilePath == null) { // if selection is a function/method name, get its owner variable String methodOwnerVar = getMethodOwner(wordToFind, textArea.getLineText(textArea.getCaretLine())); if (methodOwnerVar != null) { // if starts with an uppercase letter, probably a class name -> try that if (methodOwnerVar.substring(0,1).matches("[A-Z]")) { foundDocFilePath = searchForDocs(methodOwnerVar); } } if (foundDocFilePath == null) { if (methodOwnerVar == null) methodOwnerVar == "this"; // find type of this owner var and if found, search for that class String typeOfOwnerVar = null; typeOfOwnerVar = findTypeOfVarFromFile(methodOwnerVar, buffer.getPath()); //Macros.message(view, "method owner type is '"+typeOfOwnerVar+"'"); if (typeOfOwnerVar != null) foundDocFilePath = searchForDocs(typeOfOwnerVar); } if (foundDocFilePath != null) foundDocFilePath = foundDocFilePath+"#"+wordToFind+"\\\\(\\\\)"; } // if found a doc URL, display it if (foundDocFilePath != null) { if (!foundDocFilePath.startsWith("file://")) foundDocFilePath = "file://"+foundDocFilePath; if (displayInInfoViewer) infoviewer.InfoViewerPlugin.openURL(view, foundDocFilePath); else { Object[] mfArgs = {("\""+foundDocFilePath+"\"")}; commandToRun = MessageFormat.format(openCommand, mfArgs); runInSystemShell(view, commandToRun); if (view.getDockableWindowManager().isDockableWindowDocked("console") == true) { if (view.getDockableWindowManager().isDockableWindowVisible("console") == true) view.getDockableWindowManager().removeDockableWindow("console"); } } }else{ Macros.error(view, "Sorry. No Flex documentation found for \""+wordToFind+"\"."); } /* Macro index data (in DocBook format) Display_Flex_documentation.bsh Displays documentation about selected class, package or method from Flex language reference and optionally also other AsDoc sources */ // end Display_Flex_documentation.bsh