|
1 package org.chromium.debug.core; |
|
2 |
|
3 import org.eclipse.core.runtime.CoreException; |
|
4 import org.eclipse.core.runtime.IStatus; |
|
5 import org.eclipse.core.runtime.Status; |
|
6 import org.eclipse.debug.core.DebugPlugin; |
|
7 import org.eclipse.debug.core.sourcelookup.ISourceContainer; |
|
8 import org.eclipse.debug.core.sourcelookup.ISourceContainerType; |
|
9 import org.eclipse.debug.core.sourcelookup.ISourceContainerTypeDelegate; |
|
10 import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector; |
|
11 import org.eclipse.osgi.util.NLS; |
|
12 |
|
13 /** |
|
14 * A special type of container that translates names of the source and delegates lookup |
|
15 * to another source container. |
|
16 * This could be useful when JS resource name is like "http://localhost/scripts/util.js"; such |
|
17 * source name could be converted into "scripts/util.js". |
|
18 * Currently container supports only prefix-based translation: if source name starts with a prefix, |
|
19 * the prefix is truncated; otherwise the source name is discarded. |
|
20 */ |
|
21 public class SourceNameMapperContainer implements ISourceContainer { |
|
22 |
|
23 private static final String TYPE_ID = |
|
24 "org.chromium.debug.core.SourceNameMapperContainer.type"; //$NON-NLS-1$ |
|
25 |
|
26 private final ISourceContainer targetContainer; |
|
27 private final String prefix; |
|
28 |
|
29 public SourceNameMapperContainer(String prefix, ISourceContainer targetContainer) { |
|
30 this.targetContainer = targetContainer; |
|
31 this.prefix = prefix; |
|
32 } |
|
33 |
|
34 public void dispose() { |
|
35 } |
|
36 |
|
37 public String getPrefix() { |
|
38 return prefix; |
|
39 } |
|
40 |
|
41 public ISourceContainer getTargetContainer() { |
|
42 return targetContainer; |
|
43 } |
|
44 |
|
45 public Object[] findSourceElements(String name) throws CoreException { |
|
46 if (!name.startsWith(prefix)) { |
|
47 return new Object[0]; |
|
48 } |
|
49 String shortName = name.substring(prefix.length()); |
|
50 return targetContainer.findSourceElements(shortName); |
|
51 } |
|
52 |
|
53 |
|
54 public String getName() { |
|
55 return NLS.bind(Messages.SourceNameMapperContainer_NAME, prefix); |
|
56 } |
|
57 |
|
58 |
|
59 public ISourceContainer[] getSourceContainers() { |
|
60 return new ISourceContainer[] { targetContainer }; |
|
61 } |
|
62 |
|
63 |
|
64 public ISourceContainerType getType() { |
|
65 return DebugPlugin.getDefault().getLaunchManager().getSourceContainerType(TYPE_ID); |
|
66 } |
|
67 |
|
68 |
|
69 public void init(ISourceLookupDirector director) { |
|
70 } |
|
71 |
|
72 |
|
73 public boolean isComposite() { |
|
74 return true; |
|
75 } |
|
76 |
|
77 private String getMemento() throws CoreException { |
|
78 StringBuilder builder = new StringBuilder(); |
|
79 MementoFormat.encodeComponent(prefix, builder); |
|
80 MementoFormat.encodeComponent(targetContainer.getType().getId(), builder); |
|
81 MementoFormat.encodeComponent(targetContainer.getType().getMemento(targetContainer), builder); |
|
82 return builder.toString(); |
|
83 } |
|
84 |
|
85 |
|
86 public Object getAdapter(Class adapter) { |
|
87 return null; |
|
88 } |
|
89 |
|
90 /** |
|
91 * A type delegate that serializes/deserializes container instances into/from memento. |
|
92 */ |
|
93 public static class TypeDelegate implements ISourceContainerTypeDelegate { |
|
94 public ISourceContainer createSourceContainer(String memento) throws CoreException { |
|
95 MementoFormat.Parser parser = new MementoFormat.Parser(memento); |
|
96 String prefix; |
|
97 String typeId; |
|
98 String subContainerMemento; |
|
99 try { |
|
100 prefix = parser.nextComponent(); |
|
101 typeId = parser.nextComponent(); |
|
102 subContainerMemento = parser.nextComponent(); |
|
103 } catch (MementoFormat.ParserException e) { |
|
104 throw new CoreException(new Status(IStatus.ERROR, |
|
105 ChromiumDebugPlugin.PLUGIN_ID, "Failed to parse memento", e)); //$NON-NLS-1$ |
|
106 } |
|
107 ISourceContainerType subContainerType = |
|
108 DebugPlugin.getDefault().getLaunchManager().getSourceContainerType(typeId); |
|
109 ISourceContainer subContainer = subContainerType.createSourceContainer(subContainerMemento); |
|
110 return new SourceNameMapperContainer(prefix, subContainer); |
|
111 } |
|
112 |
|
113 public String getMemento(ISourceContainer container) throws CoreException { |
|
114 SourceNameMapperContainer chromeContainer = (SourceNameMapperContainer) container; |
|
115 return chromeContainer.getMemento(); |
|
116 } |
|
117 } |
|
118 |
|
119 /** |
|
120 * Handles memento string format. The format is just a sequence of strings that are preceded |
|
121 * with their lengths and decorated with parentheses to make it more human-readable. |
|
122 */ |
|
123 private static class MementoFormat { |
|
124 |
|
125 static void encodeComponent(String component, StringBuilder output) { |
|
126 output.append(component.length()); |
|
127 output.append('(').append(component).append(')'); |
|
128 } |
|
129 |
|
130 /** |
|
131 * A simple parser that reads char sequence as a sequence of strings. |
|
132 */ |
|
133 static class Parser { |
|
134 private final CharSequence charSequence; |
|
135 private int pos = 0; |
|
136 Parser(CharSequence charSequence) { |
|
137 this.charSequence = charSequence; |
|
138 } |
|
139 String nextComponent() throws ParserException { |
|
140 if (pos >= charSequence.length()) { |
|
141 throw new ParserException("Unexpected end of line"); //$NON-NLS-1$ |
|
142 } |
|
143 char ch = charSequence.charAt(pos); |
|
144 pos++; |
|
145 int num = Character.digit(ch, 10); |
|
146 if (num == -1) { |
|
147 throw new ParserException("Digit expected"); //$NON-NLS-1$ |
|
148 } |
|
149 int len = num; |
|
150 while (true) { |
|
151 if (pos >= charSequence.length()) { |
|
152 throw new ParserException("Unexpected end of line"); //$NON-NLS-1$ |
|
153 } |
|
154 ch = charSequence.charAt(pos); |
|
155 if (!Character.isDigit(ch)) { |
|
156 break; |
|
157 } |
|
158 pos++; |
|
159 num = Character.digit(ch, 10); |
|
160 if (num == -1) { |
|
161 throw new ParserException("Digit expected"); //$NON-NLS-1$ |
|
162 } |
|
163 len = len * 10 + num; |
|
164 } |
|
165 pos++; |
|
166 if (pos + len + 1 > charSequence.length()) { |
|
167 throw new ParserException("Unexpected end of line"); //$NON-NLS-1$ |
|
168 } |
|
169 String result = charSequence.subSequence(pos, pos + len).toString(); |
|
170 pos += len + 1; |
|
171 return result; |
|
172 } |
|
173 } |
|
174 private static class ParserException extends Exception { |
|
175 ParserException() { |
|
176 } |
|
177 ParserException(String message, Throwable cause) { |
|
178 super(message, cause); |
|
179 } |
|
180 ParserException(String message) { |
|
181 super(message); |
|
182 } |
|
183 ParserException(Throwable cause) { |
|
184 super(cause); |
|
185 } |
|
186 } |
|
187 } |
|
188 } |