示例#1
0
  public void injectAll(Disposable parent) {
    injectVariousStuffEverywhere(parent, myPsiManager);

    Project project = myPsiManager.getProject();
    Language ql = Language.findLanguageByID("JPAQL");
    Language js = Language.findLanguageByID("JavaScript");
    registerForStringVarInitializer(parent, project, ql, "ql", null, null);
    registerForStringVarInitializer(parent, project, ql, "qlPrefixed", "xxx", null);
    registerForStringVarInitializer(parent, project, js, "js", null, null);
    registerForStringVarInitializer(parent, project, js, "jsSeparated", " + ", " + 'separator'");
    registerForStringVarInitializer(parent, project, js, "jsBrokenPrefix", "xx ", "");

    registerForStringVarInitializer(
        parent, project, Language.findLanguageByID("Oracle"), "oracle", null, null);

    registerForParameterValue(parent, project, Language.findLanguageByID("Groovy"), "groovy");
  }
  public AndroidLayoutPreviewToolWindowManager(
      final Project project, final FileEditorManager fileEditorManager) {
    myProject = project;
    myFileEditorManager = fileEditorManager;

    myToolWindowUpdateQueue =
        new MergingUpdateQueue("android.layout.preview", 100, true, null, project);

    final MessageBusConnection connection = project.getMessageBus().connect(project);
    connection.subscribe(
        FileEditorManagerListener.FILE_EDITOR_MANAGER, new MyFileEditorManagerListener());
    connection.subscribe(ProjectTopics.PROJECT_ROOTS, new MyAndroidPlatformListener(project));

    PsiManager.getInstance(project)
        .addPsiTreeChangeListener(
            new PsiTreeChangeAdapter() {
              boolean myIgnoreChildrenChanged;

              @Override
              public void beforeChildrenChange(@NotNull PsiTreeChangeEvent event) {
                myIgnoreChildrenChanged = false;
              }

              @Override
              public void childrenChanged(@NotNull PsiTreeChangeEvent event) {
                // See ResourceFolderManager#PsiListener#childrenChanged
                if (isRelevant(event)
                    && !myIgnoreChildrenChanged
                    && event.getParent() != event.getChild()) {
                  update(event);
                }
              }

              @Override
              public void childAdded(@NotNull PsiTreeChangeEvent event) {
                myIgnoreChildrenChanged = true;
                if (isRelevant(event)) {
                  PsiElement child = event.getChild();
                  PsiElement parent = event.getParent();

                  if (child instanceof XmlAttribute && parent instanceof XmlTag) {
                    // Typing in a new attribute. Don't need to do any rendering until there
                    // is an actual value
                    if (((XmlAttribute) child).getValueElement() == null) {
                      return;
                    }
                  } else if (parent instanceof XmlAttribute && child instanceof XmlAttributeValue) {
                    XmlAttributeValue attributeValue = (XmlAttributeValue) child;
                    if (attributeValue.getValue() == null || attributeValue.getValue().isEmpty()) {
                      // Just added a new blank attribute; nothing to render yet
                      return;
                    }
                  } else if (parent instanceof XmlAttributeValue
                      && child instanceof XmlToken
                      && event.getOldChild() == null) {
                    // Just added attribute value
                    String text = child.getText();
                    // See if this is an attribute that takes a resource!
                    if (text.startsWith(PREFIX_RESOURCE_REF)) {
                      if (text.equals(PREFIX_RESOURCE_REF) || text.equals(ANDROID_PREFIX)) {
                        // Using code completion to insert resource reference; not yet done
                        return;
                      }
                      ResourceUrl url = ResourceUrl.parse(text);
                      if (url != null && url.name.isEmpty()) {
                        // Using code completion to insert resource reference; not yet done
                        return;
                      }
                    }
                  }
                  update(event);
                }
              }

              @Override
              public void childReplaced(@NotNull PsiTreeChangeEvent event) {
                myIgnoreChildrenChanged = true;
                if (isRelevant(event)) {
                  PsiElement child = event.getChild();
                  PsiElement parent = event.getParent();

                  if (parent instanceof XmlAttribute && child instanceof XmlToken) {
                    // Typing in attribute name. Don't need to do any rendering until there
                    // is an actual value
                    XmlAttributeValue valueElement = ((XmlAttribute) parent).getValueElement();
                    if (valueElement == null
                        || valueElement.getValue() == null
                        || valueElement.getValue().isEmpty()) {
                      return;
                    }
                  } else if (parent instanceof XmlAttributeValue
                      && child instanceof XmlToken
                      && event.getOldChild() != null) {
                    String newText = child.getText();
                    String prevText = event.getOldChild().getText();
                    // See if user is working on an incomplete URL, and is still not complete, e.g.
                    // typing in @string/foo manually
                    if (newText.startsWith(PREFIX_RESOURCE_REF)) {
                      ResourceUrl prevUrl = ResourceUrl.parse(prevText);
                      ResourceUrl newUrl = ResourceUrl.parse(newText);
                      if (prevUrl != null && prevUrl.name.isEmpty()) {
                        prevUrl = null;
                      }
                      if (newUrl != null && newUrl.name.isEmpty()) {
                        newUrl = null;
                      }
                      if (prevUrl == null && newUrl == null) {
                        return;
                      }
                    }
                  }
                  update(event);
                }
              }

              @Override
              public void childRemoved(@NotNull PsiTreeChangeEvent event) {
                myIgnoreChildrenChanged = true;
                if (isRelevant(event)) {
                  PsiElement child = event.getChild();
                  PsiElement parent = event.getParent();

                  if (parent instanceof XmlAttribute && child instanceof XmlToken) {
                    // Typing in attribute name. Don't need to do any rendering until there
                    // is an actual value
                    XmlAttributeValue valueElement = ((XmlAttribute) parent).getValueElement();
                    if (valueElement == null
                        || valueElement.getValue() == null
                        || valueElement.getValue().isEmpty()) {
                      return;
                    }
                  }
                  update(event);
                }
              }
            },
            project);

    ProjectBuilder.getInstance(project)
        .addAfterProjectBuildTask(
            new ProjectBuilder.AfterProjectBuildListener() {
              @Override
              protected void buildFinished() {
                if (myToolWindowForm != null && myToolWindowReady && !myToolWindowDisposed) {
                  ApplicationManager.getApplication()
                      .invokeLater(
                          new Runnable() {
                            @Override
                            public void run() {
                              render();
                            }
                          });
                }
              }
            });
  }
