ide/editor/src/main/java/org/apidesign/bck2brwsr/ide/editor/JSEmbeddingProvider.java
author tzezula
Wed, 13 Feb 2013 15:21:54 +0100
branchide
changeset 720 d5c565eb0986
child 723 5d1c3bc8d297
permissions -rw-r--r--
Added EmbeddingProvider for JavaScriptBody.
     1 /*
     2  * To change this template, choose Tools | Templates
     3  * and open the template in the editor.
     4  */
     5 package org.apidesign.bck2brwsr.ide.editor;
     6 
     7 import com.sun.source.tree.AnnotationTree;
     8 import com.sun.source.tree.AssignmentTree;
     9 import com.sun.source.tree.CompilationUnitTree;
    10 import com.sun.source.tree.ExpressionTree;
    11 import com.sun.source.tree.LiteralTree;
    12 import com.sun.source.tree.MethodTree;
    13 import com.sun.source.util.SourcePositions;
    14 import com.sun.source.util.TreePath;
    15 import com.sun.source.util.TreePathScanner;
    16 import com.sun.source.util.Trees;
    17 import java.io.IOException;
    18 import java.util.ArrayList;
    19 import java.util.Collection;
    20 import java.util.Collections;
    21 import java.util.List;
    22 import java.util.concurrent.atomic.AtomicBoolean;
    23 import javax.lang.model.element.TypeElement;
    24 import javax.swing.text.Document;
    25 import org.netbeans.api.editor.mimelookup.MimeRegistration;
    26 import org.netbeans.api.java.source.CompilationInfo;
    27 import org.netbeans.api.java.source.JavaParserResultTask;
    28 import org.netbeans.api.java.source.JavaSource;
    29 import org.netbeans.api.lexer.Language;
    30 import org.netbeans.api.lexer.TokenHierarchy;
    31 import org.netbeans.api.lexer.TokenSequence;
    32 import org.netbeans.modules.parsing.api.Snapshot;
    33 import org.netbeans.modules.parsing.spi.Parser;
    34 import org.netbeans.modules.parsing.spi.Scheduler;
    35 import org.netbeans.modules.parsing.spi.SchedulerEvent;
    36 import org.netbeans.modules.parsing.spi.SchedulerTask;
    37 import org.netbeans.modules.parsing.spi.TaskFactory;
    38 import org.openide.util.Exceptions;
    39 
    40 /**
    41  *
    42  * @author Tomas Zezula
    43  */
    44 public final class JSEmbeddingProvider extends JavaParserResultTask<Parser.Result> {
    45 
    46     private static final int PRIORITY = 1000;
    47     private static final String JS_ANNOTATION = "org.apidesign.bck2brwsr.core.JavaScriptBody";  //NOI18N
    48     private static final String BODY = "body";                            //NOI18N
    49     private static final String JAVA_MIME_TYPE = "text/x-java";           //NOI18N
    50     private static final String JAVASCRIPT_MIME_TYPE = "text/javascript"; //NOI18N
    51     private final AtomicBoolean canceled = new AtomicBoolean();
    52 
    53     private JSEmbeddingProvider() {
    54         super(JavaSource.Phase.ELEMENTS_RESOLVED);
    55     }
    56 
    57     @Override
    58     public int getPriority() {
    59         return PRIORITY;
    60     }
    61 
    62     @Override
    63     public void cancel() {
    64         canceled.set(true);
    65     }
    66 
    67     @Override
    68     public Class<? extends Scheduler> getSchedulerClass() {
    69         return Scheduler.EDITOR_SENSITIVE_TASK_SCHEDULER;
    70     }
    71 
    72     @Override
    73     public void run(Parser.Result t, SchedulerEvent se) {
    74         canceled.set(false);
    75         final CompilationInfo ci = CompilationInfo.get(t);
    76         final CompilationUnitTree cu = ci.getCompilationUnit();
    77         final Trees trees = ci.getTrees();
    78         final SourcePositions sp = trees.getSourcePositions();
    79         final Finder f = new Finder(trees);
    80         final List<LiteralTree> result = new ArrayList<LiteralTree>();
    81         f.scan(cu, result);
    82         if (!result.isEmpty()) {
    83             try {
    84                 final TokenHierarchy<Document> tk = TokenHierarchy.get(ci.getDocument());
    85                 final Language<?> java = Language.find(JAVA_MIME_TYPE);
    86                 final Language<?> javaScript = Language.find(JAVASCRIPT_MIME_TYPE);
    87                 if (java != null && javaScript != null) {
    88                     final TokenSequence<?> seq = tk.tokenSequence(java);
    89                     if (seq != null) {
    90                         for (LiteralTree lt : result) {
    91                             final int start = (int) sp.getStartPosition(cu, lt);
    92                             final int end = (int) sp.getEndPosition(cu, lt);
    93                             seq.move(start);
    94                             while (seq.moveNext() && seq.offset() < end) {
    95                                 seq.createEmbedding(javaScript, 1, 1, true);
    96                             }
    97                         }
    98                     }
    99                 }
   100             } catch (IOException ioe) {
   101                 Exceptions.printStackTrace(ioe);
   102             }
   103         }
   104     }
   105 
   106 
   107 
   108 
   109     private static final class Finder extends TreePathScanner<Void, List<? super LiteralTree>> {
   110 
   111         private final Trees trees;
   112         private CompilationUnitTree cu;
   113         private boolean inEmbedding;
   114 
   115         Finder(final Trees trees) {
   116             this.trees = trees;
   117         }
   118 
   119         @Override
   120         public Void visitCompilationUnit(
   121                 final CompilationUnitTree unit,
   122                 final List p) {
   123             this.cu = unit;
   124             return super.visitCompilationUnit(unit, p);
   125         }
   126 
   127 
   128 
   129         @Override
   130         public Void visitMethod(
   131                 final MethodTree m,
   132                 final List<? super LiteralTree> p) {
   133             for (AnnotationTree a : m.getModifiers().getAnnotations()) {
   134                 final TypeElement ae = (TypeElement) trees.getElement(TreePath.getPath(cu, a.getAnnotationType()));
   135                 if (ae != null && JS_ANNOTATION.contentEquals(ae.getQualifiedName())) {
   136                     final List<? extends ExpressionTree> args =  a.getArguments();
   137                     for (ExpressionTree kvp : args) {
   138                         if (kvp instanceof AssignmentTree) {
   139                             final AssignmentTree assignemt = (AssignmentTree) kvp;
   140                             if (BODY.equals(assignemt.getVariable().toString())) {
   141                                 inEmbedding = true;
   142                                 try {
   143                                     scan(assignemt.getExpression(), p);
   144                                 } finally {
   145                                     inEmbedding = false;
   146                                 }
   147                             }
   148                         }
   149                     }
   150                 }
   151             }
   152             return null;
   153         }
   154 
   155         @Override
   156         public Void visitLiteral(LiteralTree node, List<? super LiteralTree> p) {
   157             if (inEmbedding) {
   158                 p.add(node);
   159             }
   160             return super.visitLiteral(node, p);
   161         }
   162 
   163     }
   164 
   165     @MimeRegistration(
   166             service = TaskFactory.class,
   167             mimeType = JAVA_MIME_TYPE)
   168     public static final class Factory extends TaskFactory {
   169         @Override
   170         public Collection<? extends SchedulerTask> create(Snapshot snpsht) {
   171             return Collections.singleton(new JSEmbeddingProvider());
   172         }
   173     }
   174 
   175 }