<commit_before>// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.xml.util.documentation;

import com.intellij.codeInsight.lookup.LookupManager;
import com.intellij.lang.Language;
import com.intellij.lang.LanguageDocumentation;
import com.intellij.lang.documentation.DocumentationProvider;
import com.intellij.lang.documentation.ExternalDocumentationProvider;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.ThrowableComputable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.impl.FakePsiElement;
import com.intellij.psi.impl.source.html.dtd.HtmlAttributeDescriptorImpl;
import com.intellij.psi.impl.source.html.dtd.HtmlElementDescriptorImpl;
import com.intellij.psi.impl.source.xml.SchemaPrefix;
import com.intellij.psi.meta.PsiMetaData;
import com.intellij.psi.presentation.java.SymbolPresentationUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.*;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.concurrency.SynchronizedClearableLazy;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.xml.XmlAttributeDescriptor;
import com.intellij.xml.XmlElementDescriptor;
import com.intellij.xml.util.XmlUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;

import java.util.Collections;
import java.util.List;
import java.util.Map;

import static com.intellij.codeInsight.documentation.DocumentationManager.ORIGINAL_ELEMENT_KEY;

/**
 * @author maxim
 */
public class HtmlDocumentationProvider implements DocumentationProvider, ExternalDocumentationProvider {
  private static final ExtensionPointName<DocumentationProvider> SCRIPT_PROVIDER_EP_NAME = ExtensionPointName.create("com.intellij.html.scriptDocumentationProvider");

  private final boolean myUseStyleProvider;

  @NonNls public static final String ELEMENT_ELEMENT_NAME = "element";
  @NonNls public static final String NBSP = ":&nbsp;";
  @NonNls public static final String BR = "<br>";

  private static final SynchronizedClearableLazy<DocumentationProvider> ourScriptProvider = new SynchronizedClearableLazy<>(() -> {
    //noinspection CodeBlock2Expr
    return ContainerUtil.getFirstItem(SCRIPT_PROVIDER_EP_NAME.getExtensionList());
  });

  public HtmlDocumentationProvider() {
    this(true);
  }

  public HtmlDocumentationProvider(boolean useStyleProvider) {
    myUseStyleProvider = useStyleProvider;
  }

  @Override
  @Nullable
  public String getQuickNavigateInfo(PsiElement element, PsiElement originalElement) {
    if (element instanceof SchemaPrefix) {
      return ((SchemaPrefix)element).getQuickNavigateInfo();
    }
    return null;
  }

  @Override
  public List<String> getUrlFor(PsiElement element, PsiElement originalElement) {
    String result = getUrlForHtml(element, originalElement, PsiTreeUtil.getParentOfType(originalElement, XmlTag.class, false));
    DocumentationProvider styleProvider = getStyleProvider();
    if (result == null && styleProvider != null) {
      return styleProvider.getUrlFor(element, originalElement);
    }

    return result != null ? Collections.singletonList(result) : null;
  }

  @Nullable
  @Override
  public String fetchExternalDocumentation(Project project, PsiElement element, List<String> docUrls) {
    final XmlTag tag = element instanceof XmlElement ?
                       ReadAction.compute(() -> PsiTreeUtil.getParentOfType(element, XmlTag.class, false)) :
                       null;
    final SmartPsiElementPointer pointer = element.getUserData(ORIGINAL_ELEMENT_KEY);
    PsiElement originalElement = pointer != null ?
                                 ReadAction.compute((ThrowableComputable<PsiElement, RuntimeException>)pointer::getElement) :
                                 element;
    final DocEntity entity = ReadAction.compute(() -> findDocumentationEntity(element, tag));
    for (String url : docUrls) {
      if (url.contains("#attr-")) return null;
    }

    String mdnDoc = MdnDocumentationUtil.fetchExternalDocumentation(docUrls, () -> null);
    if (mdnDoc != null) {
      String name = entity != null ? entity.name : ReadAction.compute(() -> SymbolPresentationUtil.getSymbolPresentableText(element));
      Map mdnCompatData = ReadAction.compute(() -> getCompatData(entity, originalElement));
      return MdnDocumentationUtil.buildDoc(name, mdnDoc, mdnCompatData);
    }
    return null;
  }

  @Override
  public boolean hasDocumentationFor(PsiElement element, PsiElement originalElement) {
    return false;
  }

  @Override
  public boolean canPromptToConfigureDocumentation(PsiElement element) {
    return false;
  }

  @Override
  public void promptToConfigureDocumentation(PsiElement element) {}

