1 /*******************************************************************************
2 * Copyright (c) 2000, 2011 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
9 * IBM Corporation - initial API and implementation
10 * Brock Janiczak (brockj_eclipse@ihug.com.au) - https://bugs.eclipse.org/bugs/show_bug.cgi?id=20644
11 * Brock Janiczak (brockj_eclipse@ihug.com.au) - https://bugs.eclipse.org/bugs/show_bug.cgi?id=83607
12 * Benjamin Muskalla <b.muskalla@gmx.net> - [navigation][hovering] Javadoc view cannot find URL with anchor - https://bugs.eclipse.org/bugs/show_bug.cgi?id=70870
13 *******************************************************************************/
14 package org.eclipse.jdt.internal.ui.text.javadoc;
16 import java.io.IOException;
17 import java.io.Reader;
18 import java.util.ArrayList;
19 import java.util.Iterator;
20 import java.util.List;
22 import org.eclipse.jface.internal.text.html.HTMLPrinter;
23 import org.eclipse.jface.internal.text.html.SubstitutionTextReader;
25 import org.eclipse.jdt.core.dom.TagElement;
29 * Processes JavaDoc tags.
31 public class JavaDoc2HTMLTextReader extends SubstitutionTextReader {
38 Pair(String tag, String content) {
43 public void generated_5851077662602872979(StringBuffer buffer, JavaDoc2HTMLTextReader javadoc2htmltextreader) {
46 buffer.append("</dt>"); //$NON-NLS-1$
47 buffer.append("<dd>"); //$NON-NLS-1$
49 buffer.append(fContent);
53 private List<String> fParameters;
54 private String fReturn;
55 private List<String> fExceptions;
56 private List<String> fAuthors;
57 private List<String> fSees;
58 private List<String> fSince;
59 private List<Pair> fRest; // list of Pair objects
61 public JavaDoc2HTMLTextReader(Reader reader) {
63 setSkipWhitespace(false);
66 private int getTag(StringBuffer buffer) throws IOException {
68 while (c == '.' || c != -1 && Character.isLetter((char) c)) {
69 buffer.append((char) c);
75 private int getContent(StringBuffer buffer, char stopChar) throws IOException {
77 while (c != -1 && c != stopChar) {
78 buffer.append((char) c);
84 private int getContentUntilNextTag(StringBuffer buffer) throws IOException {
86 boolean blockStartRead= false;
89 int index= buffer.length();
90 while (--index >= 0 && Character.isWhitespace(buffer.charAt(index))) {
91 switch (buffer.charAt(index)) {
101 if (blockStartRead) {
102 buffer.append(processBlockTag());
103 blockStartRead= false;
105 buffer.append((char) c);
109 blockStartRead= c == '{';
114 private String substituteQualification(String qualification) {
116 if (qualification.indexOf("<a") == -1) { //$NON-NLS-1$
117 // No tag at all, use smart way
118 result= qualification.replace('#', '.');
121 int length= qualification.length();
122 result= qualification;
123 boolean insideTag= false;
124 for (int i= 0; i < length; i++) {
125 char charAt= result.charAt(i);
126 if (charAt == '<' && result.charAt(i + 1) == 'a')
130 if (charAt == '#' && !insideTag)
131 result= result.substring(0, i) + "." + result.substring(i + 1); //$NON-NLS-1$
135 if (result.startsWith(".")) //$NON-NLS-1$
136 result= result.substring(1);
140 private void printDefinitions(StringBuffer buffer, List<String> list, boolean firstword) {
141 Iterator<String> e= list.iterator();
142 while (e.hasNext()) {
144 buffer.append("<dd>"); //$NON-NLS-1$
148 buffer.append("<b>"); //$NON-NLS-1$
150 int i= getParamEndOffset(s);
151 if (i <= s.length()) {
152 buffer.append(HTMLPrinter.convertToHTMLContent(s.substring(0, i)));
153 buffer.append("</b>"); //$NON-NLS-1$
154 buffer.append(s.substring(i));
156 buffer.append("</b>"); //$NON-NLS-1$
159 buffer.append("</dd>"); //$NON-NLS-1$
163 private int getParamEndOffset(String s) {
165 final int length= s.length();
167 while (i < length && Character.isWhitespace(s.charAt(i)))
169 if (i < length && s.charAt(i) == '<') {
170 // generic type parameter
172 while (i < length && Character.isWhitespace(s.charAt(i)))
174 while (i < length && Character.isJavaIdentifierPart(s.charAt(i)))
176 while (i < length && s.charAt(i) != '>')
179 // simply read an identifier
180 while (i < length && Character.isJavaIdentifierPart(s.charAt(i)))
187 private void print(StringBuffer buffer, String tag, List<String> elements, boolean firstword) {
188 if ( !elements.isEmpty()) {
189 buffer.append("<dt>"); //$NON-NLS-1$
191 buffer.append("</dt>"); //$NON-NLS-1$
192 printDefinitions(buffer, elements, firstword);
196 private void print(StringBuffer buffer, String tag, String content) {
197 if (content != null) {
198 buffer.append("<dt>"); //$NON-NLS-1$
200 buffer.append("</dt>"); //$NON-NLS-1$
201 buffer.append("<dd>"); //$NON-NLS-1$
202 buffer.append(content);
203 buffer.append("</dd>"); //$NON-NLS-1$
207 private void printRest(StringBuffer buffer) {
208 if ( !fRest.isEmpty()) {
209 Iterator<Pair> e= fRest.iterator();
210 while (e.hasNext()) {
212 buffer.append("<dt>"); //$NON-NLS-1$
213 p.generated_5851077662602872979(buffer, this);
214 buffer.append("</dd>"); //$NON-NLS-1$
219 private String printSimpleTag() {
220 StringBuffer buffer= new StringBuffer();
221 buffer.append("<dl>"); //$NON-NLS-1$
222 print(buffer, JavaDocMessages.JavaDoc2HTMLTextReader_see_section, fSees, false);
223 print(buffer, JavaDocMessages.JavaDoc2HTMLTextReader_parameters_section, fParameters, true);
224 print(buffer, JavaDocMessages.JavaDoc2HTMLTextReader_returns_section, fReturn);
225 print(buffer, JavaDocMessages.JavaDoc2HTMLTextReader_throws_section, fExceptions, false);
226 print(buffer, JavaDocMessages.JavaDoc2HTMLTextReader_author_section, fAuthors, false);
227 print(buffer, JavaDocMessages.JavaDoc2HTMLTextReader_since_section, fSince, false);
229 buffer.append("</dl>"); //$NON-NLS-1$
231 return buffer.toString();
234 private void handleTag(String tag, String tagContent) {
236 tagContent= tagContent.trim();
238 if (TagElement.TAG_PARAM.equals(tag))
239 fParameters.add(tagContent);
240 else if (TagElement.TAG_RETURN.equals(tag))
242 else if (TagElement.TAG_EXCEPTION.equals(tag))
243 fExceptions.add(tagContent);
244 else if (TagElement.TAG_THROWS.equals(tag))
245 fExceptions.add(tagContent);
246 else if (TagElement.TAG_AUTHOR.equals(tag))
247 fAuthors.add(substituteQualification(tagContent));
248 else if (TagElement.TAG_SEE.equals(tag))
249 fSees.add(substituteQualification(tagContent));
250 else if (TagElement.TAG_SINCE.equals(tag))
251 fSince.add(substituteQualification(tagContent));
252 else if (tagContent != null)
253 fRest.add(new Pair(tag, tagContent));
257 * A '@' has been read. Process a javadoc tag
259 private String processSimpleTag() throws IOException {
261 fParameters= new ArrayList<String>();
262 fExceptions= new ArrayList<String>();
263 fAuthors= new ArrayList<String>();
264 fSees= new ArrayList<String>();
265 fSince= new ArrayList<String>();
266 fRest= new ArrayList<Pair>();
268 StringBuffer buffer= new StringBuffer();
273 buffer.append((char) c);
275 String tag= buffer.toString();
279 c= getContentUntilNextTag(buffer);
282 handleTag(tag, buffer.toString());
285 return printSimpleTag();
288 private String printBlockTag(String tag, String tagContent) {
290 if (TagElement.TAG_LINK.equals(tag) || TagElement.TAG_LINKPLAIN.equals(tag)) {
292 char[] contentChars= tagContent.toCharArray();
293 boolean inParentheses= false;
296 for (int i= 0; i < contentChars.length; i++) {
297 char nextChar= contentChars[i];
299 // tagContent always has a leading space
300 if (i == 0 && Character.isWhitespace(nextChar)) {
305 if (nextChar == '(') {
310 if (nextChar == ')') {
311 inParentheses= false;
315 // Stop at first whitespace that is not in parentheses
316 if (!inParentheses && Character.isWhitespace(nextChar)) {
321 if (TagElement.TAG_LINK.equals(tag))
322 return "<code>" + substituteQualification(tagContent.substring(labelStart)) + "</code>"; //$NON-NLS-1$//$NON-NLS-2$
324 return substituteQualification(tagContent.substring(labelStart));
326 } else if (TagElement.TAG_LITERAL.equals(tag)) {
327 return printLiteral(tagContent);
329 } else if (TagElement.TAG_CODE.equals(tag)) {
330 return "<code>" + printLiteral(tagContent) + "</code>"; //$NON-NLS-1$//$NON-NLS-2$
333 // If something went wrong at least replace the {} with the content
334 return substituteQualification(tagContent);
337 private String printLiteral(String tagContent) {
339 for (int i= 0; i < tagContent.length(); i++) {
340 if (! Character.isWhitespace(tagContent.charAt(i))) {
345 return HTMLPrinter.convertToHTMLContent(tagContent.substring(contentStart));
349 * A '{' has been read. Process a block tag
351 private String processBlockTag() throws IOException {
356 StringBuffer buffer= new StringBuffer();
358 buffer.append((char) c);
359 return buffer.toString();
362 StringBuffer buffer= new StringBuffer();
366 buffer.append((char) c);
369 String tag= buffer.toString();
372 if (c != -1 && c != '}') {
373 buffer.append((char) c);
374 c= getContent(buffer, '}');
377 return printBlockTag(tag, buffer.toString());
384 * @see SubstitutionTextReaderr#computeSubstitution(int)
387 protected String computeSubstitution(int c) throws IOException {
388 if (c == '@' && fWasWhiteSpace)
389 return processSimpleTag();
392 return processBlockTag();