update copyright
[fedora-idea.git] / java / java-impl / src / com / intellij / psi / impl / source / codeStyle / javadoc / CommentFormatter.java
blob9f900c0f65734a4fa934d71c64c11c18f75ec344
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.psi.impl.source.codeStyle.javadoc;
18 import com.intellij.lang.ASTNode;
19 import com.intellij.openapi.diagnostic.Logger;
20 import com.intellij.openapi.project.Project;
21 import com.intellij.openapi.util.text.LineTokenizer;
22 import com.intellij.psi.*;
23 import com.intellij.psi.codeStyle.CodeStyleSettings;
24 import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
25 import com.intellij.psi.impl.source.SourceTreeToPsiMap;
26 import com.intellij.psi.javadoc.PsiDocComment;
27 import com.intellij.util.IncorrectOperationException;
28 import org.jetbrains.annotations.Nullable;
30 /**
31 * @author max
33 public class CommentFormatter {
34 private static final Logger LOG = Logger.getInstance(
35 "#com.intellij.psi.impl.source.codeStyle.javadoc.CommentFormatter");
37 private final CodeStyleSettings mySettings;
38 private final JDParser myParser;
39 private final Project myProject;
41 public CommentFormatter(Project project) {
42 mySettings = CodeStyleSettingsManager.getSettings(project);
43 myParser = new JDParser(mySettings);
44 myProject = project;
47 public CodeStyleSettings getSettings() {
48 return mySettings;
51 public JDParser getParser() {
52 return myParser;
55 public void process(ASTNode element) {
56 if (!getSettings().ENABLE_JAVADOC_FORMATTING) return;
58 PsiElement psiElement = SourceTreeToPsiMap.treeElementToPsi(element);
59 processElementComment(psiElement);
62 private void processElementComment(PsiElement psiElement) {
63 if (psiElement instanceof PsiClass) {
64 String newCommentText = formatClassComment((PsiClass)psiElement);
65 replaceDocComment(newCommentText, (PsiDocCommentOwner)psiElement);
67 else if (psiElement instanceof PsiMethod) {
68 String newCommentText = formatMethodComment((PsiMethod)psiElement);
69 replaceDocComment(newCommentText, (PsiDocCommentOwner)psiElement);
71 else if (psiElement instanceof PsiField) {
72 String newCommentText = formatFieldComment((PsiField)psiElement);
73 replaceDocComment(newCommentText, (PsiDocCommentOwner)psiElement);
75 else if (psiElement instanceof PsiDocComment) {
76 processElementComment(psiElement.getParent());
80 private void replaceDocComment(String newCommentText, final PsiDocCommentOwner psiDocCommentOwner) {
81 final PsiDocComment oldComment = psiDocCommentOwner.getDocComment();
82 if (newCommentText != null) newCommentText = stripSpaces(newCommentText);
83 if (newCommentText == null || oldComment == null || newCommentText.equals(oldComment.getText())) {
84 return;
86 try {
87 PsiComment newComment = JavaPsiFacade.getInstance(myProject).getElementFactory().createCommentFromText(
88 newCommentText, null);
89 final ASTNode oldNode = oldComment.getNode();
90 final ASTNode newNode = newComment.getNode();
91 assert oldNode != null && newNode != null;
92 final ASTNode parent = oldNode.getTreeParent();
93 parent.replaceChild(oldNode, newNode); //important to replace with tree operation to avoid resolve and repository update
95 catch (IncorrectOperationException e) {
96 LOG.error(e);
100 private static String stripSpaces(String text) {
101 String[] lines = LineTokenizer.tokenize(text.toCharArray(), false);
102 StringBuffer buf = new StringBuffer(text.length());
103 for (int i = 0; i < lines.length; i++) {
104 if (i > 0) buf.append('\n');
105 buf.append(rTrim(lines[i]));
107 return buf.toString();
110 private static String rTrim(String text) {
111 int idx = text.length();
112 while (idx > 0) {
113 if (!Character.isWhitespace(text.charAt(idx-1))) break;
114 idx--;
116 return text.substring(0, idx);
119 @Nullable
120 private String formatClassComment(PsiClass psiClass) {
121 final String info = getOrigCommentInfo(psiClass);
122 if (info == null) return null;
124 JDComment comment = getParser().parse(info, new JDClassComment(this));
125 return comment.generate(getIndent(psiClass));
128 @Nullable
129 private String formatMethodComment(PsiMethod psiMethod) {
130 final String info = getOrigCommentInfo(psiMethod);
131 if (info == null) return null;
133 JDComment comment = getParser().parse(info, new JDMethodComment(this));
134 return comment.generate(getIndent(psiMethod));
137 @Nullable
138 private String formatFieldComment(PsiField psiField) {
139 final String info = getOrigCommentInfo(psiField);
140 if (info == null) return null;
142 JDComment comment = getParser().parse(info, new JDComment(this));
143 return comment.generate(getIndent(psiField));
147 * Returns the original comment info of the specified element or null
149 * @param element the specified element
150 * @return text chunk
152 private static String getOrigCommentInfo(PsiDocCommentOwner element) {
153 StringBuffer sb = new StringBuffer();
154 PsiElement e = element.getFirstChild();
155 if (!(e instanceof PsiComment)) {
156 // no comments for this element
157 return null;
159 else {
160 boolean first = true;
161 while (true) {
162 if (e instanceof PsiDocComment) {
163 PsiComment cm = (PsiComment)e;
164 String text = cm.getText();
165 if (text.startsWith("//")) {
166 if (!first) sb.append('\n');
167 sb.append(text.substring(2).trim());
169 else if (text.startsWith("/*")) {
170 if (text.charAt(2) == '*') {
171 text = text.substring(3, Math.max(3, text.length() - 2));
173 else {
174 text = text.substring(2, Math.max(2, text.length() - 2));
176 sb.append(text);
179 else if (!(e instanceof PsiWhiteSpace) && !(e instanceof PsiComment)) {
180 break;
182 first = false;
183 e = e.getNextSibling();
186 return sb.toString();
191 * For the specified element returns its indentation
193 * @param element the specified element
194 * @return indentation as string
196 private static String getIndent(PsiElement element) {
197 PsiElement e = element.getFirstChild();
198 PsiWhiteSpace lastWS = null;
199 for (; ; e = e.getNextSibling()) {
200 if (e instanceof PsiWhiteSpace) {
201 lastWS = (PsiWhiteSpace)e;
203 else if (e instanceof PsiComment) {
204 lastWS = null;
206 else {
207 break;
211 e = lastWS == null ? element.getPrevSibling() : lastWS;
212 if (!(e instanceof PsiWhiteSpace)) return "";
213 PsiWhiteSpace ws = (PsiWhiteSpace)e;
214 String t = ws.getText();
215 int l = t.length();
216 int i = l;
217 while (--i >= 0) {
218 char ch = t.charAt(i);
219 if (ch == '\n' || ch == '\r') break;
221 if (i < 0) return t;
222 i++;
223 if (i == l) return "";
224 return t.substring(i);