  public static String getUrlForHtml(PsiElement element, PsiElement originalElement, XmlTag context) {
    final DocEntity entity = findDocumentationEntity(element, context);
    String mdnUrl = MdnDocumentationUtil.getMdnUrl(getCompatData(entity, originalElement));
    if (mdnUrl != null) return mdnUrl;<commit_msg>WEB-42029 Broken documentation for TS/JS library symbols in HTML files<commit_after>// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.xml.util.documentation;

import com.intellij.codeInsight.lookup.LookupManager;
import com.intellij.lang.Language;
import com.intellij.lang.LanguageDocumentation;
import com.intellij.lang.documentation.DocumentationProvider;
import com.intellij.lang.documentation.ExternalDocumentationProvider;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.ThrowableComputable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.impl.FakePsiElement;
import com.intellij.psi.impl.source.html.dtd.HtmlAttributeDescriptorImpl;
import com.intellij.psi.impl.source.html.dtd.HtmlElementDescriptorImpl;
import com.intellij.psi.impl.source.xml.SchemaPrefix;
import com.intellij.psi.meta.PsiMetaData;
import com.intellij.psi.presentation.java.SymbolPresentationUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.*;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.concurrency.SynchronizedClearableLazy;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.xml.XmlAttributeDescriptor;
import com.intellij.xml.XmlElementDescriptor;
import com.intellij.xml.util.XmlUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;

import java.util.Collections;
import java.util.List;
import java.util.Map;

import static com.intellij.codeInsight.documentation.DocumentationManager.ORIGINAL_ELEMENT_KEY;

/**
 * @author maxim
 */
public class HtmlDocumentationProvider implements DocumentationProvider, ExternalDocumentationProvider {
  private static final ExtensionPointName<DocumentationProvider> SCRIPT_PROVIDER_EP_NAME = ExtensionPointName.create("com.intellij.html.scriptDocumentationProvider");

  private final boolean myUseStyleProvider;

  @NonNls public static final String ELEMENT_ELEMENT_NAME = "element";
  @NonNls public static final String NBSP = ":&nbsp;";
  @NonNls public static final String BR = "<br>";

  private static final SynchronizedClearableLazy<DocumentationProvider> ourScriptProvider = new SynchronizedClearableLazy<>(() -> {
    //noinspection CodeBlock2Expr
    return ContainerUtil.getFirstItem(SCRIPT_PROVIDER_EP_NAME.getExtensionList());
  });

  public HtmlDocumentationProvider() {
    this(true);
  }

  public HtmlDocumentationProvider(boolean useStyleProvider) {
    myUseStyleProvider = useStyleProvider;
  }

  @Override
  @Nullable
  public String getQuickNavigateInfo(PsiElement element, PsiElement originalElement) {
    if (element instanceof SchemaPrefix) {
      return ((SchemaPrefix)element).getQuickNavigateInfo();
    }
    return null;
  }

  @Override
  public List<String> getUrlFor(PsiElement element, PsiElement originalElement) {
    String result = getUrlForHtml(element, originalElement, PsiTreeUtil.getParentOfType(originalElement, XmlTag.class, false));
    DocumentationProvider styleProvider = getStyleProvider();
    if (result == null && styleProvider != null) {
      return styleProvider.getUrlFor(element, originalElement);
    }

    return result != null ? Collections.singletonList(result) : null;
  }

  @Nullable
  @Override
  public String fetchExternalDocumentation(Project project, PsiElement element, List<String> docUrls) {
    final XmlTag tag = element instanceof XmlElement ?
                       ReadAction.compute(() -> PsiTreeUtil.getParentOfType(element, XmlTag.class, false)) :
                       null;
    final SmartPsiElementPointer<?> pointer = element.getUserData(ORIGINAL_ELEMENT_KEY);
    PsiElement originalElement = pointer != null ?
                                 ReadAction.compute((ThrowableComputable<PsiElement, RuntimeException>)pointer::getElement) :
                                 element;
    if (originalElement != null && !(originalElement instanceof XmlElement)) {
      return null;
    }
    final DocEntity entity = ReadAction.compute(() -> findDocumentationEntity(element, tag));
    for (String url : docUrls) {
      if (url.contains("#attr-")) return null;
    }

    String mdnDoc = MdnDocumentationUtil.fetchExternalDocumentation(docUrls, () -> null);
    if (mdnDoc != null) {
      String name = entity != null ? entity.name : ReadAction.compute(() -> SymbolPresentationUtil.getSymbolPresentableText(element));
      Map mdnCompatData = ReadAction.compute(() -> getCompatData(entity, originalElement));
      return MdnDocumentationUtil.buildDoc(name, mdnDoc, mdnCompatData);
    }
    return null;
  }

  @Override
  public boolean hasDocumentationFor(PsiElement element, PsiElement originalElement) {
    return false;
  }

  @Override
  public boolean canPromptToConfigureDocumentation(PsiElement element) {
    return false;
  }

  @Override
  public void promptToConfigureDocumentation(PsiElement element) {}

  public static String getUrlForHtml(PsiElement element, PsiElement originalElement, XmlTag context) {
    final DocEntity entity = findDocumentationEntity(element, context);
    String mdnUrl = MdnDocumentationUtil.getMdnUrl(getCompatData(entity, originalElement));
    if (mdnUrl != null) return mdnUrl;
{'fraction_non_alphanumeric': 0.09182761087267526, 'fraction_numerical': 0.0024141630901287556, 'mean_word_length': 5.000536480686695, 'pattern_counts': {'":': 2, '<': 18, '<?xml version=': 0, '>': 30, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 12}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6544284', 'n_tokens_mistral': 3236, 'n_tokens_neox': 3143, 'n_words': 654}