Add Java 9+ module support
emmanue1
4 years ago
42 | 42 | } |
43 | 43 | |
44 | 44 | protected TreeNodeFactory get(String containerType, Container.Entry entry) { |
45 | String path = entry.getPath();; | |
45 | String path = entry.getPath(); | |
46 | 46 | String type = entry.isDirectory() ? "dir" : "file"; |
47 | 47 | String prefix = containerType + ':' + type + ':'; |
48 | 48 | TreeNodeFactory factory = null; |
+1
-1
25 | 25 | if (rootPath.toUri().toString().toLowerCase().endsWith(".jmod!/")) { |
26 | 26 | return true; |
27 | 27 | } else { |
28 | // Extension: accept uncompressed WAR file containing a folder 'WEB-INF' | |
28 | // Extension: accept uncompressed JMOD file containing a folder 'classes' | |
29 | 29 | try { |
30 | 30 | return rootPath.getFileSystem().provider().getScheme().equals("file") && Files.exists(rootPath.resolve("classes")); |
31 | 31 | } catch (InvalidPathException e) { |
+2
-1
43 | 43 | TreeNodeFactory treeNodeFactory = api.getTreeNodeFactory(parentEntry); |
44 | 44 | Object data = (treeNodeFactory != null) ? treeNodeFactory.make(api, parentEntry).getUserObject() : null; |
45 | 45 | Icon icon = (data instanceof TreeNodeData) ? ((TreeNodeData)data).getIcon() : null; |
46 | String location = file.getPath(); | |
46 | 47 | |
47 | api.addPanel(file.getName(), icon, "Location: " + file.getAbsolutePath(), mainPanel); | |
48 | api.addPanel(file.getName(), icon, "Location: " + location, mainPanel); | |
48 | 49 | return mainPanel; |
49 | 50 | } |
50 | 51 | } |
121 | 121 | |
122 | 122 | protected void enterTypeDeclaration(ParserRuleContext ctx) { |
123 | 123 | // Add type declaration |
124 | String typeName = ctx.getToken(JavaParser.Identifier, 0).getText(); | |
125 | int length = sbTypeDeclaration.length(); | |
126 | ||
127 | if ((length == 0) || (sbTypeDeclaration.charAt(length-1) == '/')) { | |
128 | sbTypeDeclaration.append(typeName); | |
129 | } else { | |
130 | sbTypeDeclaration.append('$').append(typeName); | |
131 | } | |
132 | ||
133 | String internalTypeName = sbTypeDeclaration.toString(); | |
134 | typeDeclarationSet.add(internalTypeName); | |
135 | nameToInternalTypeName.put(typeName, internalTypeName); | |
136 | ||
137 | HashSet<String> superInternalTypeNameSet = new HashSet<>(); | |
138 | ||
139 | // Add super type reference | |
140 | JavaParser.TypeContext superType = ctx.getRuleContext(JavaParser.TypeContext.class, 0); | |
141 | if (superType != null) { | |
142 | String superQualifiedTypeName = resolveInternalTypeName(superType.classOrInterfaceType().Identifier()); | |
143 | ||
144 | if (superQualifiedTypeName.charAt(0) != '*') | |
145 | superInternalTypeNameSet.add(superQualifiedTypeName); | |
146 | } | |
147 | ||
148 | // Add implementation references | |
149 | JavaParser.TypeListContext superInterfaces = ctx.getRuleContext(JavaParser.TypeListContext.class, 0); | |
150 | if (superInterfaces != null) { | |
151 | for (JavaParser.TypeContext superInterface : superInterfaces.type()) { | |
152 | String superQualifiedInterfaceName = resolveInternalTypeName(superInterface.classOrInterfaceType().Identifier()); | |
153 | ||
154 | if (superQualifiedInterfaceName.charAt(0) != '*') | |
155 | superInternalTypeNameSet.add(superQualifiedInterfaceName); | |
156 | } | |
157 | } | |
158 | ||
159 | if (! superInternalTypeNameSet.isEmpty()) { | |
160 | superTypeNamesMap.put(internalTypeName, superInternalTypeNameSet); | |
124 | TerminalNode identifier = ctx.getToken(JavaParser.Identifier, 0); | |
125 | ||
126 | if (identifier != null) { | |
127 | String typeName = identifier.getText(); | |
128 | int length = sbTypeDeclaration.length(); | |
129 | ||
130 | if ((length == 0) || (sbTypeDeclaration.charAt(length - 1) == '/')) { | |
131 | sbTypeDeclaration.append(typeName); | |
132 | } else { | |
133 | sbTypeDeclaration.append('$').append(typeName); | |
134 | } | |
135 | ||
136 | String internalTypeName = sbTypeDeclaration.toString(); | |
137 | typeDeclarationSet.add(internalTypeName); | |
138 | nameToInternalTypeName.put(typeName, internalTypeName); | |
139 | ||
140 | HashSet<String> superInternalTypeNameSet = new HashSet<>(); | |
141 | ||
142 | // Add super type reference | |
143 | JavaParser.TypeContext superType = ctx.getRuleContext(JavaParser.TypeContext.class, 0); | |
144 | if (superType != null) { | |
145 | String superQualifiedTypeName = resolveInternalTypeName(superType.classOrInterfaceType().Identifier()); | |
146 | ||
147 | if (superQualifiedTypeName.charAt(0) != '*') | |
148 | superInternalTypeNameSet.add(superQualifiedTypeName); | |
149 | } | |
150 | ||
151 | // Add implementation references | |
152 | JavaParser.TypeListContext superInterfaces = ctx.getRuleContext(JavaParser.TypeListContext.class, 0); | |
153 | if (superInterfaces != null) { | |
154 | for (JavaParser.TypeContext superInterface : superInterfaces.type()) { | |
155 | String superQualifiedInterfaceName = resolveInternalTypeName(superInterface.classOrInterfaceType().Identifier()); | |
156 | ||
157 | if (superQualifiedInterfaceName.charAt(0) != '*') | |
158 | superInternalTypeNameSet.add(superQualifiedInterfaceName); | |
159 | } | |
160 | } | |
161 | ||
162 | if (!superInternalTypeNameSet.isEmpty()) { | |
163 | superTypeNamesMap.put(internalTypeName, superInternalTypeNameSet); | |
164 | } | |
161 | 165 | } |
162 | 166 | } |
163 | 167 | |
196 | 200 | |
197 | 201 | public void enterFieldDeclaration(JavaParser.FieldDeclarationContext ctx) { |
198 | 202 | for (JavaParser.VariableDeclaratorContext declaration : ctx.variableDeclarators().variableDeclarator()) { |
199 | String name = declaration.variableDeclaratorId().Identifier().getText(); | |
200 | fieldDeclarationSet.add(name); | |
203 | TerminalNode identifier = declaration.variableDeclaratorId().Identifier(); | |
204 | ||
205 | if (identifier != null) { | |
206 | String name = identifier.getText(); | |
207 | fieldDeclarationSet.add(name); | |
208 | } | |
201 | 209 | } |
202 | 210 | } |
203 | 211 | |
204 | 212 | public void enterMethodDeclaration(JavaParser.MethodDeclarationContext ctx) { |
205 | String name = ctx.Identifier().getText(); | |
206 | methodDeclarationSet.add(name); | |
213 | TerminalNode identifier = ctx.Identifier(); | |
214 | ||
215 | if (identifier != null) { | |
216 | String name = identifier.getText(); | |
217 | methodDeclarationSet.add(name); | |
218 | } | |
207 | 219 | } |
208 | 220 | |
209 | 221 | public void enterInterfaceMethodDeclaration(JavaParser.InterfaceMethodDeclarationContext ctx) { |
210 | String name = ctx.Identifier().getText(); | |
211 | methodDeclarationSet.add(name); | |
222 | TerminalNode identifier = ctx.Identifier(); | |
223 | ||
224 | if (identifier != null) { | |
225 | String name = identifier.getText(); | |
226 | methodDeclarationSet.add(name); | |
227 | } | |
212 | 228 | } |
213 | 229 | |
214 | 230 | public void enterConstructorDeclaration(JavaParser.ConstructorDeclarationContext ctx) { |
281 | 297 | protected TerminalNode getRightTerminalNode(ParseTree pt) { |
282 | 298 | if (pt instanceof ParserRuleContext) { |
283 | 299 | List<ParseTree> children = ((ParserRuleContext)pt).children; |
284 | int size = children.size(); | |
285 | ||
286 | if (size > 0) { | |
287 | ParseTree last = children.get(size - 1); | |
288 | ||
289 | if (last instanceof TerminalNode) { | |
290 | return (TerminalNode) last; | |
291 | } else { | |
292 | return getRightTerminalNode(last); | |
300 | ||
301 | if (children != null) { | |
302 | int size = children.size(); | |
303 | ||
304 | if (size > 0) { | |
305 | ParseTree last = children.get(size - 1); | |
306 | ||
307 | if (last instanceof TerminalNode) { | |
308 | return (TerminalNode) last; | |
309 | } else { | |
310 | return getRightTerminalNode(last); | |
311 | } | |
293 | 312 | } |
294 | 313 | } |
295 | 314 | } |
+10
-0
20 | 20 | import java.io.File; |
21 | 21 | import java.io.IOException; |
22 | 22 | import java.io.InputStream; |
23 | import java.util.regex.Pattern; | |
23 | 24 | |
24 | 25 | public class ClassFileTreeNodeFactoryProvider extends AbstractTypeFileTreeNodeFactoryProvider { |
25 | 26 | protected static final ImageIcon CLASS_FILE_ICON = new ImageIcon(ClassFileTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/classf_obj.png")); |
35 | 36 | } |
36 | 37 | |
37 | 38 | @Override public String[] getSelectors() { return appendSelectors("*:file:*.class"); } |
39 | ||
40 | @Override | |
41 | public Pattern getPathPattern() { | |
42 | if (externalPathPattern == null) { | |
43 | return Pattern.compile("^((?!module-info\\.class).)*$"); | |
44 | } else { | |
45 | return externalPathPattern; | |
46 | } | |
47 | } | |
38 | 48 | |
39 | 49 | @Override |
40 | 50 | @SuppressWarnings("unchecked") |
+2
-2
42 | 42 | |
43 | 43 | @Override |
44 | 44 | public String makeTip(API api, Container.Entry entry) { |
45 | File file = new File(entry.getContainer().getRoot().getUri()); | |
45 | String location = new File(entry.getUri()).getPath(); | |
46 | 46 | StringBuilder tip = new StringBuilder("<html>Location: "); |
47 | 47 | |
48 | tip.append(file.getPath()); | |
48 | tip.append(location); | |
49 | 49 | tip.append("</html>"); |
50 | 50 | |
51 | 51 | return tip.toString(); |
+66
-0
0 | /* | |
1 | * Copyright (c) 2008-2019 Emmanuel Dupuy. | |
2 | * This project is distributed under the GPLv3 license. | |
3 | * This is a Copyleft license that gives the user the right to use, | |
4 | * copy and modify the code freely for non-commercial purposes. | |
5 | */ | |
6 | ||
7 | package org.jd.gui.service.treenode; | |
8 | ||
9 | import org.jd.gui.api.API; | |
10 | import org.jd.gui.api.feature.ContainerEntryGettable; | |
11 | import org.jd.gui.api.feature.UriGettable; | |
12 | import org.jd.gui.api.model.Container; | |
13 | import org.jd.gui.util.exception.ExceptionUtil; | |
14 | import org.jd.gui.view.component.ModuleInfoFilePage; | |
15 | import org.jd.gui.view.data.TreeNodeBean; | |
16 | ||
17 | import javax.swing.*; | |
18 | import javax.swing.tree.DefaultMutableTreeNode; | |
19 | import java.io.File; | |
20 | import java.util.regex.Pattern; | |
21 | ||
22 | public class ModuleInfoFileTreeNodeFactoryProvider extends ClassFileTreeNodeFactoryProvider { | |
23 | protected static final Factory FACTORY = new Factory(); | |
24 | ||
25 | static { | |
26 | // Early class loading | |
27 | try { | |
28 | Class.forName(ModuleInfoFilePage.class.getName()); | |
29 | } catch (Exception e) { | |
30 | assert ExceptionUtil.printStackTrace(e); | |
31 | } | |
32 | } | |
33 | ||
34 | @Override public String[] getSelectors() { return appendSelectors("*:file:*/module-info.class"); } | |
35 | ||
36 | @Override public Pattern getPathPattern() { return externalPathPattern; } | |
37 | ||
38 | @Override | |
39 | @SuppressWarnings("unchecked") | |
40 | public <T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> T make(API api, Container.Entry entry) { | |
41 | int lastSlashIndex = entry.getPath().lastIndexOf('/'); | |
42 | String label = entry.getPath().substring(lastSlashIndex+1); | |
43 | return (T)new FileTreeNode(entry, new TreeNodeBean(label, CLASS_FILE_ICON), FACTORY); | |
44 | } | |
45 | ||
46 | protected static class Factory implements AbstractTypeFileTreeNodeFactoryProvider.PageAndTipFactory { | |
47 | // --- PageAndTipFactory --- // | |
48 | @Override | |
49 | @SuppressWarnings("unchecked") | |
50 | public <T extends JComponent & UriGettable> T makePage(API a, Container.Entry e) { | |
51 | return (T)new ModuleInfoFilePage(a, e); | |
52 | } | |
53 | ||
54 | @Override | |
55 | public String makeTip(API api, Container.Entry entry) { | |
56 | String location = new File(entry.getUri()).getPath(); | |
57 | StringBuilder tip = new StringBuilder("<html>Location: "); | |
58 | ||
59 | tip.append(location); | |
60 | tip.append("</html>"); | |
61 | ||
62 | return tip.toString(); | |
63 | } | |
64 | } | |
65 | } |
113 | 113 | typeNameCache.put(name, qualifiedName); |
114 | 114 | return qualifiedName; |
115 | 115 | } |
116 | } catch (ClassNotFoundException e) { | |
117 | assert ExceptionUtil.printStackTrace(e); | |
116 | } catch (ClassNotFoundException ignore) { | |
117 | // Ignore class loading error | |
118 | 118 | } |
119 | 119 | |
120 | 120 | // Type not found |
170 | 170 | |
171 | 171 | if (!foldsExpanded) { |
172 | 172 | try { |
173 | Rectangle r = textArea.modelToView(start); | |
174 | ||
175 | if (r != null) { | |
173 | Rectangle rec = textArea.modelToView(start); | |
174 | ||
175 | if (rec != null) { | |
176 | 176 | // Visible |
177 | setCaretPositionAndCenter(start, end, r); | |
177 | setCaretPositionAndCenter(start, end, rec); | |
178 | 178 | } else { |
179 | 179 | // Not visible yet |
180 | SwingUtilities.invokeLater(new Runnable() { | |
181 | public void run() { | |
182 | try { | |
183 | Rectangle r = textArea.modelToView(start); | |
184 | if (r != null) { | |
185 | setCaretPositionAndCenter(start, end, r); | |
186 | } | |
187 | } catch (BadLocationException e) { | |
188 | assert ExceptionUtil.printStackTrace(e); | |
180 | SwingUtilities.invokeLater(() -> { | |
181 | try { | |
182 | Rectangle r = textArea.modelToView(start); | |
183 | if (r != null) { | |
184 | setCaretPositionAndCenter(start, end, r); | |
189 | 185 | } |
186 | } catch (BadLocationException e) { | |
187 | assert ExceptionUtil.printStackTrace(e); | |
190 | 188 | } |
191 | 189 | }); |
192 | 190 | } |
83 | 83 | |
84 | 84 | // Decompile class file |
85 | 85 | DECOMPILER.decompile(loader, printer, entryInternalName, configuration); |
86 | setText(printer.getStringBuffer().toString()); | |
87 | 86 | } catch (Throwable t) { |
88 | 87 | assert ExceptionUtil.printStackTrace(t); |
89 | 88 | setText("// INTERNAL ERROR //"); |
153 | 152 | } |
154 | 153 | } |
155 | 154 | |
155 | @Override | |
156 | public void end() { | |
157 | setText(stringBuffer.toString()); | |
158 | } | |
159 | ||
156 | 160 | // --- Add strings --- // |
157 | 161 | @Override |
158 | 162 | public void printStringConstant(String constant, String ownerInternalName) { |
44 | 44 | protected int[] lineNumberMap = null; |
45 | 45 | protected int maxLineNumber = 0; |
46 | 46 | |
47 | public void setMaxLineNumber(int maxLineNumber) { | |
47 | protected void setMaxLineNumber(int maxLineNumber) { | |
48 | 48 | if (maxLineNumber > 0) { |
49 | 49 | if (lineNumberMap == null) { |
50 | lineNumberMap = new int[maxLineNumber * 3 / 2]; | |
50 | lineNumberMap = new int[maxLineNumber+1]; | |
51 | 51 | } else if (lineNumberMap.length <= maxLineNumber) { |
52 | int[] tmp = new int[maxLineNumber * 3 / 2]; | |
52 | int[] tmp = new int[maxLineNumber+1]; | |
53 | 53 | System.arraycopy(lineNumberMap, 0, tmp, 0, lineNumberMap.length); |
54 | 54 | lineNumberMap = tmp; |
55 | 55 | } |
56 | 56 | |
57 | if (this.maxLineNumber < maxLineNumber) { | |
58 | this.maxLineNumber = maxLineNumber; | |
59 | } | |
60 | } | |
61 | } | |
62 | ||
63 | public void initLineNumbers(int maxLineNumber) { | |
64 | setMaxLineNumber(maxLineNumber); | |
65 | ||
66 | for (int i=1; i<=maxLineNumber; i++) { | |
67 | lineNumberMap[i] = i; | |
68 | } | |
69 | } | |
70 | ||
71 | public void setLineNumber(int textAreaLineNumber, int originalLineNumber) { | |
57 | this.maxLineNumber = maxLineNumber; | |
58 | } | |
59 | } | |
60 | ||
61 | protected void initLineNumbers() { | |
62 | String text = getText(); | |
63 | int len = text.length(); | |
64 | ||
65 | if (len == 0) { | |
66 | setMaxLineNumber(0); | |
67 | } else { | |
68 | int mln = len - text.replace("\n", "").length(); | |
69 | ||
70 | if (text.charAt(len-1) != '\n') { | |
71 | mln++; | |
72 | } | |
73 | ||
74 | setMaxLineNumber(mln); | |
75 | ||
76 | for (int i=1; i<=maxLineNumber; i++) { | |
77 | lineNumberMap[i] = i; | |
78 | } | |
79 | } | |
80 | } | |
81 | ||
82 | protected void setLineNumber(int textAreaLineNumber, int originalLineNumber) { | |
72 | 83 | if (originalLineNumber > 0) { |
73 | 84 | setMaxLineNumber(textAreaLineNumber); |
74 | 85 | lineNumberMap[textAreaLineNumber] = originalLineNumber; |
75 | 86 | } |
76 | 87 | } |
77 | 88 | |
78 | public void clearLineNumbers() { | |
89 | protected void clearLineNumbers() { | |
79 | 90 | if (lineNumberMap != null) { |
80 | 91 | Arrays.fill(lineNumberMap, 0); |
81 | 92 | } |
82 | 93 | } |
83 | 94 | |
84 | public int getMaximumSourceLineNumber() { return maxLineNumber; } | |
85 | ||
86 | public int getTextAreaLineNumber(int originalLineNumber) { | |
95 | protected int getMaximumSourceLineNumber() { return maxLineNumber; } | |
96 | ||
97 | protected int getTextAreaLineNumber(int originalLineNumber) { | |
87 | 98 | int textAreaLineNumber = 1; |
88 | 99 | int greatestLowerSourceLineNumber = 0; |
89 | 100 | int i = lineNumberMap.length; |
39 | 39 | referenceListener.init(declarationListener); |
40 | 40 | ANTLRJavaParser.parse(new ANTLRInputStream(text), referenceListener); |
41 | 41 | // Display |
42 | initLineNumbers(getMaxLineNumber(text)); | |
43 | 42 | setText(text); |
44 | } | |
45 | ||
46 | private static int getMaxLineNumber(String text) { | |
47 | return text.length() - text.replace("\n", "").length(); | |
43 | initLineNumbers(); | |
48 | 44 | } |
49 | 45 | |
50 | 46 | public String getSyntaxStyle() { return SyntaxConstants.SYNTAX_STYLE_JAVA; } |
395 | 391 | } |
396 | 392 | } |
397 | 393 | } |
398 | } else { | |
394 | } else if (ctx.primary() != null) { | |
399 | 395 | TerminalNode identifier = ctx.primary().Identifier(); |
400 | 396 | |
401 | 397 | if (identifier != null) { |
0 | /* | |
1 | * Copyright (c) 2008-2019 Emmanuel Dupuy. | |
2 | * This project is distributed under the GPLv3 license. | |
3 | * This is a Copyleft license that gives the user the right to use, | |
4 | * copy and modify the code freely for non-commercial purposes. | |
5 | */ | |
6 | ||
7 | package org.jd.gui.view.component; | |
8 | ||
9 | import org.fife.ui.rsyntaxtextarea.*; | |
10 | import org.jd.gui.api.API; | |
11 | import org.jd.gui.api.model.Container; | |
12 | import org.jd.gui.util.decompiler.ContainerLoader; | |
13 | import org.jd.gui.util.exception.ExceptionUtil; | |
14 | ||
15 | import javax.swing.text.Segment; | |
16 | import java.util.Map; | |
17 | ||
18 | public class ModuleInfoFilePage extends ClassFilePage { | |
19 | public static final String SYNTAX_STYLE_JAVA_MODULE = "text/java-module"; | |
20 | ||
21 | static { | |
22 | // Add a new token maker for Java 9+ module | |
23 | AbstractTokenMakerFactory atmf = (AbstractTokenMakerFactory)TokenMakerFactory.getDefaultInstance(); | |
24 | atmf.putMapping(SYNTAX_STYLE_JAVA_MODULE, ModuleInfoTokenMaker.class.getName()); | |
25 | } | |
26 | ||
27 | public ModuleInfoFilePage(API api, Container.Entry entry) { | |
28 | super(api, entry); | |
29 | } | |
30 | ||
31 | public void decompile(Map<String, String> preferences) { | |
32 | try { | |
33 | // Clear ... | |
34 | clearHyperlinks(); | |
35 | clearLineNumbers(); | |
36 | typeDeclarations.clear(); | |
37 | ||
38 | // Init preferences | |
39 | boolean unicodeEscape = getPreferenceValue(preferences, ESCAPE_UNICODE_CHARACTERS, false); | |
40 | ||
41 | // Init loader | |
42 | ContainerLoader loader = new ContainerLoader(entry); | |
43 | ||
44 | // Init printer | |
45 | ModuleInfoFilePrinter printer = new ModuleInfoFilePrinter(); | |
46 | printer.setUnicodeEscape(unicodeEscape); | |
47 | ||
48 | // Format internal name | |
49 | String entryPath = entry.getPath(); | |
50 | assert entryPath.endsWith(".class"); | |
51 | String entryInternalName = entryPath.substring(0, entryPath.length() - 6); // 6 = ".class".length() | |
52 | ||
53 | // Decompile class file | |
54 | DECOMPILER.decompile(loader, printer, entryInternalName); | |
55 | } catch (Throwable t) { | |
56 | assert ExceptionUtil.printStackTrace(t); | |
57 | setText("// INTERNAL ERROR //"); | |
58 | } | |
59 | } | |
60 | ||
61 | public String getSyntaxStyle() { return SYNTAX_STYLE_JAVA_MODULE; } | |
62 | ||
63 | public class ModuleInfoFilePrinter extends ClassFilePrinter { | |
64 | @Override | |
65 | public void start(int maxLineNumber, int majorVersion, int minorVersion) {} | |
66 | ||
67 | @Override | |
68 | public void end() { | |
69 | setText(stringBuffer.toString()); | |
70 | initLineNumbers(); | |
71 | } | |
72 | } | |
73 | ||
74 | // https://github.com/bobbylight/RSyntaxTextArea/wiki/Adding-Syntax-Highlighting-for-a-new-Language | |
75 | public static class ModuleInfoTokenMaker extends AbstractTokenMaker { | |
76 | @Override | |
77 | public TokenMap getWordsToHighlight() { | |
78 | TokenMap tokenMap = new TokenMap(); | |
79 | ||
80 | tokenMap.put("exports", Token.RESERVED_WORD); | |
81 | tokenMap.put("module", Token.RESERVED_WORD); | |
82 | tokenMap.put("open", Token.RESERVED_WORD); | |
83 | tokenMap.put("opens", Token.RESERVED_WORD); | |
84 | tokenMap.put("provides", Token.RESERVED_WORD); | |
85 | tokenMap.put("requires", Token.RESERVED_WORD); | |
86 | tokenMap.put("to", Token.RESERVED_WORD); | |
87 | tokenMap.put("transitive", Token.RESERVED_WORD); | |
88 | tokenMap.put("uses", Token.RESERVED_WORD); | |
89 | tokenMap.put("with", Token.RESERVED_WORD); | |
90 | ||
91 | return tokenMap; | |
92 | } | |
93 | ||
94 | @Override | |
95 | public void addToken(Segment segment, int start, int end, int tokenType, int startOffset) { | |
96 | // This assumes all keywords, etc. were parsed as "identifiers." | |
97 | if (tokenType==Token.IDENTIFIER) { | |
98 | int value = wordsToHighlight.get(segment, start, end); | |
99 | if (value != -1) { | |
100 | tokenType = value; | |
101 | } | |
102 | } | |
103 | super.addToken(segment, start, end, tokenType, startOffset); | |
104 | } | |
105 | ||
106 | @Override | |
107 | public Token getTokenList(Segment text, int startTokenType, int startOffset) { | |
108 | resetTokenList(); | |
109 | ||
110 | char[] array = text.array; | |
111 | int offset = text.offset; | |
112 | int end = offset + text.count; | |
113 | ||
114 | int newStartOffset = startOffset - offset; | |
115 | ||
116 | int currentTokenStart = offset; | |
117 | int currentTokenType = startTokenType; | |
118 | ||
119 | for (int i=offset; i<end; i++) { | |
120 | char c = array[i]; | |
121 | ||
122 | switch (currentTokenType) { | |
123 | case Token.NULL: | |
124 | currentTokenStart = i; // Starting a new token here. | |
125 | if (RSyntaxUtilities.isLetter(c) || c=='_') { | |
126 | currentTokenType = Token.IDENTIFIER; | |
127 | } else { | |
128 | currentTokenType = Token.WHITESPACE; | |
129 | } | |
130 | break; | |
131 | default: // Should never happen | |
132 | case Token.WHITESPACE: | |
133 | if (RSyntaxUtilities.isLetterOrDigit(c) || c=='_') { | |
134 | addToken(text, currentTokenStart, i-1, Token.WHITESPACE, newStartOffset+currentTokenStart); | |
135 | currentTokenStart = i; | |
136 | currentTokenType = Token.IDENTIFIER; | |
137 | } | |
138 | break; | |
139 | case Token.IDENTIFIER: | |
140 | if (!RSyntaxUtilities.isLetterOrDigit(c) && c!='_') { | |
141 | addToken(text, currentTokenStart, i-1, Token.IDENTIFIER, newStartOffset+currentTokenStart); | |
142 | currentTokenStart = i; | |
143 | currentTokenType = Token.WHITESPACE; | |
144 | } | |
145 | break; | |
146 | } | |
147 | } | |
148 | ||
149 | if (currentTokenType == Token.NULL) { | |
150 | addNullToken(); | |
151 | }else { | |
152 | addToken(text, currentTokenStart,end-1, currentTokenType, newStartOffset+currentTokenStart); | |
153 | addNullToken(); | |
154 | } | |
155 | ||
156 | return firstToken; | |
157 | } | |
158 | } | |
159 | } |
16 | 16 | org.jd.gui.service.treenode.ManifestFileTreeNodeFactoryProvider |
17 | 17 | org.jd.gui.service.treenode.MetainfDirectoryTreeNodeFactoryProvider |
18 | 18 | org.jd.gui.service.treenode.MetainfServiceFileTreeNodeFactoryProvider |
19 | org.jd.gui.service.treenode.ModuleInfoFileTreeNodeFactoryProvider | |
19 | 20 | org.jd.gui.service.treenode.PackageTreeNodeFactoryProvider |
20 | 21 | org.jd.gui.service.treenode.PropertiesFileTreeNodeFactoryProvider |
21 | 22 | org.jd.gui.service.treenode.SqlFileTreeNodeFactoryProvider |