mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEADEV-407: Language API for block and line comments
This commit is contained in:
@@ -4,6 +4,8 @@ import com.intellij.ide.DataManager;
|
||||
import com.intellij.openapi.actionSystem.ActionManager;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -40,6 +42,12 @@ public abstract class EditorActionTestCase extends LightCodeInsightTestCase {
|
||||
protected void doTextTest(String fileName, String textBefore, String textAfter, boolean ignoreTrailingSpaces) throws IOException {
|
||||
configureFromFileText(fileName, textBefore);
|
||||
invokeAction();
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
public void run() {
|
||||
PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
|
||||
}
|
||||
});
|
||||
assertEquals("Reparse error!", myEditor.getDocument().getText(), myFile.getText());
|
||||
checkResultByText(null, textAfter, ignoreTrailingSpaces);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.intellij.lang;
|
||||
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
*/
|
||||
public interface Commenter {
|
||||
IElementType getLineCommentToken();
|
||||
String getLineCommentPrefix();
|
||||
boolean isLineCommentPrefixOnZeroColumn();
|
||||
|
||||
IElementType getBlockCommentToken();
|
||||
String getBlockCommentPrefix();
|
||||
String getBlockCommentSuffix();
|
||||
}
|
||||
@@ -70,6 +70,10 @@ public abstract class Language {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Commenter getCommenter() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Annotator getAnnotator() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ public abstract class JavaElementVisitor {
|
||||
}
|
||||
|
||||
public void visitComment(PsiComment comment) {
|
||||
visitJavaToken(comment);
|
||||
visitElement(comment);
|
||||
}
|
||||
|
||||
public void visitConditionalExpression(PsiConditionalExpression expression) {
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
*/
|
||||
package com.intellij.psi;
|
||||
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
|
||||
public interface PsiComment extends PsiJavaToken {
|
||||
|
||||
public interface PsiComment extends PsiElement {
|
||||
IElementType getTokenType();
|
||||
}
|
||||
|
||||
@@ -4,8 +4,10 @@
|
||||
*/
|
||||
package com.intellij.psi.xml;
|
||||
|
||||
import com.intellij.psi.PsiComment;
|
||||
|
||||
/**
|
||||
* @author Mike
|
||||
*/
|
||||
public interface XmlComment extends XmlElement {
|
||||
public interface XmlComment extends XmlElement, PsiComment {
|
||||
}
|
||||
|
||||
@@ -3,277 +3,36 @@ package com.intellij.codeInsight.generation;
|
||||
import com.intellij.codeInsight.CodeInsightActionHandler;
|
||||
import com.intellij.codeInsight.CodeInsightUtil;
|
||||
import com.intellij.featureStatistics.FeatureUsageTracker;
|
||||
import com.intellij.ide.highlighter.custom.CustomFileTypeLexer;
|
||||
import com.intellij.ide.highlighter.custom.impl.CustomFileType;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.lang.Commenter;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.lexer.Lexer;
|
||||
import com.intellij.openapi.editor.*;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.fileTypes.StdFileTypes;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.editor.ex.util.EditorUtil;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.CustomHighlighterTokenType;
|
||||
import com.intellij.psi.PsiComment;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettings;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
|
||||
import com.intellij.psi.codeStyle.Indent;
|
||||
import com.intellij.psi.jsp.JspFile;
|
||||
import com.intellij.psi.jsp.JspToken;
|
||||
import com.intellij.psi.jsp.JspTokenType;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.xml.XmlComment;
|
||||
import com.intellij.psi.xml.XmlFile;
|
||||
import com.intellij.psi.xml.XmlTag;
|
||||
import com.intellij.psi.xml.XmlToken;
|
||||
import com.intellij.util.text.CharArrayUtil;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class CommentByBlockCommentHandler implements CodeInsightActionHandler, BlockCommenter.BlockCommenterContext {
|
||||
public class CommentByBlockCommentHandler implements CodeInsightActionHandler {
|
||||
private Project myProject;
|
||||
private Editor myEditor;
|
||||
private PsiFile myFile;
|
||||
private Document myDocument;
|
||||
|
||||
private static final Map<FileType, BlockCommenter> customCommenters = new HashMap<FileType, BlockCommenter>(4);
|
||||
|
||||
public static final void registerCommenter(FileType fileType, BlockCommenter blockCommenter) {
|
||||
customCommenters.put(fileType, blockCommenter);
|
||||
}
|
||||
|
||||
public static BlockCommenter getCustomCommenter(FileType fileType) {
|
||||
return customCommenters.get(fileType);
|
||||
}
|
||||
|
||||
public static BlockCommenter getCommenter(PsiFile file) {
|
||||
BlockCommenter blockCommenter = customCommenters.get(file.getFileType());
|
||||
if (blockCommenter!=null) return blockCommenter;
|
||||
|
||||
if (isJavaFile(file)) {
|
||||
return new JavaBlockCommenter();
|
||||
} else if (file instanceof XmlFile) {
|
||||
return new XmlBlockCommenter();
|
||||
} else if (file instanceof JspFile) {
|
||||
return new JspBlockCommenter();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static {
|
||||
registerCommenter(StdFileTypes.JAVA,new JavaBlockCommenter());
|
||||
registerCommenter(StdFileTypes.JSP,new JspBlockCommenter());
|
||||
registerCommenter(StdFileTypes.XML,new XmlBlockCommenter());
|
||||
|
||||
HtmlBlockCommenter blockCommenter = new HtmlBlockCommenter();
|
||||
registerCommenter(StdFileTypes.HTML,blockCommenter);
|
||||
registerCommenter(StdFileTypes.XHTML,blockCommenter);
|
||||
registerCommenter(StdFileTypes.JSPX,new JspxBlockCommenter());
|
||||
}
|
||||
|
||||
static class JavaBlockCommenter implements BlockCommenter {
|
||||
public void commentRange(int start, int end, BlockCommenterContext context) {
|
||||
context.commentRange(start,end,"/*","*/");
|
||||
}
|
||||
|
||||
public void uncommentRange(PsiElement element, int commentStart, BlockCommenterContext context) {
|
||||
if (element instanceof PsiComment && element.getText().startsWith("/*")) {
|
||||
context.uncommentRange(element.getTextRange(),"/*", "*/");
|
||||
} else {
|
||||
context.insertEmptyComment(commentStart, "/*", "*/");
|
||||
}
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
try {
|
||||
return super.clone();
|
||||
}
|
||||
catch (CloneNotSupportedException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class XmlBlockCommenter implements BlockCommenter {
|
||||
public void commentRange(int start, int end, BlockCommenterContext context) {
|
||||
context.commentRange(start, end, "<!--", "-->");
|
||||
}
|
||||
|
||||
public void uncommentRange(PsiElement element, int commentStart, BlockCommenterContext context) {
|
||||
if (element.getParent() instanceof XmlComment) {
|
||||
context.uncommentRange(element.getParent().getTextRange(), "<!--", "-->");
|
||||
} else {
|
||||
context.insertEmptyComment(commentStart, "<!--", "-->");
|
||||
}
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
try {
|
||||
return super.clone();
|
||||
}
|
||||
catch (CloneNotSupportedException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class HtmlBlockCommenter implements BlockCommenter {
|
||||
private static BlockCommenter ourStyleCommenter;
|
||||
private boolean myInitialized;
|
||||
private BlockCommenter myCommenterToUse;
|
||||
private static BlockCommenter ourScriptCommenter;
|
||||
|
||||
private void initialize(PsiElement element, int start, int end, BlockCommenterContext context) {
|
||||
if (!myInitialized) {
|
||||
myInitialized = true;
|
||||
|
||||
if (element==null) {
|
||||
element = PsiUtil.getElementInclusiveRange(
|
||||
context.getFile(),
|
||||
new TextRange(start,end)
|
||||
);
|
||||
}
|
||||
|
||||
if (element!=null) {
|
||||
element = PsiTreeUtil.getParentOfType(element, XmlTag.class,false);
|
||||
|
||||
if (element instanceof XmlTag) {
|
||||
final String name = ((XmlTag)element).getName();
|
||||
|
||||
if (name.equalsIgnoreCase("style") &&
|
||||
ourStyleCommenter!=null
|
||||
) {
|
||||
myCommenterToUse = (BlockCommenter)ourStyleCommenter.clone();
|
||||
} else if (name.equalsIgnoreCase("script") && ourScriptCommenter!=null) {
|
||||
myCommenterToUse = (BlockCommenter)ourScriptCommenter.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (myCommenterToUse==null) {
|
||||
myCommenterToUse = new XmlBlockCommenter();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static final void setStyleCommenter(BlockCommenter _styleCommenter) {
|
||||
ourStyleCommenter = _styleCommenter;
|
||||
}
|
||||
|
||||
public void commentRange(int start, int end, BlockCommenterContext context) {
|
||||
initialize(null, start, end, context);
|
||||
myCommenterToUse.commentRange(start, end, context);
|
||||
}
|
||||
|
||||
public void uncommentRange(PsiElement element, int commentStart, BlockCommenterContext context) {
|
||||
initialize(element, -1, -1, context);
|
||||
myCommenterToUse.uncommentRange(element, commentStart, context);
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
try {
|
||||
return super.clone();
|
||||
}
|
||||
catch (CloneNotSupportedException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void setScriptCommenter(BlockCommenter scriptCommenter) {
|
||||
ourScriptCommenter = scriptCommenter;
|
||||
}
|
||||
}
|
||||
|
||||
static class JspxBlockCommenter extends HtmlBlockCommenter {
|
||||
private BlockCommenter javaCommenter = new JavaBlockCommenter();
|
||||
|
||||
private boolean isJavaCommentInsideXml(PsiElement element) {
|
||||
boolean javaComment = false;
|
||||
|
||||
final XmlTag tag = PsiTreeUtil.getParentOfType(element, XmlTag.class, false);
|
||||
|
||||
if (tag.getName().equals("jsp:scriplet") || tag.getName().equals("jsp:declaration")) {
|
||||
javaComment = true;
|
||||
}
|
||||
|
||||
return javaComment;
|
||||
}
|
||||
|
||||
public void commentRange(int start, int end, BlockCommenterContext context) {
|
||||
if (isJavaCommentInsideXml( context.getFile().findElementAt(start))) {
|
||||
javaCommenter.commentRange(start, end, context);
|
||||
} else {
|
||||
super.commentRange(start, end, context);
|
||||
}
|
||||
}
|
||||
|
||||
public void uncommentRange(PsiElement element, int commentStart, BlockCommenterContext context) {
|
||||
if (isJavaCommentInsideXml( context.getFile().findElementAt(commentStart))) {
|
||||
javaCommenter.uncommentRange(element, commentStart, context);
|
||||
} else {
|
||||
super.uncommentRange(element, commentStart, context);
|
||||
}
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
final JspxBlockCommenter commenter = (JspxBlockCommenter)super.clone();
|
||||
commenter.javaCommenter = (BlockCommenter)javaCommenter.clone();
|
||||
return commenter;
|
||||
}
|
||||
}
|
||||
|
||||
static class JspBlockCommenter implements BlockCommenter {
|
||||
|
||||
public void commentRange(int start, int end, BlockCommenterContext context) {
|
||||
PsiDocumentManager.getInstance(context.getProject()).commitDocument(context.getDocument());
|
||||
PsiElement element = context.getFile().findElementAt(start);
|
||||
|
||||
if (isJavaCommentInsideJsp(element, end)) {
|
||||
context.commentRange(start, end, "/*", "*/");
|
||||
} else {
|
||||
context.commentRange(start, end, "<%--", "--%>");
|
||||
}
|
||||
}
|
||||
|
||||
public void uncommentRange(PsiElement element, int commentStart, BlockCommenterContext context) {
|
||||
if (element instanceof JspToken && ((JspToken) element).getTokenType() == JspTokenType.JSP_COMMENT) {
|
||||
context.uncommentRange(element.getTextRange(), "<%--", "--%>");
|
||||
} else {
|
||||
if (element instanceof PsiComment && element.getText().startsWith("/*")) {
|
||||
context.uncommentRange(element.getTextRange(), "/*", "*/");
|
||||
} else {
|
||||
if (!isJavaCommentInsideJsp(element, commentStart)) {
|
||||
context.insertEmptyComment(commentStart, "%--", "--%");
|
||||
} else {
|
||||
context.insertEmptyComment(commentStart, "/*", "*/");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
try {
|
||||
return super.clone();
|
||||
}
|
||||
catch (CloneNotSupportedException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isJavaCommentInsideJsp(PsiElement element, int endOffset) {
|
||||
boolean javaComment = !(element instanceof JspToken);
|
||||
|
||||
while (element != null && element.getTextRange().getEndOffset() <= endOffset) {
|
||||
if (element instanceof JspToken) {
|
||||
javaComment = false;
|
||||
break;
|
||||
}
|
||||
element = element.getNextSibling();
|
||||
}
|
||||
return javaComment;
|
||||
}
|
||||
}
|
||||
|
||||
public void invoke(Project project, Editor editor, PsiFile file) {
|
||||
myProject = project;
|
||||
myEditor = editor;
|
||||
@@ -282,48 +41,129 @@ public class CommentByBlockCommentHandler implements CodeInsightActionHandler, B
|
||||
myDocument = editor.getDocument();
|
||||
|
||||
if (!myFile.isWritable()) {
|
||||
if (!FileDocumentManager.fileForDocumentCheckedOutSuccessfully(getDocument(), project)){
|
||||
if (!FileDocumentManager.fileForDocumentCheckedOutSuccessfully(myDocument, project)){
|
||||
return;
|
||||
}
|
||||
}
|
||||
FeatureUsageTracker.getInstance().triggerFeatureUsed("codeassists.comment.block");
|
||||
final SelectionModel selectionModel = myEditor.getSelectionModel();
|
||||
BlockCommenter commenter = getCommenter(myFile);
|
||||
final Commenter commenter = getCommenter();
|
||||
if (commenter == null) return;
|
||||
final BlockCommenter blockCommenter = (BlockCommenter)commenter.clone();
|
||||
|
||||
if (selectionModel.hasSelection()) {
|
||||
int startOffset = selectionModel.getSelectionStart();
|
||||
int endOffset = selectionModel.getSelectionEnd();
|
||||
final SelectionModel selectionModel = myEditor.getSelectionModel();
|
||||
|
||||
blockCommenter.commentRange(startOffset, endOffset, this);
|
||||
} else {
|
||||
int offset = editor.getCaretModel().getOffset();
|
||||
PsiDocumentManager.getInstance(project).commitDocument(myDocument);
|
||||
PsiElement element = file.findElementAt(offset);
|
||||
if (element == null && offset > 0) {
|
||||
element = file.findElementAt(offset - 1);
|
||||
final String prefix = commenter.getBlockCommentPrefix();
|
||||
final String suffix = commenter.getBlockCommentSuffix();
|
||||
if (prefix == null || suffix == null) return;
|
||||
|
||||
TextRange commentedRange = findCommentedRange(commenter);
|
||||
if (commentedRange != null) {
|
||||
uncommentRange(commentedRange, prefix, suffix);
|
||||
}
|
||||
else {
|
||||
if (selectionModel.hasBlockSelection()) {
|
||||
final LogicalPosition start = selectionModel.getBlockStart();
|
||||
final LogicalPosition end = selectionModel.getBlockEnd();
|
||||
int startColumn = Math.min(start.column, end.column);
|
||||
int endColumn = Math.max(start.column, end.column);
|
||||
int startLine = Math.min(start.line, end.line);
|
||||
int endLine = Math.max(start.line, end.line);
|
||||
|
||||
for (int i = startLine; i <= endLine; i++) {
|
||||
editor.getCaretModel().moveToLogicalPosition(new LogicalPosition(i, endColumn));
|
||||
EditorModificationUtil.insertStringAtCaret(editor, suffix, true, true);
|
||||
}
|
||||
|
||||
for (int i = startLine; i <= endLine; i++) {
|
||||
editor.getCaretModel().moveToLogicalPosition(new LogicalPosition(i, startColumn));
|
||||
EditorModificationUtil.insertStringAtCaret(editor, prefix, true, true);
|
||||
}
|
||||
}
|
||||
else if (selectionModel.hasSelection()) {
|
||||
int selectionStart = selectionModel.getSelectionStart();
|
||||
int selectionEnd = selectionModel.getSelectionEnd();
|
||||
commentRange(selectionStart, selectionEnd, prefix, suffix);
|
||||
}
|
||||
else {
|
||||
final LogicalPosition caretPosition = myEditor.getCaretModel().getLogicalPosition();
|
||||
EditorUtil.fillVirtualSpaceUntil(editor, caretPosition.column, caretPosition.line);
|
||||
int caretOffset = myEditor.getCaretModel().getOffset();
|
||||
myDocument.insertString(caretOffset, prefix + suffix);
|
||||
myEditor.getCaretModel().moveToOffset(caretOffset + prefix.length());
|
||||
}
|
||||
if (element == null) return;
|
||||
int commentStart = (element instanceof PsiWhiteSpace) ? offset : element.getTextRange().getStartOffset();
|
||||
blockCommenter.uncommentRange(element, commentStart, this);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isJavaFile(PsiFile file) {
|
||||
return file instanceof PsiJavaFile || file instanceof PsiCodeFragment;
|
||||
private TextRange findCommentedRange(final Commenter commenter) {
|
||||
final FileType fileType = myFile.getFileType();
|
||||
if (fileType instanceof CustomFileType) {
|
||||
Lexer lexer = new CustomFileTypeLexer(((CustomFileType)fileType).getSyntaxTable());
|
||||
final CharSequence text = myDocument.getCharsSequence();
|
||||
int commentStart = CharArrayUtil.lastIndexOf(text, commenter.getBlockCommentPrefix(), myEditor.getCaretModel().getOffset());
|
||||
if (commentStart == -1) return null;
|
||||
char[] chars = CharArrayUtil.fromSequence(text);
|
||||
lexer.start(chars, commentStart, text.length());
|
||||
|
||||
if (lexer.getTokenType() == CustomHighlighterTokenType.MULTI_LINE_COMMENT) {
|
||||
return new TextRange(commentStart, lexer.getTokenEnd());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
TextRange commentedRange = null;
|
||||
PsiElement comment = findCommentAtCaret(commenter);
|
||||
if (comment != null) {
|
||||
String commentText = comment.getText();
|
||||
String prefix = commenter.getBlockCommentPrefix();
|
||||
String suffix = commenter.getBlockCommentSuffix();
|
||||
if (!commentText.startsWith(prefix) || !commentText.endsWith(suffix)) return null;
|
||||
commentedRange = comment.getTextRange();
|
||||
}
|
||||
return commentedRange;
|
||||
}
|
||||
|
||||
private Commenter getCommenter() {
|
||||
final FileType fileType = myFile.getFileType();
|
||||
if (fileType instanceof CustomFileType) {
|
||||
return ((CustomFileType)fileType).getCommenter();
|
||||
}
|
||||
|
||||
final SelectionModel selectionModel = myEditor.getSelectionModel();
|
||||
int caretOffset = myEditor.getCaretModel().getOffset();
|
||||
Language lang = getLanguageAtOffset(caretOffset);
|
||||
if (lang == null) return null;
|
||||
if (selectionModel.hasSelection()) {
|
||||
Language l1 = getLanguageAtOffset(selectionModel.getSelectionStart());
|
||||
Language l2 = getLanguageAtOffset(selectionModel.getSelectionEnd());
|
||||
if (!Comparing.equal(lang, l1) || !Comparing.equal(lang, l2)) {
|
||||
// selection covers multiple languages use language of the file to comment
|
||||
lang = myFile.getLanguage();
|
||||
}
|
||||
}
|
||||
|
||||
return lang.getCommenter();
|
||||
}
|
||||
|
||||
private PsiElement findCommentAtCaret(Commenter commenter) {
|
||||
PsiElement elt = myFile.findElementAt(myEditor.getCaretModel().getOffset());
|
||||
if (elt == null) return null;
|
||||
final ASTNode node = elt.getNode();
|
||||
if (node != null && commenter.getBlockCommentToken() == node.getElementType()) return elt;
|
||||
return PsiTreeUtil.getParentOfType(elt, PsiComment.class, false);
|
||||
}
|
||||
|
||||
private Language getLanguageAtOffset(final int offset) {
|
||||
PsiElement elt = myFile.findElementAt(offset);
|
||||
if (elt == null) {
|
||||
if (offset > 0) elt = myFile.findElementAt(offset-1);
|
||||
if (elt == null) return null;
|
||||
}
|
||||
return elt.getLanguage();
|
||||
}
|
||||
|
||||
public boolean startInWriteAction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void insertEmptyComment(int offset, String commentStart, String commentEnd) {
|
||||
myEditor.getDocument().insertString(offset, commentStart + commentEnd);
|
||||
myEditor.getCaretModel().moveToOffset(offset + commentStart.length());
|
||||
}
|
||||
|
||||
|
||||
public void commentRange(int startOffset, int endOffset, String commentPrefix, String commentSuffix) {
|
||||
CharSequence chars = myDocument.getCharsSequence();
|
||||
LogicalPosition caretPosition = myEditor.getCaretModel().getLogicalPosition();
|
||||
@@ -363,22 +203,6 @@ public class CommentByBlockCommentHandler implements CodeInsightActionHandler, B
|
||||
myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
|
||||
}
|
||||
|
||||
public PsiFile getFile() {
|
||||
return myFile;
|
||||
}
|
||||
|
||||
public Document getDocument() {
|
||||
return myDocument;
|
||||
}
|
||||
|
||||
public Project getProject() {
|
||||
return myProject;
|
||||
}
|
||||
|
||||
public Editor getEditor() {
|
||||
return myEditor;
|
||||
}
|
||||
|
||||
public void uncommentRange(TextRange range, String commentPrefix, String commentSuffix) {
|
||||
CharSequence chars = myDocument.getCharsSequence();
|
||||
int startOffset = range.getStartOffset();
|
||||
|
||||
@@ -3,35 +3,25 @@ package com.intellij.codeInsight.generation;
|
||||
import com.intellij.codeInsight.CodeInsightActionHandler;
|
||||
import com.intellij.codeInsight.CodeInsightUtil;
|
||||
import com.intellij.featureStatistics.FeatureUsageTracker;
|
||||
import com.intellij.ide.highlighter.custom.impl.CustomFileType;
|
||||
import com.intellij.lang.Commenter;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.FoldRegion;
|
||||
import com.intellij.openapi.editor.SelectionModel;
|
||||
import com.intellij.openapi.editor.ex.DocumentEx;
|
||||
import com.intellij.openapi.editor.impl.FoldingModelImpl;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.fileTypes.StdFileTypes;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
|
||||
import com.intellij.psi.codeStyle.Indent;
|
||||
import com.intellij.psi.jsp.JspFile;
|
||||
import com.intellij.psi.jsp.JspToken;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.xml.XmlFile;
|
||||
import com.intellij.psi.xml.XmlTag;
|
||||
import com.intellij.psi.xml.XmlToken;
|
||||
import com.intellij.psi.xml.XmlTokenType;
|
||||
import com.intellij.util.text.CharArrayUtil;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class CommentByLineCommentHandler implements CodeInsightActionHandler, LineCommenter.LineCommenterContext {
|
||||
public class CommentByLineCommentHandler implements CodeInsightActionHandler {
|
||||
private Project myProject;
|
||||
private PsiFile myFile;
|
||||
private Editor myEditor;
|
||||
@@ -42,48 +32,10 @@ public class CommentByLineCommentHandler implements CodeInsightActionHandler, Li
|
||||
private int myLine2;
|
||||
private int[] myStartOffsets;
|
||||
private int[] myEndOffsets;
|
||||
private Commenter[] myCommenters;
|
||||
private boolean myAllLineComments;
|
||||
private CodeStyleManager myCodeStyleManager;
|
||||
|
||||
private static final Map<FileType,LineCommenter> customCommenters = new HashMap<FileType, LineCommenter>(4);
|
||||
|
||||
public static final void registerCommenter(FileType fileType, LineCommenter commenter) {
|
||||
customCommenters.put(fileType, commenter);
|
||||
}
|
||||
|
||||
static {
|
||||
registerCommenter(StdFileTypes.XML,new XmlLineCommenter());
|
||||
HtmlLineCommenter commenter = new HtmlLineCommenter();
|
||||
registerCommenter(StdFileTypes.HTML,commenter);
|
||||
registerCommenter(StdFileTypes.XHTML,commenter);
|
||||
registerCommenter(StdFileTypes.JAVA, new JavaLineCommenter());
|
||||
registerCommenter(StdFileTypes.JSP, new JspLineCommenter());
|
||||
|
||||
registerCommenter(StdFileTypes.JSPX, new JspxLineCommenter());
|
||||
}
|
||||
|
||||
public static LineCommenter getCustomCommenter(FileType fileType) {
|
||||
return customCommenters.get(fileType);
|
||||
}
|
||||
|
||||
public static LineCommenter getCommenter(PsiFile file) {
|
||||
LineCommenter customCommenter = customCommenters.get(file.getFileType());
|
||||
|
||||
if (customCommenter!=null) {
|
||||
return customCommenter;
|
||||
} else if (isJavaFile(file)) {
|
||||
return new JavaLineCommenter();
|
||||
}
|
||||
else if (file instanceof XmlFile) {
|
||||
return new XmlLineCommenter();
|
||||
}
|
||||
else if (file instanceof JspFile) {
|
||||
return new JspLineCommenter();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void invoke(Project project, Editor editor, PsiFile file) {
|
||||
myProject = project;
|
||||
myFile = file;
|
||||
@@ -91,7 +43,7 @@ public class CommentByLineCommentHandler implements CodeInsightActionHandler, Li
|
||||
myDocument = myEditor.getDocument();
|
||||
|
||||
if (!myFile.isWritable()) {
|
||||
if (!FileDocumentManager.fileForDocumentCheckedOutSuccessfully(getDocument(), project)){
|
||||
if (!FileDocumentManager.fileForDocumentCheckedOutSuccessfully(myDocument, project)){
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -145,49 +97,85 @@ public class CommentByLineCommentHandler implements CodeInsightActionHandler, Li
|
||||
|
||||
myStartOffsets = new int[myLine2 - myLine1 + 1];
|
||||
myEndOffsets = new int[myLine2 - myLine1 + 1];
|
||||
myCommenters = new Commenter[myLine2 - myLine1 + 1];
|
||||
myAllLineComments = true;
|
||||
|
||||
CharSequence chars = myDocument.getCharsSequence();
|
||||
LineCommenter lineCommenter = customCommenters.get(myFile.getFileType());
|
||||
if (lineCommenter==null) return;
|
||||
LineCommenter customCommenter = (LineCommenter)lineCommenter.clone();
|
||||
|
||||
for (int line = myLine1; line <= myLine2; line++) {
|
||||
int offset1 = getCommentStart(line,customCommenter);
|
||||
myStartOffsets[line - myLine1] = offset1;
|
||||
if (offset1 == -1) {
|
||||
myAllLineComments = false;
|
||||
break;
|
||||
}
|
||||
|
||||
int offset = myDocument.getLineEndOffset(line) + ((DocumentEx) myDocument).getLineSeparatorLength(line);
|
||||
offset = CharArrayUtil.shiftBackward(chars, offset - 1, "\n\r") + 1;
|
||||
|
||||
int offset2 = customCommenter.getCommentEnd(offset,this);
|
||||
myEndOffsets[line - myLine1] = offset2;
|
||||
|
||||
if (offset2 == -1) {
|
||||
final Commenter commenter = findCommenter(line);
|
||||
if (commenter == null) return;
|
||||
if (commenter.getLineCommentPrefix() == null && (commenter.getBlockCommentPrefix() == null || commenter.getBlockCommentSuffix() == null)) return;
|
||||
myCommenters[line - myLine1] = commenter;
|
||||
if (!isLineCommented(line, chars, commenter)) {
|
||||
myAllLineComments = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!myAllLineComments) {
|
||||
new CommentPerformer(customCommenter).perform();
|
||||
new CommentPerformer().perform();
|
||||
}
|
||||
else {
|
||||
for (int line = myLine2; line >= myLine1; line--) {
|
||||
int offset1 = myStartOffsets[line - myLine1];
|
||||
int offset2 = myEndOffsets[line - myLine1];
|
||||
customCommenter.doUncomment(offset1,offset2,this);
|
||||
Commenter commenter = myCommenters[line - myLine1];
|
||||
if (offset2 >= 0) {
|
||||
myDocument.deleteString(offset2 - commenter.getBlockCommentSuffix().length(), offset2);
|
||||
}
|
||||
if (offset1 >= 0) {
|
||||
myDocument.deleteString(offset1, offset1 + commenter.getBlockCommentPrefix().length());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Indent computeMinIndent(int line1, int line2, CharSequence chars, CodeStyleManager codeStyleManager, FileType fileType, LineCommenter commenter) {
|
||||
private boolean isLineCommented(final int line, final CharSequence chars, final Commenter commenter) {
|
||||
boolean commented;
|
||||
String prefix = commenter.getLineCommentPrefix();
|
||||
int lineStart = myDocument.getLineStartOffset(line);
|
||||
lineStart = CharArrayUtil.shiftForward(chars, lineStart, " \t");
|
||||
if (prefix != null) {
|
||||
commented = CharArrayUtil.regionMatches(chars, lineStart, prefix);
|
||||
if (commented) {
|
||||
myStartOffsets[line - myLine1] = lineStart;
|
||||
myEndOffsets[line - myLine1] = -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
prefix = commenter.getBlockCommentPrefix();
|
||||
String suffix = commenter.getBlockCommentSuffix();
|
||||
int lineEnd = myDocument.getLineEndOffset(line);
|
||||
lineEnd = CharArrayUtil.shiftBackward(chars, lineEnd, " \t");
|
||||
commented = CharArrayUtil.regionMatches(chars, lineStart, prefix) && CharArrayUtil.regionMatches(chars, lineEnd - suffix.length(), suffix);
|
||||
if (commented) {
|
||||
myStartOffsets[line - myLine1] = lineStart;
|
||||
myEndOffsets[line - myLine1] = lineEnd;
|
||||
}
|
||||
|
||||
}
|
||||
return commented;
|
||||
}
|
||||
|
||||
private Commenter findCommenter(final int line) {
|
||||
final FileType fileType = myFile.getFileType();
|
||||
if (fileType instanceof CustomFileType) {
|
||||
return ((CustomFileType)fileType).getCommenter();
|
||||
}
|
||||
|
||||
int offset = myDocument.getLineStartOffset(line);
|
||||
final PsiElement elt = myFile.findElementAt(offset);
|
||||
if (elt == null) return null;
|
||||
final Language lang = elt.getLanguage();
|
||||
if (lang == null) return null;
|
||||
return lang.getCommenter();
|
||||
}
|
||||
|
||||
private Indent computeMinIndent(int line1, int line2, CharSequence chars, CodeStyleManager codeStyleManager, FileType fileType) {
|
||||
Indent minIndent = CodeInsightUtil.getMinLineIndent(myProject, myDocument, line1, line2, fileType);
|
||||
if (line1 > 0) {
|
||||
int commentOffset = getCommentStart(line1 - 1,commenter);
|
||||
int commentOffset = getCommentStart(line1 - 1);
|
||||
if (commentOffset >= 0) {
|
||||
int lineStart = myDocument.getLineStartOffset(line1 - 1);
|
||||
String space = chars.subSequence(lineStart, commentOffset).toString();
|
||||
@@ -201,86 +189,70 @@ public class CommentByLineCommentHandler implements CodeInsightActionHandler, Li
|
||||
return minIndent;
|
||||
}
|
||||
|
||||
|
||||
private int getCommentStart(int line, LineCommenter commenter ) {
|
||||
private int getCommentStart(int line) {
|
||||
int offset = myDocument.getLineStartOffset(line);
|
||||
CharSequence chars = myDocument.getCharsSequence();
|
||||
offset = CharArrayUtil.shiftForward(chars, offset, " \t");
|
||||
|
||||
return commenter.getCommentStart(offset,this);
|
||||
}
|
||||
|
||||
private static boolean isJavaFile(PsiFile file) {
|
||||
return file instanceof PsiJavaFile || file instanceof PsiCodeFragment;
|
||||
}
|
||||
|
||||
public CharSequence getChars() {
|
||||
return myDocument.getCharsSequence();
|
||||
}
|
||||
|
||||
public Document getDocument() {
|
||||
return myDocument;
|
||||
}
|
||||
|
||||
public Project getProject() {
|
||||
return myProject;
|
||||
}
|
||||
|
||||
public PsiFile getFile() {
|
||||
return myFile;
|
||||
}
|
||||
|
||||
public int getStartLine() {
|
||||
return myLine1;
|
||||
}
|
||||
|
||||
public int getEndLine() {
|
||||
return myLine2;
|
||||
final Commenter commenter = findCommenter(line);
|
||||
if (commenter == null) return -1;
|
||||
String prefix = commenter.getLineCommentPrefix();
|
||||
if (prefix == null) prefix = commenter.getBlockCommentPrefix();
|
||||
if (prefix == null) return -1;
|
||||
return CharArrayUtil.regionMatches(chars, offset, prefix) ? offset : -1;
|
||||
}
|
||||
|
||||
private class CommentPerformer {
|
||||
LineCommenter myCommenter;
|
||||
|
||||
public CommentPerformer(LineCommenter commenter) {
|
||||
myCommenter = commenter;
|
||||
public CommentPerformer() {
|
||||
}
|
||||
|
||||
public void perform() {
|
||||
if (CodeStyleSettingsManager.getSettings(myProject).LINE_COMMENT_AT_FIRST_COLUMN) {
|
||||
new DefaultCommentPerformer(myCommenter).perform();
|
||||
new DefaultCommentPerformer().perform();
|
||||
}
|
||||
else {
|
||||
new IndentCommentPerformer(myCommenter).perform();
|
||||
new IndentCommentPerformer().perform();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class DefaultCommentPerformer {
|
||||
LineCommenter myCommenter;
|
||||
|
||||
public DefaultCommentPerformer(LineCommenter commenter) {
|
||||
myCommenter = commenter;
|
||||
public DefaultCommentPerformer() {
|
||||
}
|
||||
|
||||
public void perform() {
|
||||
for (int line = myLine2; line >= myLine1; line--) {
|
||||
int offset = myDocument.getLineStartOffset(line);
|
||||
myCommenter.doComment(offset, line, CommentByLineCommentHandler.this);
|
||||
commentLine(line, offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class IndentCommentPerformer {
|
||||
LineCommenter myCommenter;
|
||||
private void commentLine(int line, int offset) {
|
||||
final Commenter commenter = findCommenter(line);
|
||||
String prefix = commenter.getLineCommentPrefix();
|
||||
if (prefix != null) {
|
||||
myDocument.insertString(offset, prefix);
|
||||
}
|
||||
else {
|
||||
prefix = commenter.getBlockCommentPrefix();
|
||||
String suffix = commenter.getBlockCommentSuffix();
|
||||
int endOffset = myDocument.getLineEndOffset(line);
|
||||
offset = CharArrayUtil.shiftForward(myDocument.getCharsSequence(), offset, " \t");
|
||||
endOffset = CharArrayUtil.shiftBackward(myDocument.getCharsSequence(), endOffset, " \t");
|
||||
myDocument.insertString(endOffset, suffix);
|
||||
myDocument.insertString(offset, prefix);
|
||||
}
|
||||
}
|
||||
|
||||
public IndentCommentPerformer(LineCommenter commenter) {
|
||||
myCommenter = commenter;
|
||||
private class IndentCommentPerformer {
|
||||
|
||||
public IndentCommentPerformer() {
|
||||
}
|
||||
|
||||
public void perform() {
|
||||
CharSequence chars = myDocument.getCharsSequence();
|
||||
final FileType fileType = myFile.getFileType();
|
||||
Indent minIndent = computeMinIndent(myLine1, myLine2, chars, myCodeStyleManager, fileType,myCommenter);
|
||||
Indent minIndent = computeMinIndent(myLine1, myLine2, chars, myCodeStyleManager, fileType);
|
||||
|
||||
for (int line = myLine2; line >= myLine1; line--) {
|
||||
int lineStart = myDocument.getLineStartOffset(line);
|
||||
@@ -301,329 +273,8 @@ public class CommentByLineCommentHandler implements CodeInsightActionHandler, Li
|
||||
offset++;
|
||||
}
|
||||
|
||||
myCommenter.doComment(offset, line, CommentByLineCommentHandler.this);
|
||||
commentLine(line, offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class HtmlLineCommenter implements LineCommenter {
|
||||
private static LineCommenter ourStyleCommenter;
|
||||
private boolean myInitialized;
|
||||
private LineCommenter myCommenterToUse;
|
||||
private static LineCommenter ourScriptCommenter;
|
||||
|
||||
private void initialize(LineCommenterContext context) {
|
||||
if (!myInitialized) {
|
||||
PsiElement elementInclusiveRange = PsiUtil.getElementInclusiveRange(
|
||||
context.getFile(),
|
||||
new TextRange(
|
||||
context.getDocument().getLineStartOffset(context.getStartLine()),
|
||||
context.getDocument().getLineEndOffset(context.getEndLine())
|
||||
)
|
||||
);
|
||||
elementInclusiveRange = PsiTreeUtil.getParentOfType(elementInclusiveRange,XmlTag.class,false);
|
||||
|
||||
if (elementInclusiveRange instanceof XmlTag) {
|
||||
String tagName = ((XmlTag)elementInclusiveRange).getName();
|
||||
|
||||
if (tagName.equalsIgnoreCase("style") &&
|
||||
ourStyleCommenter!=null
|
||||
) {
|
||||
myCommenterToUse = (LineCommenter)ourStyleCommenter.clone();
|
||||
} else if (tagName.equalsIgnoreCase("script") &&
|
||||
ourScriptCommenter!=null
|
||||
) {
|
||||
myCommenterToUse = (LineCommenter)ourScriptCommenter.clone();
|
||||
}
|
||||
}
|
||||
|
||||
if (myCommenterToUse == null) {
|
||||
myCommenterToUse = new XmlLineCommenter();
|
||||
}
|
||||
myInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static final void setStyleCommenter(LineCommenter _styleCommenter) {
|
||||
ourStyleCommenter = _styleCommenter;
|
||||
}
|
||||
|
||||
public void doComment(int offset, int line, LineCommenterContext context) {
|
||||
initialize(context);
|
||||
myCommenterToUse.doComment(offset, line, context);
|
||||
}
|
||||
|
||||
public int getCommentEnd(int offset, LineCommenterContext context) {
|
||||
initialize(context);
|
||||
return myCommenterToUse.getCommentEnd(offset, context);
|
||||
}
|
||||
|
||||
public int getCommentStart(int offset, LineCommenterContext context) {
|
||||
initialize(context);
|
||||
return myCommenterToUse.getCommentStart(offset, context);
|
||||
}
|
||||
|
||||
public void doUncomment(int offset1, int offset2, LineCommenterContext context) {
|
||||
initialize(context);
|
||||
myCommenterToUse.doUncomment(offset1, offset2, context);
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
try {
|
||||
return super.clone();
|
||||
}
|
||||
catch (CloneNotSupportedException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void setScriptCommenter(LineCommenter scriptCommenter) {
|
||||
ourScriptCommenter = scriptCommenter;
|
||||
}
|
||||
}
|
||||
|
||||
private static class XmlLineCommenter implements LineCommenter {
|
||||
public void doComment(int offset, int line, LineCommenterContext context) {
|
||||
final Document myDocument = context.getDocument();
|
||||
myDocument.insertString(offset, "<!--");
|
||||
myDocument.insertString(myDocument.getLineEndOffset(line), "-->");
|
||||
}
|
||||
|
||||
public int getCommentEnd(int offset, LineCommenterContext context) {
|
||||
offset -= "-->".length();
|
||||
if (offset < 0) return -1;
|
||||
|
||||
if (!CharArrayUtil.regionMatches(context.getChars(), offset, "-->")) return -1;
|
||||
|
||||
PsiDocumentManager.getInstance(context.getProject()).commitDocument(context.getDocument());
|
||||
PsiElement element = context.getFile().findElementAt(offset);
|
||||
if (element instanceof XmlToken && element.getTextRange().getStartOffset() == offset) {
|
||||
XmlToken token = (XmlToken)element;
|
||||
|
||||
if (token.getTokenType() == XmlTokenType.XML_COMMENT_END) {
|
||||
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int getCommentStart(int offset, LineCommenterContext context) {
|
||||
if (offset > context.getDocument().getTextLength() - "<!--".length()) return -1;
|
||||
if (!CharArrayUtil.regionMatches(context.getChars(), offset, "<!--")) return -1;
|
||||
|
||||
PsiDocumentManager.getInstance(context.getProject()).commitDocument(context.getDocument());
|
||||
PsiElement element = context.getFile().findElementAt(offset);
|
||||
if (element instanceof XmlToken && element.getTextRange().getStartOffset() == offset) {
|
||||
XmlToken token = (XmlToken)element;
|
||||
|
||||
if (token.getTokenType() == XmlTokenType.XML_COMMENT_START) {
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
public void doUncomment(int offset1, int offset2, LineCommenterContext context) {
|
||||
context.getDocument().deleteString(offset2, offset2 + 3);
|
||||
context.getDocument().deleteString(offset1, offset1 + 4);
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
try {
|
||||
return super.clone();
|
||||
} catch(CloneNotSupportedException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class JavaLineCommenter implements LineCommenter {
|
||||
public void doComment(int offset, int line, LineCommenterContext context) {
|
||||
context.getDocument().insertString(offset, "//");
|
||||
}
|
||||
|
||||
public int getCommentEnd(int offset, LineCommenterContext context) {
|
||||
return offset;
|
||||
}
|
||||
|
||||
public void doUncomment(int offset, int offset2, LineCommenterContext context) {
|
||||
context.getDocument().deleteString(offset, offset + 2);
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
try {
|
||||
return super.clone();
|
||||
} catch(CloneNotSupportedException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public int getCommentStart(int offset, LineCommenterContext context) {
|
||||
if (offset > context.getDocument().getTextLength() - 2) return -1;
|
||||
if (!CharArrayUtil.regionMatches(context.getChars(), offset, "//")) return -1;
|
||||
|
||||
PsiDocumentManager.getInstance(context.getProject()).commitDocument(context.getDocument());
|
||||
PsiElement element = context.getFile().findElementAt(offset);
|
||||
|
||||
if (element instanceof PsiComment && element.getTextRange().getStartOffset() == offset) {
|
||||
return offset;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private static class JspLineCommenter implements LineCommenter {
|
||||
private boolean myJavaComment;
|
||||
private boolean initialized;
|
||||
|
||||
public void doComment(int offset, int line, LineCommenterContext context) {
|
||||
final Document myDocument = context.getDocument();
|
||||
|
||||
if (!initialized) {
|
||||
PsiDocumentManager.getInstance(context.getProject()).commitAllDocuments();
|
||||
|
||||
myJavaComment = true;
|
||||
for (int line1 = context.getStartLine(); line1 <= context.getEndLine(); line1++) {
|
||||
int offset1 = myDocument.getLineStartOffset(line1);
|
||||
final PsiElement elementAt = context.getFile().findElementAt(offset1);
|
||||
if (elementAt instanceof JspToken) {
|
||||
myJavaComment = false;
|
||||
}
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
if (myJavaComment) {
|
||||
myDocument.insertString(offset, "//");
|
||||
}
|
||||
else {
|
||||
myDocument.insertString(offset, "<%--");
|
||||
myDocument.insertString(myDocument.getLineEndOffset(line), "--%>");
|
||||
}
|
||||
}
|
||||
|
||||
public void doUncomment(int offset1, int offset2, LineCommenterContext context) {
|
||||
final Document myDocument = context.getDocument();
|
||||
|
||||
if (CharArrayUtil.regionMatches(myDocument.getCharsSequence(), offset1, "//")) {
|
||||
myDocument.deleteString(offset1, offset1 + "//".length());
|
||||
}
|
||||
else {
|
||||
myDocument.deleteString(offset2, offset2 + "--%>".length());
|
||||
myDocument.deleteString(offset1, offset1 + "<%--".length());
|
||||
}
|
||||
}
|
||||
|
||||
public int getCommentStart(int offset, LineCommenterContext context) {
|
||||
final Document myDocument = context.getDocument();
|
||||
if (offset > myDocument.getTextLength() - "//".length()) return -1;
|
||||
|
||||
if (CharArrayUtil.regionMatches(myDocument.getCharsSequence(), offset, "//")) {
|
||||
PsiDocumentManager.getInstance(context.getProject()).commitDocument(myDocument);
|
||||
PsiElement element = context.getFile().findElementAt(offset);
|
||||
if (element instanceof PsiComment && element.getTextRange().getStartOffset() == offset) {
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (offset > myDocument.getTextLength() - "<%--".length()) return -1;
|
||||
if (CharArrayUtil.regionMatches(myDocument.getCharsSequence(), offset, "<%--")) return offset;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int getCommentEnd(int offset, LineCommenterContext context) {
|
||||
if (offset < 0) return -1;
|
||||
if (!CharArrayUtil.regionMatches(context.getChars(), offset - "--%>".length(), "--%>")) return offset;
|
||||
return offset - "--%>".length();
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
try {
|
||||
return super.clone();
|
||||
} catch(CloneNotSupportedException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class JspxLineCommenter extends HtmlLineCommenter {
|
||||
private boolean myJavaComment;
|
||||
private boolean initialized;
|
||||
|
||||
public void doComment(int offset, int line, LineCommenter.LineCommenterContext context) {
|
||||
final Document myDocument = context.getDocument();
|
||||
initialize(context);
|
||||
|
||||
if (myJavaComment) {
|
||||
myDocument.insertString(offset, "//");
|
||||
}
|
||||
else {
|
||||
super.doComment(offset, line, context);
|
||||
}
|
||||
}
|
||||
|
||||
private void initialize(final LineCommenterContext context) {
|
||||
if (initialized) return;
|
||||
PsiDocumentManager.getInstance(context.getProject()).commitAllDocuments();
|
||||
Document myDocument = context.getDocument();
|
||||
myJavaComment = false;
|
||||
|
||||
for (int line1 = context.getStartLine(); line1 <= context.getEndLine(); line1++) {
|
||||
int offset1 = myDocument.getLineStartOffset(line1);
|
||||
final PsiElement elementAt = context.getFile().findElementAt(offset1);
|
||||
final XmlTag tag = PsiTreeUtil.getParentOfType(elementAt, XmlTag.class, false);
|
||||
|
||||
if (tag == null || tag.getName().equals("jsp:scriplet") || tag.getName().equals("jsp:declaration")) {
|
||||
myJavaComment = true;
|
||||
}
|
||||
}
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
public void doUncomment(int offset1, int offset2, LineCommenterContext context) {
|
||||
final Document myDocument = context.getDocument();
|
||||
initialize(context);
|
||||
|
||||
if (myJavaComment && CharArrayUtil.regionMatches(myDocument.getCharsSequence(), offset1, "//")) {
|
||||
myDocument.deleteString(offset1, offset1 + "//".length());
|
||||
}
|
||||
else {
|
||||
super.doUncomment(offset1, offset2, context);
|
||||
}
|
||||
}
|
||||
|
||||
public int getCommentStart(int offset, LineCommenterContext context) {
|
||||
final Document myDocument = context.getDocument();
|
||||
if (offset > myDocument.getTextLength() - "//".length()) return -1;
|
||||
initialize(context);
|
||||
|
||||
if (myJavaComment && CharArrayUtil.regionMatches(myDocument.getCharsSequence(), offset, "//")) {
|
||||
PsiDocumentManager.getInstance(context.getProject()).commitDocument(myDocument);
|
||||
PsiElement element = context.getFile().findElementAt(offset);
|
||||
if (element instanceof PsiComment && element.getTextRange().getStartOffset() == offset) {
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return super.getCommentStart(offset, context);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int getCommentEnd(int offset, LineCommenterContext context) {
|
||||
if (offset < 0) return -1;
|
||||
initialize(context);
|
||||
|
||||
if (myJavaComment) return offset;
|
||||
return super.getCommentEnd(offset, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+10
-3
@@ -3,11 +3,12 @@ package com.intellij.codeInsight.generation.actions;
|
||||
import com.intellij.codeInsight.CodeInsightActionHandler;
|
||||
import com.intellij.codeInsight.actions.BaseCodeInsightAction;
|
||||
import com.intellij.codeInsight.generation.CommentByBlockCommentHandler;
|
||||
import com.intellij.ide.highlighter.custom.impl.CustomFileType;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileTypes.StdFileTypes;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.xml.XmlFile;
|
||||
|
||||
public class CommentByBlockCommentAction extends BaseCodeInsightAction {
|
||||
public CommentByBlockCommentAction() {
|
||||
@@ -19,6 +20,12 @@ public class CommentByBlockCommentAction extends BaseCodeInsightAction {
|
||||
}
|
||||
|
||||
protected boolean isValidForFile(Project project, Editor editor, final PsiFile file) {
|
||||
return CommentByBlockCommentHandler.getCommenter(file)!=null;
|
||||
final FileType fileType = file.getFileType();
|
||||
if (fileType instanceof CustomFileType) {
|
||||
return ((CustomFileType)fileType).getCommenter() != null;
|
||||
}
|
||||
|
||||
final Language lang = file.getLanguage();
|
||||
return lang != null && lang.getCommenter() != null;
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,30 @@
|
||||
package com.intellij.codeInsight.generation.actions;
|
||||
|
||||
import com.intellij.aspects.psi.PsiAspectFile;
|
||||
import com.intellij.codeInsight.CodeInsightActionHandler;
|
||||
import com.intellij.codeInsight.actions.BaseCodeInsightAction;
|
||||
import com.intellij.codeInsight.generation.CommentByLineCommentHandler;
|
||||
import com.intellij.ide.highlighter.custom.impl.CustomFileType;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiJavaFile;
|
||||
import com.intellij.psi.jsp.JspFile;
|
||||
import com.intellij.psi.xml.XmlFile;
|
||||
|
||||
public class CommentByLineCommentAction extends BaseCodeInsightAction{
|
||||
public class CommentByLineCommentAction extends BaseCodeInsightAction {
|
||||
public CommentByLineCommentAction() {
|
||||
setEnabledInModalContext(true);
|
||||
}
|
||||
|
||||
protected CodeInsightActionHandler getHandler(){
|
||||
protected CodeInsightActionHandler getHandler() {
|
||||
return new CommentByLineCommentHandler();
|
||||
}
|
||||
|
||||
protected boolean isValidForFile(Project project, Editor editor, final PsiFile file) {
|
||||
return CommentByLineCommentHandler.getCommenter(file)!=null;
|
||||
final FileType fileType = file.getFileType();
|
||||
if (fileType instanceof CustomFileType) {
|
||||
return ((CustomFileType)fileType).getCommenter() != null;
|
||||
}
|
||||
final Language lang = file.getLanguage();
|
||||
return lang != null && lang.getCommenter() != null;
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,11 @@ package com.intellij.lang.dtd;
|
||||
|
||||
import com.intellij.find.findUsages.FindUsagesManager;
|
||||
import com.intellij.ide.highlighter.XmlFileHighlighter;
|
||||
import com.intellij.lang.Commenter;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.lang.ParserDefinition;
|
||||
import com.intellij.lang.findUsages.FindUsagesProvider;
|
||||
import com.intellij.lang.xml.XmlCommenter;
|
||||
import com.intellij.openapi.fileTypes.SyntaxHighlighter;
|
||||
import com.intellij.openapi.project.Project;
|
||||
|
||||
@@ -32,4 +34,8 @@ public class DTDLanguage extends Language {
|
||||
public FindUsagesProvider getFindUsagesProvider() {
|
||||
return new FindUsagesManager.HtmlFindUsagesHandler();
|
||||
}
|
||||
|
||||
public Commenter getCommenter() {
|
||||
return new XmlCommenter();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,7 +269,7 @@ public class PsiBuilderImpl implements PsiBuilder {
|
||||
TreeUtil.addChildren((CompositeElement)curNode, errorElement);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LOG.assertTrue(curToken == myLexems.size(), "Not all of the tokens inserted to the tree");
|
||||
LOG.assertTrue(curNode == null, "Unbalanced tree");
|
||||
|
||||
@@ -280,18 +280,23 @@ public class PsiBuilderImpl implements PsiBuilder {
|
||||
lastIdx = Math.min(lastIdx, myLexems.size());
|
||||
while (curToken < lastIdx) {
|
||||
Token lexem = myLexems.get(curToken++);
|
||||
final IElementType type = lexem.getTokenType();
|
||||
final LeafPsiElement childNode = new LeafPsiElement(type,
|
||||
myLexer.getBuffer(),
|
||||
lexem.myTokenStart,
|
||||
lexem.myTokenEnd,
|
||||
lexem.myState,
|
||||
myCharTable);
|
||||
final LeafPsiElement childNode = createLeaf(lexem);
|
||||
TreeUtil.addChildren((CompositeElement)curNode, childNode);
|
||||
}
|
||||
return curToken;
|
||||
}
|
||||
|
||||
private LeafPsiElement createLeaf(final Token lexem) {
|
||||
final IElementType type = lexem.getTokenType();
|
||||
if (myWhitespaces.isInSet(type)) {
|
||||
return new PsiWhiteSpaceImpl(myLexer.getBuffer(), lexem.myTokenStart, lexem.myTokenEnd, lexem.myState, myCharTable);
|
||||
}
|
||||
else if (myComments.isInSet(type)) {
|
||||
return new PsiCommentImpl(type, myLexer.getBuffer(), lexem.myTokenStart, lexem.myTokenEnd, lexem.myState, myCharTable);
|
||||
}
|
||||
return new LeafPsiElement(type, myLexer.getBuffer(), lexem.myTokenStart, lexem.myTokenEnd, lexem.myState, myCharTable);
|
||||
}
|
||||
|
||||
/**
|
||||
* just to make removeRange method available.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.intellij.lang.java;
|
||||
|
||||
import com.intellij.lang.Commenter;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
*/
|
||||
public class JavaCommenter implements Commenter {
|
||||
public IElementType getLineCommentToken() {
|
||||
return JavaTokenType.END_OF_LINE_COMMENT;
|
||||
}
|
||||
|
||||
public String getLineCommentPrefix() {
|
||||
return "//";
|
||||
}
|
||||
|
||||
public boolean isLineCommentPrefixOnZeroColumn() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public IElementType getBlockCommentToken() {
|
||||
return JavaTokenType.C_STYLE_COMMENT;
|
||||
}
|
||||
|
||||
public String getBlockCommentPrefix() {
|
||||
return "/*";
|
||||
}
|
||||
|
||||
public String getBlockCommentSuffix() {
|
||||
return "*/";
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package com.intellij.lang.java;
|
||||
|
||||
import com.intellij.codeFormatting.PseudoTextBuilder;
|
||||
import com.intellij.ide.highlighter.JavaFileHighlighter;
|
||||
import com.intellij.lang.Commenter;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.lang.ParserDefinition;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
@@ -40,4 +41,8 @@ public class JavaLanguage extends Language {
|
||||
public ParserDefinition getParserDefinition() {
|
||||
return new JavaParserDefinition();
|
||||
}
|
||||
|
||||
public Commenter getCommenter() {
|
||||
return new JavaCommenter();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.intellij.codeFormatting.PseudoTextBuilder;
|
||||
import com.intellij.codeFormatting.xml.xml.XmlPseudoTextBuilder;
|
||||
import com.intellij.find.findUsages.FindUsagesManager;
|
||||
import com.intellij.ide.highlighter.XmlFileHighlighter;
|
||||
import com.intellij.lang.Commenter;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.lang.ParserDefinition;
|
||||
import com.intellij.lang.findUsages.FindUsagesProvider;
|
||||
@@ -53,4 +54,8 @@ public class XMLLanguage extends Language {
|
||||
public FindUsagesProvider getFindUsagesProvider() {
|
||||
return FIND_USAGES_HANDLER;
|
||||
}
|
||||
|
||||
public Commenter getCommenter() {
|
||||
return new XmlCommenter();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.intellij.lang.xml;
|
||||
|
||||
import com.intellij.lang.Commenter;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
*/
|
||||
public class XmlCommenter implements Commenter {
|
||||
public IElementType getLineCommentToken() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getLineCommentPrefix() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isLineCommentPrefixOnZeroColumn() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public IElementType getBlockCommentToken() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getBlockCommentPrefix() {
|
||||
return "<!--";
|
||||
}
|
||||
|
||||
public String getBlockCommentSuffix() {
|
||||
return "-->";
|
||||
}
|
||||
}
|
||||
@@ -4,13 +4,14 @@ import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.PsiJavaToken;
|
||||
import com.intellij.psi.impl.source.tree.ElementType;
|
||||
import com.intellij.psi.impl.source.tree.TreeElement;
|
||||
import com.intellij.psi.javadoc.PsiDocComment;
|
||||
import com.intellij.psi.javadoc.PsiDocTag;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
|
||||
class ClsDocCommentImpl extends ClsElementImpl implements PsiDocComment, JavaTokenType{
|
||||
class ClsDocCommentImpl extends ClsElementImpl implements PsiDocComment, JavaTokenType, PsiJavaToken {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.compiled.ClsDocCommentImpl");
|
||||
|
||||
private final ClsElementImpl myParent;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.intellij.psi.impl.source.javadoc;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.lexer.JavaDocLexer;
|
||||
import com.intellij.lexer.JavaLexer;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
@@ -7,6 +8,7 @@ import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.PsiJavaToken;
|
||||
import com.intellij.psi.impl.source.SourceTreeToPsiMap;
|
||||
import com.intellij.psi.impl.source.parsing.ChameleonTransforming;
|
||||
import com.intellij.psi.impl.source.tree.*;
|
||||
@@ -16,12 +18,11 @@ import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import com.intellij.util.CharTable;
|
||||
import com.intellij.util.text.CharArrayCharSequence;
|
||||
import com.intellij.lang.ASTNode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class PsiDocCommentImpl extends CompositePsiElement implements PsiDocComment, JavaTokenType, Reparseable {
|
||||
public class PsiDocCommentImpl extends CompositePsiElement implements PsiDocComment, JavaTokenType, Reparseable, PsiJavaToken {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.javadoc.PsiDocCommentImpl");
|
||||
|
||||
private static final TokenSet TAG_BIT_SET = TokenSet.create(new IElementType[]{DOC_TAG});
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
package com.intellij.psi.impl.source.tree;
|
||||
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiComment;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.util.CharTable;
|
||||
|
||||
public class PsiCommentImpl extends LeafPsiElement implements PsiComment, JavaTokenType {
|
||||
protected PsiCommentImpl(IElementType type, char[] buffer, int startOffset, int endOffset, int lexerState, CharTable table) {
|
||||
public class PsiCommentImpl extends LeafPsiElement implements PsiComment, JavaTokenType, PsiJavaToken {
|
||||
public PsiCommentImpl(IElementType type, char[] buffer, int startOffset, int endOffset, int lexerState, CharTable table) {
|
||||
super(type, buffer, startOffset, endOffset, lexerState, table);
|
||||
}
|
||||
|
||||
@@ -22,4 +21,11 @@ public class PsiCommentImpl extends LeafPsiElement implements PsiComment, JavaTo
|
||||
public String toString(){
|
||||
return "PsiComment(" + getElementType().toString() + ")";
|
||||
}
|
||||
|
||||
public Language getLanguage() {
|
||||
PsiElement master = getNextSibling();
|
||||
if (master == null) master = getPrevSibling();
|
||||
if (master == null) master = getParent();
|
||||
return master.getLanguage();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
package com.intellij.psi.impl.source.tree;
|
||||
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.PsiWhiteSpace;
|
||||
import com.intellij.psi.TokenType;
|
||||
import com.intellij.util.CharTable;
|
||||
|
||||
public class PsiWhiteSpaceImpl extends LeafPsiElement implements PsiWhiteSpace {
|
||||
protected PsiWhiteSpaceImpl(char[] buffer, int startOffset, int endOffset, int lexerState, CharTable table) {
|
||||
public PsiWhiteSpaceImpl(char[] buffer, int startOffset, int endOffset, int lexerState, CharTable table) {
|
||||
super(TokenType.WHITE_SPACE, buffer, startOffset, endOffset, lexerState, table);
|
||||
}
|
||||
|
||||
@@ -17,4 +19,11 @@ public class PsiWhiteSpaceImpl extends LeafPsiElement implements PsiWhiteSpace {
|
||||
public String toString(){
|
||||
return "PsiWhiteSpace";
|
||||
}
|
||||
|
||||
public Language getLanguage() {
|
||||
PsiElement master = getNextSibling();
|
||||
if (master == null) master = getPrevSibling();
|
||||
if (master == null) master = getParent();
|
||||
return master.getLanguage();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.intellij.psi.impl.source.xml;
|
||||
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.xml.XmlComment;
|
||||
|
||||
/**
|
||||
@@ -11,6 +12,10 @@ public class XmlCommentImpl extends XmlElementImpl implements XmlComment {
|
||||
super(XML_COMMENT);
|
||||
}
|
||||
|
||||
public IElementType getTokenType() {
|
||||
return XML_COMMENT;
|
||||
}
|
||||
|
||||
public void accept(PsiElementVisitor visitor) {
|
||||
visitor.visitXmlComment(this);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user