org.chromium.debug.core/src/org/chromium/debug/core/ReverseSourceLookup.java
changeset 355 8726e95bcbba
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.chromium.debug.core/src/org/chromium/debug/core/ReverseSourceLookup.java	Mon Jun 07 16:51:19 2010 -0700
@@ -0,0 +1,100 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.debug.core;
+
+import org.chromium.debug.core.model.VmResourceId;
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.sourcelookup.ISourceContainer;
+import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector;
+import org.eclipse.debug.core.sourcelookup.containers.ContainerSourceContainer;
+import org.eclipse.debug.core.sourcelookup.containers.DefaultSourceContainer;
+
+/**
+ * Eclipse has a standard facility for looking up source file for a debug artifact.
+ * LiveEdit feature has an opposite problem: find script in remote VM for a particular js file.
+ * This class implements some approach to this problem. An instance of this class corresponds
+ * to a particular debug launch.
+ */
+public class ReverseSourceLookup {
+  private final ISourceLookupDirector sourceDirector;
+
+  public ReverseSourceLookup(ISourceLookupDirector sourceDirector) {
+    this.sourceDirector = sourceDirector;
+  }
+
+  /**
+   * Tries to find a corresponding script for a file from a user workspace. The method uses
+   * the file name and current source lookup rules to retrieve a resource id, regardless of
+   * whether the resource has actually been loaded into the VM (you may want to set a breakpoint
+   * on resource before it is actually loaded).
+   */
+  public VmResourceId findVmResource(IFile sourceFile) throws CoreException {
+    for (ISourceContainer container : sourceDirector.getSourceContainers()) {
+      VmResourceId scriptName = tryForContainer(sourceFile, container);
+      if (scriptName != null) {
+        return scriptName;
+      }
+    }
+    return null;
+  }
+
+  private VmResourceId tryForContainer(IFile sourceFile, ISourceContainer container)
+      throws CoreException {
+    if (container.isComposite() && isSupportedCompositeContainer(container)) {
+      ISourceContainer[] subContainers = container.getSourceContainers();
+      for (ISourceContainer subContainer : subContainers) {
+        VmResourceId res = tryForContainer(sourceFile, subContainer);
+        if (res != null) {
+          return res;
+        }
+      }
+      return null;
+    } else if (container instanceof VProjectSourceContainer) {
+      VProjectSourceContainer projectSourceContainer = (VProjectSourceContainer) container;
+      return projectSourceContainer.findScriptId(sourceFile);
+    } else {
+      String name = tryForNonVirtualContainer(sourceFile, container);
+      if (name == null) {
+        return null;
+      }
+      return VmResourceId.forName(name);
+    }
+  }
+
+  /**
+   * We use {@link ISourceContainer#getSourceContainers()} method to unwrap internal containers.
+   * However it doesn't make sense for all composite containers (some of them may return their
+   * subdirectories as containers, which is not what we need).
+   */
+  private boolean isSupportedCompositeContainer(ISourceContainer container) {
+    return container instanceof DefaultSourceContainer;
+  }
+
+  /**
+   * @param container that may not wrap VProjectSourceContainer
+   */
+  private String tryForNonVirtualContainer(IFile resource, ISourceContainer container) {
+    if (container instanceof ContainerSourceContainer) {
+      ContainerSourceContainer containerSourceContainer = (ContainerSourceContainer) container;
+      IContainer resourceContainer = containerSourceContainer.getContainer();
+      if (resourceContainer.getFullPath().isPrefixOf(resource.getFullPath())) {
+        String name = resource.getFullPath().makeRelativeTo(
+            resourceContainer.getFullPath()).toPortableString();
+        return name;
+      }
+    } else if (container instanceof SourceNameMapperContainer) {
+      SourceNameMapperContainer mappingContainer =
+          (SourceNameMapperContainer) container;
+      String subResult = tryForNonVirtualContainer(resource, mappingContainer.getTargetContainer());
+      if (subResult != null) {
+        return mappingContainer.getPrefix() + subResult;
+      }
+    }
+
+    return null;
+  }
+}