KickJava   Java API By Example, From Geeks To Geeks.

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


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.util.HashSet JavaDoc;
15 import java.util.Set JavaDoc;
16
17 import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
18 import org.eclipse.jface.text.IRegion;
19 import org.eclipse.jface.text.Region;
20
21 /**
22  * Multi-line comment line in a comment region.
23  *
24  * @since 3.0
25  */

26 public class MultiCommentLine extends CommentLine implements ICommentAttributes, IHtmlTagDelimiters, IJavaDocTagConstants {
27
28     /** Line prefix of multi-line comment content lines */
29     public static final String JavaDoc MULTI_COMMENT_CONTENT_PREFIX= " * "; //$NON-NLS-1$
30

31     /** Line prefix of multi-line comment end lines */
32     public static final String JavaDoc MULTI_COMMENT_END_PREFIX= " */"; //$NON-NLS-1$
33

34     /** Line prefix of multi-line comment content lines */
35     public static final String JavaDoc MULTI_COMMENT_START_PREFIX= "/* "; //$NON-NLS-1$
36

37     /** The indentation reference of this line */
38     private String JavaDoc fReferenceIndentation= ""; //$NON-NLS-1$
39

40     /** The javadoc tag lookup. */
41     private static final Set JavaDoc fgTagLookup;
42     
43     static {
44         fgTagLookup= new HashSet JavaDoc();
45         for (int i= 0; i < JAVADOC_BREAK_TAGS.length; i++) {
46             fgTagLookup.add(new String JavaDoc(JAVADOC_BREAK_TAGS[i]));
47         }
48         for (int i= 0; i < JAVADOC_SINGLE_BREAK_TAG.length; i++) {
49             fgTagLookup.add(new String JavaDoc(JAVADOC_SINGLE_BREAK_TAG[i]));
50         }
51         for (int i= 0; i < JAVADOC_CODE_TAGS.length; i++) {
52             fgTagLookup.add(new String JavaDoc(JAVADOC_CODE_TAGS[i]));
53         }
54         for (int i= 0; i < JAVADOC_IMMUTABLE_TAGS.length; i++) {
55             fgTagLookup.add(new String JavaDoc(JAVADOC_IMMUTABLE_TAGS[i]));
56         }
57         for (int i= 0; i < JAVADOC_NEWLINE_TAGS.length; i++) {
58             fgTagLookup.add(new String JavaDoc(JAVADOC_NEWLINE_TAGS[i]));
59         }
60         for (int i= 0; i < JAVADOC_SEPARATOR_TAGS.length; i++) {
61             fgTagLookup.add(new String JavaDoc(JAVADOC_SEPARATOR_TAGS[i]));
62         }
63     }
64
65     /**
66      * Creates a new multi-line comment line.
67      *
68      * @param region comment region to create the line for
69      */

70     protected MultiCommentLine(final CommentRegion region) {
71         super(region);
72     }
73
74     /*
75      * @see org.eclipse.jdt.internal.corext.text.comment.CommentLine#adapt(org.eclipse.jdt.internal.corext.text.comment.CommentLine)
76      */

77     protected void adapt(final CommentLine previous) {
78
79         if (!hasAttribute(COMMENT_ROOT) && !hasAttribute(COMMENT_PARAMETER) && !previous.hasAttribute(COMMENT_BLANKLINE))
80             fReferenceIndentation= previous.getIndentationReference();
81     }
82
83     /*
84      * @see org.eclipse.jdt.internal.corext.text.comment.CommentLine#append(org.eclipse.jdt.internal.corext.text.comment.CommentRange)
85      */

86     protected void append(final CommentRange range) {
87
88         final MultiCommentRegion parent= (MultiCommentRegion)getParent();
89
90         if (range.hasAttribute(COMMENT_PARAMETER))
91             setAttribute(COMMENT_PARAMETER);
92         else if (range.hasAttribute(COMMENT_ROOT))
93             setAttribute(COMMENT_ROOT);
94         else if (range.hasAttribute(COMMENT_BLANKLINE))
95             setAttribute(COMMENT_BLANKLINE);
96
97         final int ranges= getSize();
98         if (ranges == 1) {
99
100             if (parent.isIndentRoots()) {
101
102                 final CommentRange first= getFirst();
103                 final String JavaDoc common= parent.getText(first.getOffset(), first.getLength()) + CommentRegion.COMMENT_RANGE_DELIMITER;
104
105                 if (hasAttribute(COMMENT_ROOT))
106                     fReferenceIndentation= common;
107                 else if (hasAttribute(COMMENT_PARAMETER)) {
108                     if (parent.isIndentDescriptions())
109                         fReferenceIndentation= "\t" + common; //$NON-NLS-1$
110
else
111                         fReferenceIndentation= common;
112                 }
113             }
114         }
115         super.append(range);
116     }
117
118     /*
119      * @see org.eclipse.jdt.internal.corext.text.comment.CommentLine#getContentLinePrefix()
120      */

121     protected String JavaDoc getContentPrefix() {
122         return MULTI_COMMENT_CONTENT_PREFIX;
123     }
124
125     /*
126      * @see org.eclipse.jdt.internal.corext.text.comment.CommentLine#getEndLinePrefix()
127      */

128     protected String JavaDoc getEndingPrefix() {
129         return MULTI_COMMENT_END_PREFIX;
130     }
131
132     /**
133      * Returns the reference indentation to use for this line.
134      *
135      * @return the reference indentation for this line
136      */

137     protected final String JavaDoc getIndentationReference() {
138         return fReferenceIndentation;
139     }
140
141     /*
142      * @see org.eclipse.jdt.internal.corext.text.comment.CommentLine#getStartLinePrefix()
143      */

144     protected String JavaDoc getStartingPrefix() {
145         return MULTI_COMMENT_START_PREFIX;
146     }
147
148     /*
149      * @see org.eclipse.jdt.internal.corext.text.comment.CommentLine#scanLine(int)
150      */

151     protected void scanLine(final int line) {
152
153         final CommentRegion parent= getParent();
154         final String JavaDoc start= getStartingPrefix().trim();
155         final String JavaDoc end= getEndingPrefix().trim();
156         final String JavaDoc content= getContentPrefix().trim();
157
158         final int lines= parent.getSize();
159         final CommentRange range= getFirst();
160
161         int offset= 0;
162         int postfix= 0;
163
164         String JavaDoc text= parent.getText(range.getOffset(), range.getLength());
165         if (line == 0) {
166
167             offset= text.indexOf(start);
168             if (offset >= 0 && text.substring(0, offset).trim().length() != 0)
169                 offset= -1;
170             
171             if (offset >= 0) {
172
173                 offset += start.length();
174                 range.trimBegin(offset);
175
176                 postfix= text.lastIndexOf(end);
177                 if (postfix >= 0 && text.substring(postfix + end.length()).trim().length() != 0)
178                     postfix= -1;
179                 
180                 if (postfix >= offset)
181                     // comment ends on same line
182
range.setLength(postfix - offset);
183                 else {
184                     postfix= text.lastIndexOf(content);
185                     if (postfix >= 0 && text.substring(postfix + content.length()).trim().length() != 0)
186                         postfix= -1;
187                     
188                     if (postfix >= offset) {
189
190                         range.setLength(postfix - offset);
191                         parent.setBorder(BORDER_UPPER);
192
193                         if (postfix > offset) {
194
195                             text= parent.getText(range.getOffset(), range.getLength());
196                             final IRegion region= trimLine(text, content);
197
198                             range.move(region.getOffset());
199                             range.setLength(region.getLength());
200                         }
201                     }
202                 }
203             }
204         } else if (line == lines - 1) {
205
206             offset= text.indexOf(content);
207             if (offset >= 0 && text.substring(0, offset).trim().length() != 0)
208                 offset= -1;
209             postfix= text.lastIndexOf(end);
210             if (postfix >= 0 && text.substring(postfix + end.length()).trim().length() != 0)
211                 postfix= -1;
212             
213             if (offset >= 0 && offset == postfix)
214                 // no content on line, only the comment postfix
215
range.setLength(0);
216             else {
217                 if (offset >= 0)
218                     // omit the content prefix
219
range.trimBegin(offset + content.length());
220                 
221                 if (postfix >= 0)
222                     // omit the comment postfix
223
range.trimEnd(-end.length());
224                 
225                 text= parent.getText(range.getOffset(), range.getLength());
226                 final IRegion region= trimLine(text, content);
227                 if (region.getOffset() != 0 || region.getLength() != text.length()) {
228
229                     range.move(region.getOffset());
230                     range.setLength(region.getLength());
231
232                     parent.setBorder(BORDER_UPPER);
233                     parent.setBorder(BORDER_LOWER);
234                 }
235             }
236         } else {
237
238             offset= text.indexOf(content);
239             if (offset >= 0 && text.substring(0, offset).trim().length() != 0)
240                 offset= -1;
241             
242             if (offset >= 0) {
243
244                 offset += content.length();
245                 range.trimBegin(offset);
246             }
247         }
248     }
249
250     /*
251      * @see org.eclipse.jdt.internal.corext.text.comment.CommentLine#tokenizeLine(int)
252      */

253     protected void tokenizeLine(int line) {
254
255         int offset= 0;
256         int index= offset;
257
258         final CommentRegion parent= getParent();
259         final CommentRange range= getFirst();
260         final int begin= range.getOffset();
261
262         final String JavaDoc content= parent.getText(begin, range.getLength());
263         final int length= content.length();
264
265         while (offset < length && ScannerHelper.isWhitespace(content.charAt(offset)))
266             offset++;
267
268         CommentRange result= null;
269         if (offset >= length && !parent.isClearLines() && (line > 0 && line < parent.getSize() - 1)) {
270
271             result= new CommentRange(begin, 0);
272             result.setAttribute(COMMENT_BLANKLINE);
273             result.setAttribute(COMMENT_FIRST_TOKEN);
274
275             parent.append(result);
276         }
277
278         int attribute= COMMENT_FIRST_TOKEN | COMMENT_STARTS_WITH_RANGE_DELIMITER;
279         while (offset < length) {
280
281             while (offset < length && ScannerHelper.isWhitespace(content.charAt(offset))) {
282                 offset++;
283                 attribute |= COMMENT_STARTS_WITH_RANGE_DELIMITER;
284             }
285
286             index= offset;
287
288             if (index < length) {
289
290                 if (content.charAt(index) == HTML_TAG_PREFIX) {
291
292                     // in order to avoid recognizing any < in a comment, even those which are part of e.g.
293
// java source code, we validate the tag content to be one of the recognized
294
// tags (structural, breaks, pre, code).
295
int tag= ++index;
296                     while (index < length && content.charAt(index) != HTML_TAG_POSTFIX && content.charAt(index) != HTML_TAG_PREFIX)
297                         index++;
298
299                     if (index < length && content.charAt(index) == HTML_TAG_POSTFIX && isValidTag(content.substring(tag, index))) {
300                         index++;
301                         attribute |= COMMENT_HTML; // only set html attribute if postfix found
302
} else {
303                         // no tag - do the usual thing from the original offset
304
index= tag;
305                         while (index < length
306                                 && !ScannerHelper.isWhitespace(content.charAt(index))
307                                 && content.charAt(index) != HTML_TAG_PREFIX
308                                 && !content.startsWith(LINK_TAG_PREFIX_STRING, index))
309                             index++;
310                     }
311
312
313                 } else if (content.startsWith(LINK_TAG_PREFIX_STRING, index)) {
314
315                     while (index < length && content.charAt(index) != LINK_TAG_POSTFIX)
316                         index++;
317
318                     if (index < length && content.charAt(index) == LINK_TAG_POSTFIX)
319                         index++;
320
321                     attribute |= COMMENT_OPEN | COMMENT_CLOSE;
322
323                 } else {
324
325                     while (index < length
326                             && !ScannerHelper.isWhitespace(content.charAt(index))
327                             && content.charAt(index) != HTML_TAG_PREFIX
328                             && !content.startsWith(LINK_TAG_PREFIX_STRING, index))
329                         index++;
330                 }
331             }
332
333             if (index - offset > 0) {
334
335                 result= new CommentRange(begin + offset, index - offset);
336                 result.setAttribute(attribute);
337
338                 parent.append(result);
339                 offset= index;
340             }
341             
342             attribute= 0;
343         }
344     }
345
346     /**
347      * Checks whether <code>tag</code> is a valid tag content (text inside
348      * the angular brackets &lt;, &gt;).
349      * <p>
350      * The algorithm is to see if the tag trimmed of whitespace and an
351      * optional slash starts with one of our recognized tags.
352      *
353      * @param tag the tag to check
354      * @return <code>true</code> if <code>tag</code> is a valid tag
355      * content
356      */

357     private boolean isValidTag(String JavaDoc tag) {
358         // strip the slash
359
if (tag.startsWith("/")) //$NON-NLS-1$
360
tag= tag.substring(1, tag.length());
361         
362         // strip ws
363
tag= tag.trim();
364         
365         // extract first token
366
int i= 0;
367         while (i < tag.length() && !ScannerHelper.isWhitespace(tag.charAt(i)))
368             i++;
369         tag= tag.substring(0, i);
370         
371         // see if it's a tag
372
return isTagName(tag.toLowerCase());
373     }
374
375     /**
376      * Checks whether <code>tag</code> is one of the configured tags.
377      *
378      * @param tag the tag to check
379      * @return <code>true</code> if <code>tag</code> is a configured tag
380      * name
381      */

382     private boolean isTagName(String JavaDoc tag) {
383         return fgTagLookup.contains(tag);
384     }
385
386     /**
387      * Removes all leading and trailing occurrences from <code>line</code>.
388      *
389      * @param line the string to remove the occurrences of
390      * <code>trimmable</code>
391      * @param trimmable the string to remove from <code>line</code>
392      * @return the region of the trimmed substring within <code>line</code>
393      */

394     protected final IRegion trimLine(final String JavaDoc line, final String JavaDoc trimmable) {
395
396         final int trim= trimmable.length();
397
398         int offset= 0;
399         int length= line.length() - trim;
400
401         while (line.startsWith(trimmable, offset))
402             offset += trim;
403
404         while (line.startsWith(trimmable, length))
405             length -= trim;
406
407         return new Region(offset, length + trim);
408     }
409 }
410
Popular Tags