|
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
|
2 // Use of this source code is governed by a BSD-style license that can be |
|
3 // found in the LICENSE file. |
|
4 |
|
5 package org.chromium.debug.core; |
|
6 |
|
7 import org.chromium.debug.core.model.VmResourceId; |
|
8 import org.eclipse.core.resources.IContainer; |
|
9 import org.eclipse.core.resources.IFile; |
|
10 import org.eclipse.core.runtime.CoreException; |
|
11 import org.eclipse.debug.core.sourcelookup.ISourceContainer; |
|
12 import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector; |
|
13 import org.eclipse.debug.core.sourcelookup.containers.ContainerSourceContainer; |
|
14 import org.eclipse.debug.core.sourcelookup.containers.DefaultSourceContainer; |
|
15 |
|
16 /** |
|
17 * Eclipse has a standard facility for looking up source file for a debug artifact. |
|
18 * LiveEdit feature has an opposite problem: find script in remote VM for a particular js file. |
|
19 * This class implements some approach to this problem. An instance of this class corresponds |
|
20 * to a particular debug launch. |
|
21 */ |
|
22 public class ReverseSourceLookup { |
|
23 private final ISourceLookupDirector sourceDirector; |
|
24 |
|
25 public ReverseSourceLookup(ISourceLookupDirector sourceDirector) { |
|
26 this.sourceDirector = sourceDirector; |
|
27 } |
|
28 |
|
29 /** |
|
30 * Tries to find a corresponding script for a file from a user workspace. The method uses |
|
31 * the file name and current source lookup rules to retrieve a resource id, regardless of |
|
32 * whether the resource has actually been loaded into the VM (you may want to set a breakpoint |
|
33 * on resource before it is actually loaded). |
|
34 */ |
|
35 public VmResourceId findVmResource(IFile sourceFile) throws CoreException { |
|
36 for (ISourceContainer container : sourceDirector.getSourceContainers()) { |
|
37 VmResourceId scriptName = tryForContainer(sourceFile, container); |
|
38 if (scriptName != null) { |
|
39 return scriptName; |
|
40 } |
|
41 } |
|
42 return null; |
|
43 } |
|
44 |
|
45 private VmResourceId tryForContainer(IFile sourceFile, ISourceContainer container) |
|
46 throws CoreException { |
|
47 if (container.isComposite() && isSupportedCompositeContainer(container)) { |
|
48 ISourceContainer[] subContainers = container.getSourceContainers(); |
|
49 for (ISourceContainer subContainer : subContainers) { |
|
50 VmResourceId res = tryForContainer(sourceFile, subContainer); |
|
51 if (res != null) { |
|
52 return res; |
|
53 } |
|
54 } |
|
55 return null; |
|
56 } else if (container instanceof VProjectSourceContainer) { |
|
57 VProjectSourceContainer projectSourceContainer = (VProjectSourceContainer) container; |
|
58 return projectSourceContainer.findScriptId(sourceFile); |
|
59 } else { |
|
60 String name = tryForNonVirtualContainer(sourceFile, container); |
|
61 if (name == null) { |
|
62 return null; |
|
63 } |
|
64 return VmResourceId.forName(name); |
|
65 } |
|
66 } |
|
67 |
|
68 /** |
|
69 * We use {@link ISourceContainer#getSourceContainers()} method to unwrap internal containers. |
|
70 * However it doesn't make sense for all composite containers (some of them may return their |
|
71 * subdirectories as containers, which is not what we need). |
|
72 */ |
|
73 private boolean isSupportedCompositeContainer(ISourceContainer container) { |
|
74 return container instanceof DefaultSourceContainer; |
|
75 } |
|
76 |
|
77 /** |
|
78 * @param container that may not wrap VProjectSourceContainer |
|
79 */ |
|
80 private String tryForNonVirtualContainer(IFile resource, ISourceContainer container) { |
|
81 if (container instanceof ContainerSourceContainer) { |
|
82 ContainerSourceContainer containerSourceContainer = (ContainerSourceContainer) container; |
|
83 IContainer resourceContainer = containerSourceContainer.getContainer(); |
|
84 if (resourceContainer.getFullPath().isPrefixOf(resource.getFullPath())) { |
|
85 String name = resource.getFullPath().makeRelativeTo( |
|
86 resourceContainer.getFullPath()).toPortableString(); |
|
87 return name; |
|
88 } |
|
89 } else if (container instanceof SourceNameMapperContainer) { |
|
90 SourceNameMapperContainer mappingContainer = |
|
91 (SourceNameMapperContainer) container; |
|
92 String subResult = tryForNonVirtualContainer(resource, mappingContainer.getTargetContainer()); |
|
93 if (subResult != null) { |
|
94 return mappingContainer.getPrefix() + subResult; |
|
95 } |
|
96 } |
|
97 |
|
98 return null; |
|
99 } |
|
100 } |