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