diff --git a/platform/analysis-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReference.java b/platform/analysis-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReference.java index 8e249af6c201..7669ee88b656 100644 --- a/platform/analysis-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReference.java +++ b/platform/analysis-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReference.java @@ -183,6 +183,13 @@ public class FileReference implements PsiFileReference, FileReferenceOwner, PsiP if (context instanceof PackagePrefixFileSystemItem) { context = ((PackagePrefixFileSystemItem)context).getDirectory(); } + else if (context instanceof FileReferenceResolver) { + PsiFileSystemItem child = ((FileReferenceResolver)context).resolveFileReference(this, decoded); + if (child != null) { + result.add(new PsiElementResolveResult(getOriginalFile(child))); + return; + } + } if (context.getParent() == null && FileUtil.namesEqual(decoded, context.getName())) { // match filesystem roots diff --git a/platform/analysis-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReferenceResolver.java b/platform/analysis-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReferenceResolver.java new file mode 100644 index 000000000000..3f11fb6c7458 --- /dev/null +++ b/platform/analysis-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReferenceResolver.java @@ -0,0 +1,10 @@ +package com.intellij.psi.impl.source.resolve.reference.impl.providers; + +import com.intellij.psi.PsiFileSystemItem; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public interface FileReferenceResolver { + @Nullable + PsiFileSystemItem resolveFileReference(@NotNull FileReference reference, @NotNull String name); +} \ No newline at end of file diff --git a/platform/core-api/src/com/intellij/openapi/vfs/ex/http/HttpFileSystem.java b/platform/core-api/src/com/intellij/openapi/vfs/ex/http/HttpFileSystem.java index 9ab4fd341e87..a42441fe49de 100644 --- a/platform/core-api/src/com/intellij/openapi/vfs/ex/http/HttpFileSystem.java +++ b/platform/core-api/src/com/intellij/openapi/vfs/ex/http/HttpFileSystem.java @@ -42,4 +42,5 @@ public abstract class HttpFileSystem extends DeprecatedVirtualFileSystem { public abstract void removeFileListener(@NotNull HttpVirtualFileListener listener); + public abstract VirtualFile createChild(@NotNull VirtualFile parent, @NotNull String name, boolean isDirectory); } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/HttpFileReferenceHelper.java b/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/HttpFileReferenceHelper.java new file mode 100644 index 000000000000..96da73032e94 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/HttpFileReferenceHelper.java @@ -0,0 +1,36 @@ +package com.intellij.psi.impl.source.resolve.reference.impl.providers; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.impl.http.HttpVirtualFile; +import com.intellij.psi.PsiFileSystemItem; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.Collections; + +final class HttpFileReferenceHelper extends FileReferenceHelper { + @Nullable + @Override + public PsiFileSystemItem findRoot(Project project, @NotNull VirtualFile file) { + VirtualFile root = file; + VirtualFile parent; + while ((parent = root.getParent()) != null) { + root = parent; + } + return getPsiFileSystemItem(project, root); + } + + @NotNull + @Override + public Collection getContexts(Project project, @NotNull VirtualFile file) { + PsiFileSystemItem item = getPsiFileSystemItem(project, file); + return item == null ? Collections.emptyList() : Collections.singleton(item); + } + + @Override + public boolean isMine(Project project, @NotNull VirtualFile file) { + return file instanceof HttpVirtualFile; + } +} \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/http/HttpFileSystemBase.java b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/http/HttpFileSystemBase.java index 752442007413..7177138d1d9a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/http/HttpFileSystemBase.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/http/HttpFileSystemBase.java @@ -41,12 +41,7 @@ public abstract class HttpFileSystemBase extends HttpFileSystem { } public VirtualFile findFileByPath(@NotNull String path, boolean isDirectory) { - try { - return getRemoteFileManager().getOrCreateFile(Urls.newFromIdea(VirtualFileManager.constructUrl(myProtocol, path)), path, isDirectory); - } - catch (IOException e) { - return null; - } + return getRemoteFileManager().getOrCreateFile(null, Urls.newFromIdea(VirtualFileManager.constructUrl(myProtocol, path)), path, isDirectory); } @Override @@ -69,16 +64,22 @@ public abstract class HttpFileSystemBase extends HttpFileSystem { return file instanceof HttpVirtualFile && ((HttpVirtualFile)file).getFileInfo().getState() == RemoteFileState.DOWNLOADED; } + @Override + @NotNull + public VirtualFile createChild(@NotNull VirtualFile parent, @NotNull String name, boolean isDirectory) { + return getRemoteFileManager().getOrCreateFile((VirtualFileImpl)parent, Urls.newFromIdea(parent.getUrl() + '/' + name), parent.getPath() + '/' + name, isDirectory); + } + @Override @NotNull public VirtualFile createChildDirectory(Object requestor, @NotNull VirtualFile vDir, @NotNull String dirName) throws IOException { - throw new UnsupportedOperationException(); + return createChild(vDir, dirName, true); } @NotNull @Override public VirtualFile createChildFile(Object requestor, @NotNull VirtualFile vDir, @NotNull String fileName) throws IOException { - throw new UnsupportedOperationException(); + return createChild(vDir, fileName, false); } @Override diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/http/RemoteFileManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/http/RemoteFileManagerImpl.java index a514518cb94a..b69c0befd376 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/http/RemoteFileManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/http/RemoteFileManagerImpl.java @@ -24,8 +24,8 @@ import com.intellij.util.EventDispatcher; import com.intellij.util.Url; import gnu.trove.THashMap; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -55,17 +55,17 @@ public class RemoteFileManagerImpl extends RemoteFileManager implements Disposab return myDefaultRemoteContentProvider; } - public synchronized VirtualFileImpl getOrCreateFile(final @NotNull Url url, final @NotNull String path, final boolean directory) throws IOException { + public synchronized VirtualFileImpl getOrCreateFile(@Nullable VirtualFileImpl parent, @NotNull Url url, @NotNull String path, final boolean directory) { Pair key = Pair.create(directory, url); VirtualFileImpl file = myRemoteFiles.get(key); if (file == null) { - if (!directory) { - RemoteFileInfoImpl fileInfo = new RemoteFileInfoImpl(url, this); - file = new VirtualFileImpl(getHttpFileSystem(url), path, fileInfo); - fileInfo.addDownloadingListener(new MyDownloadingListener(file)); + if (directory) { + file = new VirtualFileImpl(getHttpFileSystem(url), parent, path, null); } else { - file = new VirtualFileImpl(getHttpFileSystem(url), path, null); + RemoteFileInfoImpl fileInfo = new RemoteFileInfoImpl(url, this); + file = new VirtualFileImpl(getHttpFileSystem(url), parent, path, fileInfo); + fileInfo.addDownloadingListener(new MyDownloadingListener(file)); } myRemoteFiles.put(key, file); } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/http/VirtualFileImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/http/VirtualFileImpl.java index 873ac0200b16..ba49cfb5a690 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/http/VirtualFileImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/http/VirtualFileImpl.java @@ -18,17 +18,22 @@ package com.intellij.openapi.vfs.impl.http; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileSystem; import com.intellij.util.ArrayUtil; import com.intellij.util.FileContentUtilCore; +import com.intellij.util.SmartList; import com.intellij.util.UriUtil; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.List; class VirtualFileImpl extends HttpVirtualFile { private final HttpFileSystemBase myFileSystem; @@ -38,7 +43,16 @@ class VirtualFileImpl extends HttpVirtualFile { private final String myParentPath; private final String myName; - VirtualFileImpl(HttpFileSystemBase fileSystem, String path, @Nullable final RemoteFileInfoImpl fileInfo) { + private List myChildren; + + VirtualFileImpl(@NotNull HttpFileSystemBase fileSystem, @Nullable VirtualFileImpl parent, String path, @Nullable RemoteFileInfoImpl fileInfo) { + if (parent != null) { + if (parent.myChildren == null) { + parent.myChildren = new SmartList(); + } + parent.myChildren.add(this); + } + myFileSystem = fileSystem; myPath = path; myFileInfo = fileInfo; @@ -142,7 +156,20 @@ class VirtualFileImpl extends HttpVirtualFile { @Override public VirtualFile[] getChildren() { - return EMPTY_ARRAY; + return ContainerUtil.isEmpty(myChildren) ? EMPTY_ARRAY : myChildren.toArray(new VirtualFile[myChildren.size()]); + } + + @Nullable + @Override + public VirtualFile findChild(@NotNull @NonNls String name) { + if (!ContainerUtil.isEmpty(myChildren)) { + for (VirtualFile child : myChildren) { + if (StringUtil.equals(child.getNameSequence(), name)) { + return child; + } + } + } + return null; } @Override diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index ec1ee6d92152..c53b98798a26 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -744,6 +744,7 @@ + diff --git a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/html/HtmlFileImpl.java b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/html/HtmlFileImpl.java index 90ca5605c426..86b2368b6489 100644 --- a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/html/HtmlFileImpl.java +++ b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/html/HtmlFileImpl.java @@ -16,21 +16,30 @@ package com.intellij.psi.impl.source.html; import com.intellij.lang.ASTNode; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.ex.http.HttpFileSystem; +import com.intellij.openapi.vfs.impl.http.HttpVirtualFile; import com.intellij.psi.FileViewProvider; +import com.intellij.psi.PsiFileSystemItem; +import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReference; +import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReferenceResolver; import com.intellij.psi.impl.source.tree.CompositeElement; import com.intellij.psi.impl.source.xml.XmlFileImpl; import com.intellij.psi.xml.XmlDocument; import com.intellij.psi.xml.XmlElementType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * @author maxim */ -public class HtmlFileImpl extends XmlFileImpl { +public class HtmlFileImpl extends XmlFileImpl implements FileReferenceResolver { public HtmlFileImpl(FileViewProvider provider) { super(provider, XmlElementType.HTML_FILE); } public String toString() { + return "HtmlFile:" + getName(); } @@ -41,4 +50,33 @@ public class HtmlFileImpl extends XmlFileImpl { ASTNode node = treeElement.findChildByType(XmlElementType.HTML_DOCUMENT); return node != null ? (XmlDocument)node.getPsi() : null; } + + @Nullable + @Override + public PsiFileSystemItem resolveFileReference(@NotNull FileReference reference, @NotNull String name) { + VirtualFile file = getVirtualFile(); + if (!(file instanceof HttpVirtualFile)) { + return null; + } + + VirtualFile childFile = file.findChild(name); + HttpFileSystem fileSystem = (HttpFileSystem)getVirtualFile().getFileSystem(); + if (childFile == null) { + childFile = fileSystem.createChild(getVirtualFile(), name, !reference.isLast()); + } + if (childFile.isDirectory()) { + // pre create children + VirtualFile childParent = childFile; + FileReference[] references = reference.getFileReferenceSet().getAllReferences(); + for (int i = reference.getIndex() + 1, n = references.length; i < n; i++) { + FileReference childReference = references[i]; + childParent = fileSystem.createChild(childParent, childReference.decode(childReference.getText()), i != (n - 1)); + } + + return getManager().findDirectory(childFile); + } + else { + return getManager().findFile(childFile); + } + } }