1 19 20 package org.netbeans.modules.languages.javascript; 21 22 import java.util.HashSet ; 23 import java.util.ListIterator ; 24 import java.util.ListIterator ; 25 import java.util.Set ; 26 import org.netbeans.api.languages.ASTItem; 27 import org.netbeans.api.languages.CharInput; 28 import org.netbeans.api.languages.DatabaseManager; 29 import org.netbeans.api.languages.LibrarySupport; 30 import org.netbeans.api.languages.ASTNode; 31 import org.netbeans.api.languages.ASTPath; 32 import org.netbeans.api.languages.SyntaxContext; 33 import org.netbeans.api.languages.support.CompletionSupport; 34 import org.netbeans.api.lexer.Token; 35 import org.netbeans.api.lexer.TokenHierarchy; 36 import org.netbeans.api.lexer.TokenSequence; 37 import org.netbeans.modules.editor.NbEditorDocument; 38 import org.netbeans.modules.editor.NbEditorUtilities; 39 import org.netbeans.api.languages.Context; 40 import org.netbeans.api.languages.LibrarySupport; 41 import org.netbeans.api.languages.SyntaxContext; 42 import org.netbeans.api.languages.ASTNode; 43 import org.netbeans.api.languages.ASTToken; 44 import org.netbeans.modules.languages.javascript.Semantic.Declaration; 45 import org.openide.DialogDisplayer; 46 import org.openide.ErrorManager; 47 import org.openide.ErrorManager; 48 import org.openide.NotifyDescriptor; 49 import org.openide.cookies.EditCookie; 50 import org.openide.cookies.EditorCookie; 51 import org.openide.cookies.SaveCookie; 52 import org.openide.loaders.DataObject; 53 import org.openide.text.Line; 54 import org.openide.text.NbDocument; 55 import org.openide.windows.IOProvider; 56 import org.openide.windows.InputOutput; 57 import java.io.IOException ; 58 import java.io.Reader ; 59 import java.io.Writer ; 60 import java.lang.reflect.InvocationTargetException ; 61 import java.lang.reflect.Method ; 62 import java.util.ArrayList ; 63 import java.util.Collection ; 64 import java.util.Iterator ; 65 import java.util.List ; 66 import javax.swing.text.BadLocationException ; 67 import javax.swing.text.Caret ; 68 import javax.swing.text.Document ; 69 import javax.swing.text.JTextComponent ; 70 import javax.swing.text.StyledDocument ; 71 import javax.swing.text.StyledDocument ; 72 import org.openide.cookies.LineCookie; 73 74 75 79 public class JavaScript { 80 81 private static final String DOC = "org/netbeans/modules/languages/javascript/Documentation.xml"; 82 private static final String MIME_TYPE = "text/javascript"; 83 84 private static Set regExp = new HashSet (); 85 static { 86 regExp.add (new Integer (',')); 87 regExp.add (new Integer (')')); 88 regExp.add (new Integer (';')); 89 } 90 91 public static Object [] parseRegularExpression (CharInput input) { 92 if (input.read () != '/') 93 throw new InternalError (); 94 int start = input.getIndex (); 95 while (!input.eof () && 96 input.next () != '/' 97 ) { 98 if (input.next () == '\r' || 99 input.next () == '\n' 100 ) { 101 input.setIndex (start); 102 return new Object [] { 103 ASTToken.create (MIME_TYPE, "js_operator", "", 0), 104 null 105 }; 106 } 107 if (input.next () == '\\') 108 input.read (); 109 input.read (); 110 } 111 while (input.next () == '/') input.read (); 112 while (!input.eof ()) { 113 int ch = input.next (); 114 if (ch != 'g' && ch != 'i' && ch != 'm') 115 break; 116 input.read (); 117 } 118 int end = input.getIndex (); 119 while ( 120 !input.eof () && ( 121 input.next () == ' ' || 122 input.next () == '\t' 123 ) 124 ) 125 input.read (); 126 if ( 127 !input.eof () && 128 input.next () == '.' 129 ) { 130 int h = input.getIndex (); 131 input.read (); 132 if (input.next () >= '0' && 133 input.next () <= '9' 134 ) { 135 input.setIndex (start); 136 return new Object [] { 137 ASTToken.create (MIME_TYPE, "js_operator", "", 0), 138 null 139 }; 140 } else { 141 input.setIndex (end); 142 return new Object [] { 143 ASTToken.create (MIME_TYPE, "js_regularExpression", "", 0), 144 null 145 }; 146 } 147 } 148 if ( 149 !input.eof () && regExp.contains (new Integer (input.next ())) 150 ) { 151 input.setIndex (end); 152 return new Object [] { 153 ASTToken.create (MIME_TYPE, "js_regularExpression", "", 0), 154 null 155 }; 156 } 157 input.setIndex (start); 158 return new Object [] { 159 ASTToken.create (MIME_TYPE, "js_operator", "", 0), 160 null 161 }; 162 } 163 164 public static Runnable hyperlink (SyntaxContext context) { 165 ASTPath path = context.getASTPath (); 166 ASTToken t = (ASTToken) path.getLeaf (); 167 ASTNode n = path.size () > 1 ? 168 (ASTNode) path.get (path.size () - 2) : 169 null; 170 String name = t.getIdentifier (); 171 DatabaseManager databaseManager = DatabaseManager.getDefault (); 172 List <Line.Part> list = databaseManager.get (path, name, false); 173 if (list.isEmpty ()) 174 list = databaseManager.get (DatabaseManager.FOLDER, name); 175 if (list.isEmpty ()) return null; 176 final Line.Part l = list.get (0); 177 if (l == null) return null; 178 DataObject dataObject = (DataObject) l.getLine ().getLookup (). 179 lookup (DataObject.class); 180 EditorCookie ec = (EditorCookie) dataObject.getCookie (EditCookie.class); 181 StyledDocument document = ec.getDocument (); 182 int offset = NbDocument.findLineOffset ( 183 document, 184 l.getLine ().getLineNumber () 185 ) + l.getColumn (); 186 if (offset == t.getOffset ()) return null; 187 return new Runnable () { 188 public void run () { 189 l.getLine ().show (Line.SHOW_GOTO, l.getColumn ()); 190 } 191 }; 192 } 193 194 public static String functionName (SyntaxContext context) { 195 ASTPath path = context.getASTPath (); 196 ASTNode n = (ASTNode) path.getLeaf (); 197 String name = null; 198 ASTNode nameNode = n.getNode ("FunctionName"); 199 if (nameNode != null) 200 name = nameNode.getAsText (); 201 String parameters = ""; 202 ASTNode parametersNode = n.getNode ("FormalParameterList"); 203 if (parametersNode != null) 204 parameters = parametersNode.getAsText (); 205 if (name != null) return name + " (" + parameters + ")"; 206 207 ListIterator <ASTItem> it = path.listIterator (path.size () - 1); 208 while (it.hasPrevious ()) { 209 ASTItem item = it.previous (); 210 if (item instanceof ASTToken) break; 211 ASTNode p = (ASTNode) item; 212 if (p.getNT ().equals ("AssignmentExpressionInitial") && 213 p.getNode ("AssignmentOperator") != null 214 ) { 215 return ((ASTNode) p.getChildren ().get (0)).getAsText () + 216 " (" + getAsText (n.getNode ("FormalParameterList")) + ")"; 217 } 218 if (p.getNT ().equals ("PropertyNameAndValue")) { 219 return p.getNode ("PropertyName").getAsText () + 220 " (" + getAsText (n.getNode ("FormalParameterList")) + ")"; 221 } 222 } 223 return "?"; 224 } 225 226 public static String objectName (SyntaxContext context) { 227 ASTPath path = context.getASTPath (); 228 ASTNode n = (ASTNode) path.getLeaf (); 229 ListIterator <ASTItem> it = path.listIterator (path.size ()); 230 while (it.hasPrevious ()) { 231 ASTItem item = it.previous (); 232 if (item instanceof ASTToken) break; 233 ASTNode p = (ASTNode) item; 234 if (p.getNT ().equals ("AssignmentExpressionInitial") && 235 p.getNode ("AssignmentOperator") != null 236 ) { 237 return ((ASTNode) p.getChildren ().get (0)).getAsText (); 238 } 239 if (p.getNT ().equals ("PropertyNameAndValue")) { 240 return p.getNode ("PropertyName").getAsText (); 241 } 242 } 243 return "?"; 244 } 245 246 247 249 public static List completionItems (Context context) { 250 List result = new ArrayList (); 251 if (context instanceof SyntaxContext) { 252 ASTPath path = ((SyntaxContext) context).getASTPath (); 253 DatabaseManager databaseManager = DatabaseManager.getDefault (); 254 Collection c = databaseManager.getIds (path, true); 255 result.addAll (c); 256 c = databaseManager.getIds (DatabaseManager.FOLDER); 257 result.addAll (c); 258 return result; 259 } 260 261 TokenSequence ts = context.getTokenSequence (); 262 Token token = ts.token (); 263 String tokenText = token.text ().toString (); 264 String libraryContext = null; 265 if (tokenText.equals (".")) { 266 token = previousToken (ts); 267 if (token.id ().name ().endsWith ("identifier")) 268 libraryContext = token.text ().toString (); 269 } else 270 if (token.id ().name ().endsWith ("identifier") ) { 271 token = previousToken (ts); 272 if (token.text ().toString ().equals (".")) { 273 token = previousToken (ts); 274 if (token.id ().name ().endsWith ("identifier")) 275 libraryContext = token.text ().toString (); 276 } 277 } 278 279 if (libraryContext != null) { 280 result.addAll (getFromLibrary (libraryContext, 1, "black")); 281 result.addAll (getFromLibrary ("member", 2, "black")); 282 } else 283 result.addAll (getFromLibrary ("keyword", 2, "blue")); 284 result.addAll (getFromLibrary ("root",2, "black")); 285 return result; 286 } 287 288 private static Token previousToken (TokenSequence ts) { 289 do { 290 if (!ts.movePrevious ()) return ts.token (); 291 } while (ts.token ().id ().name ().endsWith ("whitespace")); 292 return ts.token (); 293 } 294 295 private static List getFromLibrary ( 296 String context, 297 int priority, 298 String color 299 ) { 300 List l = getLibrary ().getItems (context); 301 List result = new ArrayList (); 302 if (l == null) return result; 303 Iterator it = l.iterator (); 304 while (it.hasNext ()) { 305 String item = (String ) it.next (); 306 String description = getLibrary ().getProperty 307 (context, item, "description"); 308 if (description == null) 309 result.add (CompletionSupport.createCompletionItem ( 310 item, 311 "<html><b><font color=" + color + ">" + item + 312 "</font></b></html>", 313 null, 314 priority 315 )); 316 else 317 result.add (CompletionSupport.createCompletionItem ( 318 item, 319 "<html><b><font color=" + color + ">" + item + 320 ": </font></b><font color=black> " + 321 description + "</font></html>", 322 null, 323 priority 324 )); 325 } 326 return result; 327 } 328 329 private static List completionDescriptions; 330 331 public static List completionDescriptions (Context context) { 332 return completionItems (context); 333 } 376 377 378 380 public static void performDeleteCurrentMethod (ASTNode node, JTextComponent comp) { 381 NbEditorDocument doc = (NbEditorDocument)comp.getDocument(); 382 int position = comp.getCaretPosition(); 383 ASTPath path = node.findPath(position); 384 ASTNode methodNode = null; 385 for (Iterator iter = path.listIterator(); iter.hasNext(); ) { 386 Object obj = iter.next(); 387 if (!(obj instanceof ASTNode)) 388 break; 389 ASTNode n = (ASTNode) obj; 390 if ("FunctionDeclaration".equals(n.getNT())) { methodNode = n; 392 } } if (methodNode != null) { 395 try { 396 doc.remove(methodNode.getOffset(), methodNode.getLength()); 397 } catch (BadLocationException e) { 398 ErrorManager.getDefault().notify(e); 399 } 400 } 401 } 402 403 public static boolean enabledDeleteCurrentMethod (ASTNode node, JTextComponent comp) { 404 NbEditorDocument doc = (NbEditorDocument)comp.getDocument(); 405 int position = comp.getCaretPosition(); 406 ASTPath path = node.findPath(position); 407 if (path == null) return false; 408 for (Iterator iter = path.listIterator(); iter.hasNext(); ) { 409 Object obj = iter.next(); 410 if (!(obj instanceof ASTNode)) 411 return false; 412 ASTNode n = (ASTNode) obj; 413 if ("FunctionDeclaration".equals(n.getNT())) { return true; 415 } } return false; 418 } 419 420 public static void performRun (ASTNode node, JTextComponent comp) { 421 ClassLoader cl = JavaScript.class.getClassLoader (); 422 try { 423 Class managerClass = cl.loadClass ("javax.script.ScriptEngineManager"); 426 Object manager = managerClass.newInstance(); 427 Method getEngineByMimeType = managerClass.getMethod ("getEngineByMimeType", new Class [] {String .class}); 428 Object engine = getEngineByMimeType.invoke (manager, new Object [] {"text/javascript"}); 429 430 Document doc = comp.getDocument (); 431 DataObject dob = NbEditorUtilities.getDataObject (doc); 432 String name = dob.getPrimaryFile ().getNameExt (); 433 SaveCookie saveCookie = (SaveCookie) dob.getLookup ().lookup (SaveCookie.class); 434 if (saveCookie != null) 435 try { 436 saveCookie.save (); 437 } catch (IOException ex) { 438 ErrorManager.getDefault ().notify (ex); 439 } 440 441 Class engineClass = cl.loadClass ("javax.script.ScriptEngine"); 443 Method getContext = engineClass.getMethod ("getContext", new Class [] {}); 444 Object context = getContext.invoke (engine, new Object [] {}); 445 446 InputOutput io = IOProvider.getDefault ().getIO ("Run " + name, false); 447 448 Class contextClass = cl.loadClass("javax.script.ScriptContext"); 452 Method setWriter = contextClass.getMethod ("setWriter", new Class [] {Writer .class}); 453 Method setErrorWriter = contextClass.getMethod ("setErrorWriter", new Class [] {Writer .class}); 454 Method setReader = contextClass.getMethod ("setReader", new Class [] {Reader .class}); 455 setWriter.invoke (context, new Object [] {io.getOut ()}); 456 setErrorWriter.invoke (context, new Object [] {io.getErr ()}); 457 setReader.invoke (context, new Object [] {io.getIn ()}); 458 459 io.getOut().reset (); 460 io.getErr ().reset (); 461 io.select (); 462 463 Method eval = engineClass.getMethod ("eval", new Class [] {String .class}); 465 Object o = eval.invoke (engine, new Object [] {doc.getText (0, doc.getLength ())}); 466 467 if (o != null) 468 DialogDisplayer.getDefault ().notify (new NotifyDescriptor.Message ("Result: " + o)); 469 470 } catch (InvocationTargetException ex) { 471 try { 472 Class scriptExceptionClass = cl.loadClass("javax.script.ScriptException"); 473 if (ex.getCause () != null && 474 scriptExceptionClass.isAssignableFrom (ex.getCause ().getClass ()) 475 ) 476 DialogDisplayer.getDefault ().notify (new NotifyDescriptor.Message (ex.getCause ().getMessage ())); 477 else 478 ErrorManager.getDefault ().notify (ex); 479 } catch (Exception ex2) { 480 ErrorManager.getDefault ().notify (ex2); 481 } 482 } catch (Exception ex) { 483 ErrorManager.getDefault ().notify (ex); 484 } 485 } 513 514 public static boolean enabledRun (ASTNode node, JTextComponent comp) { 515 try { 516 ClassLoader cl = JavaScript.class.getClassLoader (); 517 Class managerClass = cl.loadClass ("javax.script.ScriptEngineManager"); 518 519 return managerClass != null; 520 } catch (ClassNotFoundException ex) { 521 return false; 522 } 523 } 524 525 public static void performGoToDeclaration (ASTNode node, JTextComponent comp) { 526 NbEditorDocument doc = (NbEditorDocument)comp.getDocument(); 527 int position = comp.getCaretPosition(); 528 ASTPath path = node.findPath(position); 529 ASTItem item = path.getLeaf(); 530 if (!(item instanceof ASTToken)) { 531 return; 532 } 533 DatabaseManager manager = DatabaseManager.getDefault(); 534 Semantic.Info info = Semantic.getInfo(doc); 535 Semantic.Declaration decl = info.getItem(item); 536 if (info == null || decl == null) { 537 return; 538 } 539 int offset = decl.getASTItem().getOffset(); 540 DataObject dobj = NbEditorUtilities.getDataObject (doc); 541 LineCookie lc = (LineCookie)dobj.getCookie(LineCookie.class); 542 Line.Set lineSet = lc.getLineSet(); 543 Line line = lineSet.getCurrent(NbDocument.findLineNumber(doc, offset)); 544 int column = NbDocument.findLineColumn (doc, offset); 545 line.show (Line.SHOW_GOTO, column); 546 } 547 548 public static boolean enabledGoToDeclaration (ASTNode node, JTextComponent comp) { 549 NbEditorDocument doc = (NbEditorDocument)comp.getDocument(); 550 int position = comp.getCaretPosition(); 551 ASTPath path = node.findPath(position); 552 ASTItem item = path.getLeaf(); 553 if (!(item instanceof ASTToken)) { 554 return false; 555 } 556 DatabaseManager manager = DatabaseManager.getDefault(); 557 Semantic.Info info = Semantic.getInfo(doc); 558 return info != null && info.getItem(item) != null; 559 } 560 561 public static boolean isFunctionParameter (Context context) { 562 return isVariable(context, Declaration.PARAMETER); 563 } 564 565 public static boolean isLocalVariable(Context context) { 566 return isVariable(context, Declaration.LOCAL_VARIABLE); 567 } 568 569 571 private static boolean isVariable(Context context, int kind) { 572 if (!(context instanceof SyntaxContext)) { 573 return false; 574 } 575 SyntaxContext scontext = (SyntaxContext)context; 576 ASTPath path = scontext.getASTPath (); 577 Object obj = path.getLeaf (); 578 if (!(obj instanceof ASTToken)) { 579 return false; 580 } 581 ASTToken leaf = (ASTToken)obj; 582 Semantic.Info info = Semantic.getInfo(scontext.getDocument()); 583 if (info == null) return false; 584 Declaration decl = info.getItem(leaf); 585 return decl != null && decl.getKind() == kind; 586 } 587 588 private static LibrarySupport library; 589 590 private static LibrarySupport getLibrary () { 591 if (library == null) 592 library = LibrarySupport.create (DOC); 593 return library; 594 } 595 596 private static TokenSequence getTokenSequence (Document doc, Caret caret) { 597 int ln = NbDocument.findLineNumber ((StyledDocument ) doc, caret.getDot ()) - 1; 598 int start = NbDocument.findLineOffset ((StyledDocument ) doc, ln); 599 TokenHierarchy th = TokenHierarchy.get (doc); 600 TokenSequence ts = th.tokenSequence (); 601 ts.move (start); 602 return ts; 603 } 604 605 private static void indent (Document doc, Caret caret, int i) { 606 StringBuilder sb = new StringBuilder (); 607 while (i > 0) { 608 sb.append (' ');i--; 609 } 610 try { 611 doc.insertString (caret.getDot (), sb.toString (), null); 612 } catch (BadLocationException ex) { 613 ErrorManager.getDefault ().notify (ex); 614 } 615 } 616 617 private static int getIndent (TokenSequence ts) { 618 if (ts.token ().id ().name ().equals ("js_whitespace")) { 619 String w = ts.token ().text ().toString (); 620 int i = w.lastIndexOf ('\n'); 621 if (i >= 0) 622 w = w.substring (i + 1); 623 i = w.lastIndexOf ('\r'); 624 if (i >= 0) 625 w = w.substring (i + 1); 626 return w.length (); 627 } 628 return 0; 629 } 630 631 private static String getAsText (ASTNode n) { 632 if (n == null) return ""; 633 return n.getAsText (); 634 } 635 } 636 | Popular Tags |