package com.jetbrains.lang.dart.ide; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.search.FilenameIndex; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.util.SmartList; import com.intellij.util.Url; import com.intellij.util.Urls; import com.jetbrains.javascript.debugger.FileUrlMapper; import com.jetbrains.lang.dart.DartFileType; import com.jetbrains.lang.dart.pubServer.PubServerManager; import com.jetbrains.lang.dart.sdk.DartSdk; import com.jetbrains.lang.dart.util.DartUrlResolver; import com.jetbrains.lang.dart.util.PubspecYamlUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.builtInWebServer.WebServerPathToFileManager; import org.jetbrains.ide.BuiltInServerManagerImpl; import java.util.Collections; import java.util.List; import static com.jetbrains.lang.dart.util.DartUrlResolver.PACKAGE_PREFIX; import static com.jetbrains.lang.dart.util.PubspecYamlUtil.PUBSPEC_YAML; final class DartFileUrlMapper extends FileUrlMapper { private static final String SDK_URL_MARKER = "/packages/$sdk/lib/"; private static final String PACKAGE_URL_MARKER = "/" + DartUrlResolver.PACKAGES_FOLDER_NAME + "/"; @NotNull @Override public List<Url> getUrls(@NotNull final VirtualFile file, @NotNull final Project project, @Nullable final String currentAuthority) { if (currentAuthority == null || file.getFileType() != DartFileType.INSTANCE) return Collections.emptyList(); final String dartUri = DartUrlResolver.getInstance(project, file).getDartUrlForFile(file); if (!dartUri.startsWith(PACKAGE_PREFIX)) return Collections.emptyList(); if (BuiltInServerManagerImpl.isOnBuiltInWebServerByAuthority(currentAuthority)) { // for built-in server: // package:PackageName/subdir/foo.dart -> http://localhost:63342/ProjectName/MayBeRelPathToDartProject/web/packages/PackageName/subdir/foo.dart final VirtualFile pubspec = PubspecYamlUtil.findPubspecYamlFile(project, file); if (pubspec == null) return Collections.emptyList(); final VirtualFile dartRoot = pubspec.getParent(); final String dartRootUrlPath = WebServerPathToFileManager.getInstance(project).getPath(dartRoot); if (dartRootUrlPath == null) return Collections.emptyList(); //BuiltInWebBrowserUrlProviderKt.getBuiltInServerUrls(pubspec, project, currentAuthority); final Url dartRootUrl = Urls.newHttpUrl(currentAuthority, "/" + project.getName() + "/" + dartRootUrlPath); final String urlPath = StringUtil.trimEnd(dartRootUrl.getPath(), "/") + "/web/packages/" + dartUri.substring(PACKAGE_PREFIX.length()); final List<Url> result = new SmartList<>(); result.add(Urls.newHttpUrl(currentAuthority, urlPath)); if (Registry.is("dart.redirect.to.pub.server", true)) { for (String pubAuthority : PubServerManager.getInstance(project).getAlivePubServerAuthorities(dartRoot)) { final String pubUrlPath = "/packages/" + dartUri.substring(PACKAGE_PREFIX.length()); result.add(Urls.newHttpUrl(pubAuthority, pubUrlPath)); } } return result; } else { // for any other server (e.g. localhost:8181): // package:PackageName/subdir/foo.dart -> http://localhost:8181/packages/PackageName/subdir/foo.dart final String urlPath = "/packages/" + dartUri.substring(PACKAGE_PREFIX.length()); return Collections.singletonList(Urls.newHttpUrl(currentAuthority, urlPath)); } } @Nullable @Override public VirtualFile getFile(@NotNull final Url url, @NotNull final Project project, @Nullable Url requestor) { final String scheme = url.getScheme(); final String path = url.getPath(); if (DartUrlResolver.DART_SCHEME.equals(scheme)) { return DartUrlResolver.findFileInDartSdkLibFolder(project, DartSdk.getDartSdk(project), DartUrlResolver.DART_PREFIX + path); } if (DartUrlResolver.PACKAGE_SCHEME.equals(scheme)) { final String packageUri = PACKAGE_PREFIX + path; final VirtualFile contextFile = findContextFile(project, requestor); if (contextFile != null) { return ReadAction.compute(() -> DartUrlResolver.getInstance(project, contextFile).findFileByDartUrl(packageUri)); } else { if (ApplicationManager.getApplication().isDispatchThread()) { return DumbService.getInstance(project).isDumb() ? null : findFileInAnyPackagesFolder(project, packageUri); } return DumbService.getInstance(project).runReadActionInSmartMode(() -> findFileInAnyPackagesFolder(project, packageUri)); } } if ("http".equalsIgnoreCase(scheme)) { final int sdkUrlMarkerIndex = path.indexOf(SDK_URL_MARKER); if (sdkUrlMarkerIndex >= 0) { // http://localhost:63343/dart-tagtree/example/packages/$sdk/lib/_internal/js_runtime/lib/js_helper.dart final String relPath = path.substring(sdkUrlMarkerIndex + SDK_URL_MARKER.length()); return DartUrlResolver.findFileInDartSdkLibFolder(project, DartSdk.getDartSdk(project), DartUrlResolver.DART_PREFIX + relPath); } final int packageUrlMarkerIndex = path.lastIndexOf(PACKAGE_URL_MARKER); if (packageUrlMarkerIndex >= 0) { // http://localhost:63343/DartSample2/web/packages/browser/dart.js or http://localhost:63343/DartSample2/packages/DartSample2/src/myFile.dart // First make sure that this URL relates to Dart. 'packageUrlMarkerIndex >= 0' condition is not strict enough to guarantee that this is a Dart project final VirtualFile contextFile = findContextFile(project, requestor); if (contextFile != null) { final String packageUri = PACKAGE_PREFIX + path.substring(packageUrlMarkerIndex + PACKAGE_URL_MARKER.length()); return ReadAction.compute(() -> DartUrlResolver.getInstance(project, contextFile).findFileByDartUrl(packageUri)); } } } return null; } @Nullable private static VirtualFile findContextFile(final @NotNull Project project, final @Nullable Url url) { if (url == null) return null; for (FileUrlMapper urlMapper : FileUrlMapper.EP_NAME.getExtensions()) { if (urlMapper instanceof DartFileUrlMapper) continue; final VirtualFile file = urlMapper.getFile(url, project, url); if (file != null) return file; } return null; } @Nullable private static VirtualFile findFileInAnyPackagesFolder(final @NotNull Project project, final @NotNull String packageUrl) { for (final VirtualFile yamlFile : FilenameIndex.getVirtualFilesByName(project, PUBSPEC_YAML, GlobalSearchScope.projectScope(project))) { final VirtualFile file = DartUrlResolver.getInstance(project, yamlFile).findFileByDartUrl(packageUrl); if (file != null) return file; } return null; } @Nullable @Override public FileType getFileType(@NotNull Url url) { return DartUrlResolver.DART_SCHEME.equals(url.getScheme()) || DartUrlResolver.PACKAGE_SCHEME.equals(url.getScheme()) ? DartFileType.INSTANCE : null; } }