KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > formatter > comment > JavaDocRegion


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 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
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11
12 package org.eclipse.jdt.internal.formatter.comment;
13
14 import java.io.IOException JavaDoc;
15 import java.io.StringReader JavaDoc;
16 import java.util.ArrayList JavaDoc;
17 import java.util.Iterator JavaDoc;
18
19 import org.eclipse.text.edits.TextEdit;
20
21 import org.eclipse.jface.text.BadLocationException;
22 import org.eclipse.jface.text.DefaultLineTracker;
23 import org.eclipse.jface.text.IDocument;
24 import org.eclipse.jface.text.ILineTracker;
25 import org.eclipse.jface.text.Position;
26 import org.eclipse.jface.text.TextUtilities;
27
28 import org.eclipse.jdt.core.formatter.CodeFormatter;
29 import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
30 import org.eclipse.jdt.internal.formatter.CodeFormatterVisitor;
31
32
33 /**
34  * Javadoc region in a source code document.
35  *
36  * @since 3.0
37  */

38 public class JavaDocRegion extends MultiCommentRegion implements IJavaDocTagConstants {
39
40     /** The positions of code ranges */
41     private final ArrayList JavaDoc fCodePositions= new ArrayList JavaDoc();
42      
43     /** Should HTML tags be formatted? */
44     private final boolean fFormatHtml;
45
46     /** Should source code regions be formatted? */
47     private final boolean fFormatSource;
48     
49     /**
50      * Creates a new Javadoc region.
51      *
52      * @param document the document which contains the comment region
53      * @param position the position of this comment region in the document
54      * @param formatter the given formatter
55      */

56     public JavaDocRegion(final IDocument document, final Position position, final CodeFormatterVisitor formatter) {
57         super(document, position, formatter);
58
59         fFormatSource = this.preferences.comment_format_source;
60         fFormatHtml = this.preferences.comment_format_html;
61         fClear = this.preferences.comment_clear_blank_lines_in_javadoc_comment;
62     }
63
64     /*
65      * @see org.eclipse.jdt.internal.corext.text.comment.CommentRegion#canFormat(org.eclipse.jdt.internal.corext.text.comment.CommentRange, org.eclipse.jdt.internal.corext.text.comment.CommentRange)
66      */

67     protected boolean canFormat(final CommentRange previous, final CommentRange next) {
68         
69         if (previous != null) {
70             
71             final boolean isCurrentCode= next.hasAttribute(COMMENT_CODE);
72             final boolean isLastCode= previous.hasAttribute(COMMENT_CODE);
73             
74             final int base= getOffset();
75             
76             if (!isLastCode && isCurrentCode)
77                 fCodePositions.add(new Position(base + previous.getOffset()));
78             else if (isLastCode && !isCurrentCode)
79                 fCodePositions.add(new Position(base + next.getOffset() + next.getLength()));
80             
81             if (previous.hasAttribute(COMMENT_IMMUTABLE) && next.hasAttribute(COMMENT_IMMUTABLE))
82                 return false;
83             
84             return true;
85         }
86         return false;
87     }
88
89     /*
90      * @see org.eclipse.jdt.internal.corext.text.comment.CommentRegion#formatRegion(java.lang.String, int)
91      */

92     protected final void formatRegion(final String JavaDoc indentation, final int width) {
93     
94         super.formatRegion(indentation, width);
95         
96         if (fFormatSource) {
97             
98             try {
99                 
100                 if (fCodePositions.size() > 0) {
101                     
102                     int begin= 0;
103                     int end= 0;
104                     
105                     Position position= null;
106                     
107                     final IDocument document= getDocument();
108                     
109                     for (int index= fCodePositions.size() - 1; index >= 0;) {
110                         
111                         position= (Position)fCodePositions.get(index--);
112                         begin= position.getOffset();
113                         
114                         if (index >= 0) {
115                             position= (Position)fCodePositions.get(index--);
116                             end= position.getOffset();
117                         } else {
118                             /*
119                              * Handle missing closing tag
120                              * see: https://bugs.eclipse.org/bugs/show_bug.cgi?id=57011
121                              */

122                             position= null;
123                             end= getOffset() + getLength() - MultiCommentLine.MULTI_COMMENT_END_PREFIX.trim().length();
124                             while (end > begin && ScannerHelper.isWhitespace(document.getChar(end - 1)))
125                                 end--;
126                         }
127                         
128                         String JavaDoc snippet= document.get(begin, end - begin);
129                         snippet= preprocessCodeSnippet(snippet);
130                         snippet= formatCodeSnippet(snippet);
131                         snippet= postprocessCodeSnippet(snippet, indentation);
132                         
133                         logEdit(snippet, begin - getOffset(), end - begin);
134                     }
135                 }
136             } catch (BadLocationException e) {
137                 // Can not happen
138
CommentFormatterUtil.log(e);
139             }
140         }
141     }
142
143     /**
144      * Preprocess a given code snippet.
145      *
146      * @param snippet the code snippet
147      * @return the preprocessed code snippet
148      */

149     private String JavaDoc preprocessCodeSnippet(String JavaDoc snippet) {
150         // strip content prefix
151
StringBuffer JavaDoc buffer= new StringBuffer JavaDoc();
152         ILineTracker tracker= new DefaultLineTracker();
153         String JavaDoc contentPrefix= MultiCommentLine.MULTI_COMMENT_CONTENT_PREFIX.trim();
154         
155         buffer.setLength(0);
156         buffer.append(snippet);
157         tracker.set(snippet);
158         for (int line= tracker.getNumberOfLines() - 1; line > 0; line--) {
159             int lineOffset;
160             try {
161                 lineOffset= tracker.getLineOffset(line);
162             } catch (BadLocationException e) {
163                 // Can not happen
164
CommentFormatterUtil.log(e);
165                 return snippet;
166             }
167             int prefixOffset= buffer.indexOf(contentPrefix, lineOffset);
168             if (prefixOffset >= 0 && buffer.substring(lineOffset, prefixOffset).trim().length() == 0)
169                 buffer.delete(lineOffset, prefixOffset + contentPrefix.length() + 1);
170         }
171         
172         return convertHtml2Java(buffer.toString());
173     }
174
175     /**
176      * Format the given code snippet
177      *
178      * @param snippet the code snippet
179      * @return the formatted code snippet
180      */

181     private String JavaDoc formatCodeSnippet(String JavaDoc snippet) {
182         String JavaDoc lineDelimiter= TextUtilities.getDefaultLineDelimiter(getDocument());
183         TextEdit edit= CommentFormatterUtil.format2(CodeFormatter.K_UNKNOWN, snippet, 0, lineDelimiter, this.preferences.getMap());
184         if (edit != null)
185             snippet= CommentFormatterUtil.evaluateFormatterEdit(snippet, edit, null);
186         return snippet;
187     }
188
189     /**
190      * Postprocesses the given code snippet with the given indentation.
191      *
192      * @param snippet the code snippet
193      * @param indentation the indentation
194      * @return the postprocessed code snippet
195      */

196     private String JavaDoc postprocessCodeSnippet(String JavaDoc snippet, String JavaDoc indentation) {
197         // patch content prefix
198
StringBuffer JavaDoc buffer= new StringBuffer JavaDoc();
199         ILineTracker tracker= new DefaultLineTracker();
200         String JavaDoc patch= indentation + MultiCommentLine.MULTI_COMMENT_CONTENT_PREFIX;
201
202         // remove trailing spaces
203
int i= snippet.length();
204         while (i > 0 && ' ' == snippet.charAt(i-1))
205             i--;
206         snippet= snippet.substring(0, i);
207         
208         buffer.setLength(0);
209         String JavaDoc lineDelimiter= getDelimiter();
210         if (lineDelimiter != null && snippet.indexOf(lineDelimiter) != 0)
211             buffer.append(lineDelimiter);
212         buffer.append(convertJava2Html(snippet));
213         if (lineDelimiter != null && snippet.lastIndexOf(lineDelimiter) != snippet.length() - lineDelimiter.length())
214             buffer.append(lineDelimiter);
215         tracker.set(buffer.toString());
216         
217         for (int line= tracker.getNumberOfLines() - 1; line > 0; line--)
218             try {
219                 buffer.insert(tracker.getLineOffset(line), patch);
220             } catch (BadLocationException e) {
221                 // Can not happen
222
CommentFormatterUtil.log(e);
223                 return snippet;
224             }
225         
226         return buffer.toString();
227     }
228
229     /*
230      * @see org.eclipse.jdt.internal.corext.text.comment.MultiCommentRegion#markHtmlRanges()
231      */

232     protected final void markHtmlRanges() {
233
234         markTagRanges(JAVADOC_IMMUTABLE_TAGS, COMMENT_IMMUTABLE, true);
235
236         if (fFormatSource)
237             markTagRanges(JAVADOC_CODE_TAGS, COMMENT_CODE, false);
238     }
239
240     /*
241      * @see org.eclipse.jdt.internal.corext.text.comment.MultiCommentRegion#markHtmlTag(org.eclipse.jdt.internal.corext.text.comment.CommentRange, java.lang.String)
242      */

243     protected final void markHtmlTag(final CommentRange range, final char[] token) {
244
245         if (range.hasAttribute(COMMENT_HTML)) {
246
247             range.markHtmlTag(JAVADOC_IMMUTABLE_TAGS, token, COMMENT_IMMUTABLE, true, true);
248             if (fFormatHtml) {
249
250                 range.markHtmlTag(JAVADOC_SEPARATOR_TAGS, token, COMMENT_SEPARATOR, true, true);
251                 range.markHtmlTag(JAVADOC_BREAK_TAGS, token, COMMENT_BREAK, false, true);
252                 range.markHtmlTag(JAVADOC_SINGLE_BREAK_TAG, token, COMMENT_BREAK, true, false);
253                 range.markHtmlTag(JAVADOC_NEWLINE_TAGS, token, COMMENT_NEWLINE, true, false);
254
255             } else
256                 range.markHtmlTag(JAVADOC_CODE_TAGS, token, COMMENT_SEPARATOR, true, true);
257         }
258     }
259
260     /*
261      * @see org.eclipse.jdt.internal.corext.text.comment.MultiCommentRegion#markJavadocTag(org.eclipse.jdt.internal.corext.text.comment.CommentRange, java.lang.String)
262      */

263     protected final void markJavadocTag(final CommentRange range, final char[] token) {
264
265         range.markPrefixTag(JAVADOC_PARAM_TAGS, COMMENT_TAG_PREFIX, token, COMMENT_PARAMETER);
266
267         if (token[0] == JAVADOC_TAG_PREFIX && !range.hasAttribute(COMMENT_PARAMETER))
268             range.setAttribute(COMMENT_ROOT);
269     }
270
271     /**
272      * Marks the comment region with the HTML range tag.
273      *
274      * @param tags the HTML tag which confines the HTML range
275      * @param attribute the attribute to set if the comment range is in the
276      * HTML range
277      * @param html <code>true</code> iff the HTML tags in this HTML range
278      * should be marked too, <code>false</code> otherwise
279      */

280     protected final void markTagRanges(final char[][] tags, final int attribute, final boolean html) {
281         
282         int level= 0;
283         int count= 0;
284         char[] token= null;
285         CommentRange current= null;
286         
287         for (int index= 0; index < tags.length; index++) {
288             
289             level= 0;
290             for (final Iterator JavaDoc iterator= getRanges().iterator(); iterator.hasNext();) {
291                 
292                 current= (CommentRange)iterator.next();
293                 count= current.getLength();
294                 
295                 if (count > 0 || level > 0) { // PR44035: when inside a tag, mark blank lines as well to get proper snippet formatting
296

297                     token= getText(current.getOffset(), current.getLength()).toCharArray();
298                     level= current.markTagRange(token, tags[index], level, attribute, html);
299                 }
300             }
301         }
302     }
303
304     /*
305      * @see org.eclipse.jdt.internal.corext.text.comment.CommentRegion#canAppend(org.eclipse.jdt.internal.corext.text.comment.CommentLine, org.eclipse.jdt.internal.corext.text.comment.CommentRange, org.eclipse.jdt.internal.corext.text.comment.CommentRange, int, int)
306      */

307     protected boolean canAppend(CommentLine line, CommentRange previous, CommentRange next, int index, int count) {
308         // don't append code sections
309
if (next.hasAttribute(COMMENT_CODE | COMMENT_FIRST_TOKEN) && line.getSize() != 0)
310             return false;
311         return super.canAppend(line, previous, next, index, count);
312     }
313
314     /**
315      * Converts <code>formatted</code> into valid html code suitable to be
316      * put inside &lt;pre&gt;&lt;/pre&gt; tags by replacing any html symbols
317      * by the relevant entities.
318      *
319      * @param formatted the formatted java code
320      * @return html version of the formatted code
321      */

322     private String JavaDoc convertJava2Html(String JavaDoc formatted) {
323         Java2HTMLEntityReader reader= new Java2HTMLEntityReader(new StringReader JavaDoc(formatted));
324         char[] buf= new char[256];
325         StringBuffer JavaDoc buffer= new StringBuffer JavaDoc();
326         int l;
327         try {
328             do {
329                 l= reader.read(buf);
330                 if (l != -1)
331                     buffer.append(buf, 0, l);
332             } while (l > 0);
333             return buffer.toString();
334         } catch (IOException JavaDoc e) {
335             return formatted;
336         }
337     }
338
339     /**
340      * Converts <code>html</code> into java code suitable for formatting
341      * by replacing any html entities by their plain text representation.
342      *
343      * @param html html code, may contain html entities
344      * @return plain textified version of <code>html</code>
345      */

346     private String JavaDoc convertHtml2Java(String JavaDoc html) {
347         HTMLEntity2JavaReader reader= new HTMLEntity2JavaReader(new StringReader JavaDoc(html));
348         char[] buf= new char[html.length()]; // html2text never gets longer, only shorter!
349

350         try {
351             int read= reader.read(buf);
352             return new String JavaDoc(buf, 0, read);
353         } catch (IOException JavaDoc e) {
354             return html;
355         }
356     }
357     
358     /*
359      * @see org.eclipse.jdt.internal.corext.text.comment.CommentRegion#createLine()
360      * @since 3.1
361      */

362     protected CommentLine createLine() {
363         return new JavaDocLine(this);
364     }
365 }
366
Popular Tags