diff --git a/platform/lang-impl/src/com/intellij/codeInsight/generation/CommentByLineCommentHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/generation/CommentByLineCommentHandler.java index 05cbe5586ce8..a344a38e4496 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/generation/CommentByLineCommentHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/generation/CommentByLineCommentHandler.java @@ -44,9 +44,12 @@ import com.intellij.psi.util.PsiUtilBase; import com.intellij.util.StringBuilderSpinAllocator; import com.intellij.util.containers.IntArrayList; import com.intellij.util.text.CharArrayUtil; +import gnu.trove.THashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Map; + public class CommentByLineCommentHandler implements CodeInsightActionHandler { private Project myProject; private PsiFile myFile; @@ -59,6 +62,7 @@ public class CommentByLineCommentHandler implements CodeInsightActionHandler { private int[] myStartOffsets; private int[] myEndOffsets; private Commenter[] myCommenters; + private Map myCommenterStateMap; private CodeStyleManager myCodeStyleManager; public void invoke(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) { @@ -121,8 +125,19 @@ public class CommentByLineCommentHandler implements CodeInsightActionHandler { if (startingNewLineComment) { final Commenter commenter = myCommenters[0]; if (commenter != null) { - String prefix = commenter.getLineCommentPrefix(); - if (prefix == null) prefix = commenter.getBlockCommentPrefix(); + String prefix; + if (commenter instanceof SelfManagingCommenter) { + prefix = ((SelfManagingCommenter)commenter).getCommentPrefix( + myStartLine, + myDocument, + myFile, + myCommenterStateMap.get((SelfManagingCommenter)commenter) + ); + } else { + prefix = commenter.getLineCommentPrefix(); + if (prefix == null) prefix = commenter.getBlockCommentPrefix(); + } + int lineStart = myDocument.getLineStartOffset(myStartLine); lineStart = CharArrayUtil.shiftForward(myDocument.getCharsSequence(), lineStart, " \t"); lineStart += prefix.length(); @@ -169,6 +184,7 @@ public class CommentByLineCommentHandler implements CodeInsightActionHandler { myStartOffsets = new int[myEndLine - myStartLine + 1]; myEndOffsets = new int[myEndLine - myStartLine + 1]; myCommenters = new Commenter[myEndLine - myStartLine + 1]; + myCommenterStateMap = new THashMap(); CharSequence chars = myDocument.getCharsSequence(); boolean singleline = myStartLine == myEndLine; @@ -208,14 +224,24 @@ public class CommentByLineCommentHandler implements CodeInsightActionHandler { } boolean allLineCommented = true; + for (int line = myStartLine; line <= myEndLine; line++) { - final Commenter commenter = blockSuitableCommenter != null ? blockSuitableCommenter : findCommenter(line); + Commenter commenter = blockSuitableCommenter != null ? blockSuitableCommenter : findCommenter(line); if (commenter == null) return; - if (commenter.getLineCommentPrefix() == null && (commenter.getBlockCommentPrefix() == null || commenter.getBlockCommentSuffix() == null)) { return; } + + if (commenter instanceof SelfManagingCommenter && + myCommenterStateMap.get(commenter) == null) { + final SelfManagingCommenter selfManagingCommenter = (SelfManagingCommenter)commenter; + SelfManagingCommenter.CommenterDataHolder state = + selfManagingCommenter.createLineCommentingState(myStartLine, myEndLine, myDocument, myFile); + if (state == null) state = SelfManagingCommenter.CommenterDataHolder.EMPTY_STATE; + myCommenterStateMap.put(selfManagingCommenter, state); + } + myCommenters[line - myStartLine] = commenter; if (!isLineCommented(line, chars, commenter) && (singleline || !isLineEmpty(line))) { allLineCommented = false; @@ -271,38 +297,48 @@ public class CommentByLineCommentHandler implements CodeInsightActionHandler { } private boolean isLineCommented(final int line, final CharSequence chars, final Commenter commenter) { - String prefix = commenter.getLineCommentPrefix(); + boolean commented; + int lineEndForBlockCommenting = -1; int lineStart = myDocument.getLineStartOffset(line); lineStart = CharArrayUtil.shiftForward(chars, lineStart, " \t"); - boolean commented; - if (prefix != null) { - commented = CharArrayUtil.regionMatches(chars, lineStart, prefix) || - prefix.endsWith(" ") && CharArrayUtil.regionMatches(chars, lineStart, prefix.trim()+"\n"); - if (commented) { - myStartOffsets[line - myStartLine] = lineStart; - myEndOffsets[line - myStartLine] = -1; - } - } - else { - prefix = commenter.getBlockCommentPrefix(); - String suffix = commenter.getBlockCommentSuffix(); - final int textLength = myDocument.getTextLength(); - int lineEnd = myDocument.getLineEndOffset(line); - if (lineEnd == textLength) { - final int shifted = CharArrayUtil.shiftBackward(chars, textLength - 1, " \t"); - if (shifted < textLength - 1) lineEnd = shifted; + + if (commenter instanceof SelfManagingCommenter) { + final SelfManagingCommenter selfManagingCommenter = (SelfManagingCommenter)commenter; + commented = selfManagingCommenter.isCommented(line, lineStart, myDocument, myFile, myCommenterStateMap.get(selfManagingCommenter)); + } else { + String prefix = commenter.getLineCommentPrefix(); + + if (prefix != null) { + commented = CharArrayUtil.regionMatches(chars, lineStart, prefix) || + prefix.endsWith(" ") && CharArrayUtil.regionMatches(chars, lineStart, prefix.trim()+"\n"); + if (commented) { + myStartOffsets[line - myStartLine] = lineStart; + myEndOffsets[line - myStartLine] = -1; + } } else { - lineEnd = CharArrayUtil.shiftBackward(chars, lineEnd, " \t"); - } - commented = lineStart == lineEnd && myStartLine != myEndLine || - CharArrayUtil.regionMatches(chars, lineStart, prefix) - && CharArrayUtil.regionMatches(chars, lineEnd - suffix.length(), suffix); - if (commented) { - myStartOffsets[line - myStartLine] = lineStart; - myEndOffsets[line - myStartLine] = lineEnd; + prefix = commenter.getBlockCommentPrefix(); + String suffix = commenter.getBlockCommentSuffix(); + final int textLength = myDocument.getTextLength(); + lineEndForBlockCommenting = myDocument.getLineEndOffset(line); + if (lineEndForBlockCommenting == textLength) { + final int shifted = CharArrayUtil.shiftBackward(chars, textLength - 1, " \t"); + if (shifted < textLength - 1) lineEndForBlockCommenting = shifted; + } + else { + lineEndForBlockCommenting = CharArrayUtil.shiftBackward(chars, lineEndForBlockCommenting, " \t"); + } + commented = lineStart == lineEndForBlockCommenting && myStartLine != myEndLine || + CharArrayUtil.regionMatches(chars, lineStart, prefix) + && CharArrayUtil.regionMatches(chars, lineEndForBlockCommenting - suffix.length(), suffix); } } + + if (commented) { + myStartOffsets[line - myStartLine] = lineStart; + myEndOffsets[line - myStartLine] = lineEndForBlockCommenting; + } + return commented; } @@ -414,6 +450,13 @@ public class CommentByLineCommentHandler implements CodeInsightActionHandler { if (commenter == null) return; final int startOffset = myStartOffsets[line - myStartLine]; + + if (commenter instanceof SelfManagingCommenter) { + final SelfManagingCommenter selfManagingCommenter = (SelfManagingCommenter)commenter; + selfManagingCommenter.uncommentLine(line, startOffset, myDocument, myFile, myCommenterStateMap.get(selfManagingCommenter)); + return; + } + final int endOffset = myEndOffsets[line - myStartLine]; if (startOffset == endOffset) { return; @@ -471,6 +514,12 @@ public class CommentByLineCommentHandler implements CodeInsightActionHandler { private void commentLine(int line, int offset, @Nullable Commenter commenter) { if (commenter == null) commenter = findCommenter(line); if (commenter == null) return; + if (commenter instanceof SelfManagingCommenter) { + final SelfManagingCommenter selfManagingCommenter = (SelfManagingCommenter)commenter; + selfManagingCommenter.commentLine(line, offset, myDocument, myFile, myCommenterStateMap.get(selfManagingCommenter)); + return; + } + String prefix = commenter.getLineCommentPrefix(); if (prefix != null) { myDocument.insertString(offset, prefix); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/generation/SelfManagingCommenter.java b/platform/lang-impl/src/com/intellij/codeInsight/generation/SelfManagingCommenter.java new file mode 100644 index 000000000000..990056001ae5 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/generation/SelfManagingCommenter.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2010 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.generation; + +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; + +/** + * @author Maxim.Mossienko + */ +public interface SelfManagingCommenter { + ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.selfManagingCommenter"); + + T createLineCommentingState(int startLine, int endLine, Document document, PsiFile file); + + void commentLine(int line, int offset, Document document, PsiFile file, T data); + + void uncommentLine(int line, int startOffset, Document document, PsiFile file, T data); + + boolean isCommented(int line, int lineStart, Document document, PsiFile file, T data); + + @NotNull + String getCommentPrefix(int line, Document document, PsiFile file, T data); + + interface CommenterDataHolder { + CommenterDataHolder EMPTY_STATE = new CommenterDataHolder() {}; + } +} diff --git a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml index 727f9d853aa0..bb2b388ecb65 100644 --- a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml @@ -121,6 +121,8 @@ +