示例#3
0
  private static void injectVariousStuffEverywhere(Disposable parent, final PsiManager psiManager) {
    final Language ql = Language.findLanguageByID("JPAQL");
    final Language js = Language.findLanguageByID("JavaScript");
    final Language html = Language.findLanguageByID("HTML");
    if (ql == null || js == null) return;
    final Language ecma4 = Language.findLanguageByID("ECMA Script Level 4");

    final MultiHostInjector myMultiHostInjector =
        new MultiHostInjector() {
          @Override
          public void getLanguagesToInject(
              @NotNull MultiHostRegistrar registrar, @NotNull PsiElement context) {
            XmlAttributeValue value = (XmlAttributeValue) context;
            PsiElement parent = value.getParent();
            if (parent instanceof XmlAttribute) {
              @NonNls String attrName = ((XmlAttribute) parent).getLocalName();
              if ("jsInBraces".equals(attrName)) {
                registrar.startInjecting(js);
                String text = value.getText();
                int index = 0;
                while (text.indexOf('{', index) != -1) {
                  int lbrace = text.indexOf('{', index);
                  int rbrace = text.indexOf('}', index);
                  registrar.addPlace(
                      "", "", (PsiLanguageInjectionHost) value, new TextRange(lbrace + 1, rbrace));
                  index = rbrace + 1;
                }
                registrar.doneInjecting();
              }
            }
          }

          @Override
          @NotNull
          public List<? extends Class<? extends PsiElement>> elementsToInjectIn() {
            return Arrays.asList(XmlAttributeValue.class);
          }
        };
    InjectedLanguageManager.getInstance(psiManager.getProject())
        .registerMultiHostInjector(myMultiHostInjector);
    Disposer.register(
        parent,
        new Disposable() {
          @Override
          public void dispose() {
            boolean b =
                InjectedLanguageManager.getInstance(psiManager.getProject())
                    .unregisterMultiHostInjector(myMultiHostInjector);
            assert b;
          }
        });

    final LanguageInjector myInjector =
        new LanguageInjector() {
          @Override
          public void getLanguagesToInject(
              @NotNull PsiLanguageInjectionHost host,
              @NotNull InjectedLanguagePlaces placesToInject) {
            if (host instanceof XmlAttributeValue) {
              XmlAttributeValue value = (XmlAttributeValue) host;
              PsiElement parent = value.getParent();
              if (parent instanceof XmlAttribute) {
                @NonNls String attrName = ((XmlAttribute) parent).getLocalName();
                if ("ql".equals(attrName)) {
                  inject(host, placesToInject, ql);
                  return;
                }
                if ("js".equals(attrName)) {
                  inject(host, placesToInject, js);
                  return;
                }

                if ("jsprefix".equals(attrName)) {
                  inject(host, placesToInject, js, "function foo(doc, window){", "}");
                  return;
                }
              }
            }
            if (host instanceof XmlText) {
              // inject to xml tags named 'ql'
              final XmlText xmlText = (XmlText) host;
              XmlTag tag = xmlText.getParentTag();
              if (tag == null) return;
              if ("ql".equals(tag.getLocalName())) {
                inject(host, placesToInject, ql);
                return;
              }
              if ("js".equals(tag.getLocalName())) {
                inject(host, placesToInject, js);
                return;
              }
              if ("htmlInject".equals(tag.getLocalName())) {
                inject(host, placesToInject, html);
                return;
              }
              if (ecma4 != null && "ecma4".equals(tag.getLocalName())) {
                inject(host, placesToInject, ecma4);
                return;
              }
              if ("jsprefix".equals(tag.getLocalName())) {
                inject(host, placesToInject, js, "function foo(doc, window){", "}");
                return;
              }

              if ("jsInHash".equals(tag.getLocalName())) {
                String text = xmlText.getText();
                if (text.contains("#")) {
                  int start = text.indexOf('#');
                  int end = text.lastIndexOf('#');
                  if (start != end && start != -1) {
                    placesToInject.addPlace(js, new TextRange(start + 1, end), null, null);
                    return;
                  }
                }
              }
            }

            if (host instanceof PsiComment
                && ((PsiComment) host).getTokenType() == JavaTokenType.C_STYLE_COMMENT) {
              /* {{{
               *   js code
               *   js code
               * }}}
               */
              String text = host.getText();
              String prefix = "/*\n * {{{\n";
              String suffix = " }}}\n */";
              if (text.startsWith(prefix) && text.endsWith(suffix)) {
                String s = StringUtil.trimEnd(StringUtil.trimStart(text, prefix), suffix);
                int off = 0;
                while (!s.isEmpty()) {
                  String t = s.trim();
                  if (t.startsWith("*")) t = t.substring(1).trim();
                  int i = s.length() - t.length();
                  off += i;
                  int endOfLine = t.indexOf('\n');
                  if (endOfLine == -1) endOfLine = t.length();
                  placesToInject.addPlace(
                      js, TextRange.from(prefix.length() + off, endOfLine), "", "\n");
                  off += endOfLine;
                  s = s.substring(i + endOfLine);
                }
                return;
              }
            }

            if (host instanceof PsiCommentImpl) {
              String text = host.getText();
              if (text.startsWith("/*--{") && text.endsWith("}--*/")) {
                TextRange textRange = new TextRange(4, text.length() - 4);
                if (!(host.getParent() instanceof PsiMethod)) return;
                PsiMethod method = (PsiMethod) host.getParent();
                if (!method.hasModifierProperty(PsiModifier.NATIVE)
                    || !method.hasModifierProperty(PsiModifier.PUBLIC)) return;
                String paramList = "";
                for (PsiParameter parameter : method.getParameterList().getParameters()) {
                  if (!paramList.isEmpty()) paramList += ",";
                  paramList += parameter.getName();
                }
                @NonNls String header = "function " + method.getName() + "(" + paramList + ") {";
                Language gwt = Language.findLanguageByID("GWT JavaScript");
                placesToInject.addPlace(gwt, textRange, header, "}");
                return;
              }
              PsiElement parent = host.getParent();
              if (parent instanceof PsiMethod && ((PsiMethod) parent).getName().equals("xml")) {
                placesToInject.addPlace(
                    StdLanguages.XML, new TextRange(2, host.getTextLength() - 2), null, null);
                return;
              }
            }

            // inject to all string literal initializers of variables named 'ql'
            if (host instanceof PsiLiteralExpression
                && ((PsiLiteralExpression) host).getValue() instanceof String) {
              PsiVariable variable = PsiTreeUtil.getParentOfType(host, PsiVariable.class);
              if (variable == null) return;
              if (host.getParent() instanceof PsiPolyadicExpression) return;
              if ("ql".equals(variable.getName())) {
                placesToInject.addPlace(ql, textRangeToInject(host), null, null);
              }
              if ("xml".equals(variable.getName())) {
                placesToInject.addPlace(StdLanguages.XML, textRangeToInject(host), null, null);
              }
              if ("js".equals(variable.getName())) { // with prefix/suffix
                placesToInject.addPlace(
                    js, textRangeToInject(host), "function foo(doc,window) {", "}");
              }

              if ("lang".equals(variable.getName())) {
                // various lang depending on field "languageID" content
                PsiClass aClass = PsiTreeUtil.getParentOfType(variable, PsiClass.class);
                aClass = aClass.findInnerClassByName("Language", false);
                String text =
                    aClass
                        .getInitializers()[0]
                        .getBody()
                        .getFirstBodyElement()
                        .getNextSibling()
                        .getText()
                        .substring(2);
                Language language = Language.findLanguageByID(text);

                if (language != null) {
                  placesToInject.addPlace(language, textRangeToInject(host), "", "");
                }
              }
            }
          }
        };

    final ExtensionPoint<LanguageInjector> extensionPoint =
        Extensions.getRootArea().getExtensionPoint(LanguageInjector.EXTENSION_POINT_NAME);
    extensionPoint.registerExtension(myInjector);
    Disposer.register(
        parent,
        new Disposable() {
          @Override
          public void dispose() {
            extensionPoint.unregisterExtension(myInjector);
          }
        });
  }