com.intellij.xml.index.XmlNamespaceIndex Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of xml-psi-impl Show documentation
Show all versions of xml-psi-impl Show documentation
A packaging of the IntelliJ Community Edition xml-psi-impl library.
This is release number 1 of trunk branch 142.
The newest version!
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.xml.index;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.io.StreamUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.xml.XmlFile;
import com.intellij.util.NullableFunction;
import com.intellij.util.indexing.DataIndexer;
import com.intellij.util.indexing.FileBasedIndex;
import com.intellij.util.indexing.FileContent;
import com.intellij.util.indexing.ID;
import com.intellij.util.io.DataExternalizer;
import com.intellij.util.io.DataInputOutputUtil;
import com.intellij.util.io.IOUtil;
import com.intellij.util.text.CharArrayUtil;
import com.intellij.xml.util.XmlUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.*;
import java.util.*;
/**
* @author Dmitry Avdeev
*/
public class XmlNamespaceIndex extends XmlIndex {
@Nullable
public static String getNamespace(@NotNull VirtualFile file, final Project project, PsiFile context) {
if (DumbService.isDumb(project) || (context != null && XmlUtil.isStubBuilding())) {
return computeNamespace(file);
}
final List list = FileBasedIndex.getInstance().getValues(NAME, file.getUrl(), createFilter(project));
return list.size() == 0 ? null : list.get(0).getNamespace();
}
@Nullable
public static String computeNamespace(@NotNull VirtualFile file) {
InputStream stream = null;
try {
stream = file.getInputStream();
return XsdNamespaceBuilder.computeNamespace(stream);
}
catch (IOException e) {
return null;
}
finally {
StreamUtil.closeStream(stream);
}
}
public static List> getResourcesByNamespace(String namespace,
@NotNull Project project,
@Nullable Module module) {
List> resources =
IndexedRelevantResource.getResources(NAME, namespace, module, project, null);
Collections.sort(resources);
return resources;
}
public static List> getAllResources(@Nullable final Module module,
@NotNull Project project,
@Nullable NullableFunction>, IndexedRelevantResource> chooser) {
return IndexedRelevantResource.getAllResources(NAME, module, project, chooser);
}
public static final ID NAME = ID.create("XmlNamespaces");
@Override
@NotNull
public ID getName() {
return NAME;
}
@Override
@NotNull
public DataIndexer getIndexer() {
return new DataIndexer() {
@Override
@NotNull
public Map map(@NotNull final FileContent inputData) {
final XsdNamespaceBuilder builder;
if ("dtd".equals(inputData.getFile().getExtension())) {
builder = new XsdNamespaceBuilder(inputData.getFileName(), "", Collections.emptyList(), Collections.emptyList());
}
else {
builder = XsdNamespaceBuilder.computeNamespace(CharArrayUtil.readerFromCharSequence(inputData.getContentAsText()));
}
final HashMap map = new HashMap(2);
String namespace = builder.getNamespace();
if (namespace != null) {
map.put(namespace, builder);
}
// so that we could get ns by file url (see getNamespace method above)
map.put(inputData.getFile().getUrl(), builder);
return map;
}
};
}
@NotNull
@Override
public DataExternalizer getValueExternalizer() {
return new DataExternalizer() {
@Override
public void save(@NotNull DataOutput out, XsdNamespaceBuilder value) throws IOException {
IOUtil.writeUTF(out, value.getNamespace() == null ? "" : value.getNamespace());
IOUtil.writeUTF(out, value.getVersion() == null ? "" : value.getVersion());
writeList(out, value.getTags());
writeList(out, value.getRootTags());
}
@Override
public XsdNamespaceBuilder read(@NotNull DataInput in) throws IOException {
return new XsdNamespaceBuilder(IOUtil.readUTF(in),
IOUtil.readUTF(in),
readList(in),
readList(in));
}
};
}
private static void writeList(@NotNull DataOutput out, List tags) throws IOException {
DataInputOutputUtil.writeINT(out, tags.size());
for (String s : tags) {
IOUtil.writeUTF(out, s);
}
}
@NotNull
private static ArrayList readList(@NotNull DataInput in) throws IOException {
int count;
ArrayList tags = new ArrayList(count = DataInputOutputUtil.readINT(in));
for (int i = 0; i < count; i++) {
tags.add(IOUtil.readUTF(in));
}
return tags;
}
@Override
public int getVersion() {
return 4;
}
@Nullable
public static IndexedRelevantResource guessSchema(String namespace,
@Nullable final String tagName,
@Nullable final String version,
@Nullable String schemaLocation,
@Nullable Module module,
@NotNull Project project) {
final List>
resources = getResourcesByNamespace(namespace, project, module);
if (resources.isEmpty()) return null;
if (resources.size() == 1) return resources.get(0);
final String fileName = schemaLocation == null ? null : new File(schemaLocation).getName();
IndexedRelevantResource resource =
Collections.max(resources, new Comparator>() {
@Override
public int compare(IndexedRelevantResource o1,
IndexedRelevantResource o2) {
if (fileName != null) {
int i = Comparing.compare(fileName.equals(o1.getFile().getName()), fileName.equals(o2.getFile().getName()));
if (i != 0) return i;
}
if (tagName != null) {
int i = Comparing.compare(o1.getValue().hasTag(tagName), o2.getValue().hasTag(tagName));
if (i != 0) return i;
}
int i = o1.compareTo(o2);
if (i != 0) return i;
return o1.getValue().getRating(tagName, version) - o2.getValue().getRating(tagName, version);
}
});
if (tagName != null && !resource.getValue().hasTag(tagName)) {
return null;
}
return resource;
}
@Nullable
public static XmlFile guessSchema(String namespace,
@Nullable final String tagName,
@Nullable final String version,
@Nullable String schemaLocation,
@NotNull PsiFile file) {
if (DumbService.isDumb(file.getProject()) || XmlUtil.isStubBuilding()) return null;
IndexedRelevantResource resource =
guessSchema(namespace, tagName, version, schemaLocation, ModuleUtilCore.findModuleForPsiElement(file), file.getProject());
if (resource == null) return null;
return findSchemaFile(resource.getFile(), file);
}
@Nullable
private static XmlFile findSchemaFile(VirtualFile resourceFile, PsiFile baseFile) {
PsiFile psiFile = baseFile.getManager().findFile(resourceFile);
return psiFile instanceof XmlFile ? (XmlFile)psiFile : null;
}
@Nullable
public static XmlFile guessDtd(String dtdUri, @NotNull PsiFile baseFile) {
if (!dtdUri.endsWith(".dtd") ||
DumbService.isDumb(baseFile.getProject()) ||
XmlUtil.isStubBuilding()) return null;
String dtdFileName = new File(dtdUri).getName();
List>
list = getResourcesByNamespace(dtdFileName, baseFile.getProject(), ModuleUtilCore.findModuleForPsiElement(baseFile));
if (list.isEmpty()) {
return null;
}
IndexedRelevantResource resource;
if (list.size() > 1) {
final String[] split = dtdUri.split("/");
resource = Collections.max(list, new Comparator>() {
@Override
public int compare(IndexedRelevantResource o1,
IndexedRelevantResource o2) {
return weight(o1) - weight(o2);
}
int weight(IndexedRelevantResource o1) {
VirtualFile file = o1.getFile();
for (int i = split.length - 1; i >= 0 && file != null; i--) {
String s = split[i];
if (!s.equals(file.getName())) {
return split.length - i;
}
file = file.getParent();
}
return 0;
}
});
}
else {
resource = list.get(0);
}
return findSchemaFile(resource.getFile(), baseFile);
}
}