From 24b1f59950ae8bab42cd79fa172820a6c483d0be Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Thu, 16 Oct 2014 18:16:04 +0400 Subject: [PATCH] IDEA-58423 xml: commenting double dashes produces invalid xml --- .../CommentByBlockCommentHandler.java | 28 +++++-- .../generation/EscapingCommenter.java | 33 ++------ .../com/intellij/lang/xml/XmlCommenter.java | 79 +++++++++++++++++++ 3 files changed, 108 insertions(+), 32 deletions(-) rename xml/xml-psi-impl/src/com/intellij/lang/xml/XmlCommenter.java => platform/lang-impl/src/com/intellij/codeInsight/generation/EscapingCommenter.java (55%) create mode 100644 xml/impl/src/com/intellij/lang/xml/XmlCommenter.java diff --git a/platform/lang-impl/src/com/intellij/codeInsight/generation/CommentByBlockCommentHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/generation/CommentByBlockCommentHandler.java index 4fa6dd1a3b27..27a27dad6f2e 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/generation/CommentByBlockCommentHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/generation/CommentByBlockCommentHandler.java @@ -387,7 +387,7 @@ public class CommentByBlockCommentHandler extends MultiCaretCodeInsightActionHan } public void commentRange(int startOffset, int endOffset, String commentPrefix, String commentSuffix, Commenter commenter) { - CharSequence chars = myDocument.getCharsSequence(); + final CharSequence chars = myDocument.getCharsSequence(); LogicalPosition caretPosition = myCaret.getLogicalPosition(); if (startOffset == 0 || chars.charAt(startOffset - 1) == '\n') { @@ -416,7 +416,7 @@ public class CommentByBlockCommentHandler extends MultiCaretCodeInsightActionHan nestingSuffix.append(commentSuffix.startsWith("\n") ? commentSuffix.substring(1) : commentSuffix); nestingSuffix.append("\n"); TextRange range = - insertNestedComments(chars, startOffset, endOffset, nestingPrefix.toString(), nestingSuffix.toString(), commenter); + insertNestedComments(startOffset, endOffset, nestingPrefix.toString(), nestingSuffix.toString(), commenter); myCaret.setSelection(range.getStartOffset(), range.getEndOffset()); LogicalPosition pos = new LogicalPosition(caretPosition.line + 1, caretPosition.column); myCaret.moveToLogicalPosition(pos); @@ -424,7 +424,7 @@ public class CommentByBlockCommentHandler extends MultiCaretCodeInsightActionHan } } - TextRange range = insertNestedComments(chars, startOffset, endOffset, commentPrefix, commentSuffix, commenter); + TextRange range = insertNestedComments(startOffset, endOffset, commentPrefix, commentSuffix, commenter); myCaret.setSelection(range.getStartOffset(), range.getEndOffset()); LogicalPosition pos = new LogicalPosition(caretPosition.line, caretPosition.column + commentPrefix.length()); myCaret.moveToLogicalPosition(pos); @@ -449,8 +449,7 @@ public class CommentByBlockCommentHandler extends MultiCaretCodeInsightActionHan } } - private TextRange insertNestedComments(CharSequence chars, - int startOffset, + private TextRange insertNestedComments(int startOffset, int endOffset, String commentPrefix, String commentSuffix, @@ -471,6 +470,7 @@ public class CommentByBlockCommentHandler extends MultiCaretCodeInsightActionHan IntArrayList nestedCommentSuffixes = new IntArrayList(); String commentedPrefix = commenter.getCommentedBlockCommentPrefix(); String commentedSuffix = commenter.getCommentedBlockCommentSuffix(); + CharSequence chars = myDocument.getCharsSequence(); for (int i = startOffset; i < endOffset; ++i) { if (CharArrayUtil.regionMatches(chars, i, normalizedPrefix)) { nestedCommentPrefixes.add(i); @@ -523,7 +523,20 @@ public class CommentByBlockCommentHandler extends MultiCaretCodeInsightActionHan shift += commentPrefix.length(); } - return new TextRange(startOffset, endOffset + shift); + TextRange range = new TextRange(startOffset, endOffset + shift); + return processDocument(range, commenter, true); + } + + private TextRange processDocument(TextRange range, Commenter commenter, boolean escape) { + if (!(commenter instanceof EscapingCommenter)) return range; + RangeMarker marker = myDocument.createRangeMarker(range); + if (escape) { + ((EscapingCommenter)commenter).escape(myDocument, range); + } + else { + ((EscapingCommenter)commenter).unescape(myDocument, range); + } + return TextRange.create(marker.getStartOffset(), marker.getEndOffset()); } private static int getNearest(String text, String pattern, int position) { @@ -641,6 +654,7 @@ public class CommentByBlockCommentHandler extends MultiCaretCodeInsightActionHan return; } + RangeMarker marker = myDocument.createRangeMarker(range); String text = myDocument.getCharsSequence().subSequence(range.getStartOffset(), range.getEndOffset()).toString(); int startOffset = range.getStartOffset(); //boolean endsProperly = CharArrayUtil.regionMatches(chars, range.getEndOffset() - commentSuffix.length(), commentSuffix); @@ -670,5 +684,7 @@ public class CommentByBlockCommentHandler extends MultiCaretCodeInsightActionHan commenter); } } + + processDocument(TextRange.create(marker.getStartOffset(), marker.getEndOffset()), commenter, false); } } diff --git a/xml/xml-psi-impl/src/com/intellij/lang/xml/XmlCommenter.java b/platform/lang-impl/src/com/intellij/codeInsight/generation/EscapingCommenter.java similarity index 55% rename from xml/xml-psi-impl/src/com/intellij/lang/xml/XmlCommenter.java rename to platform/lang-impl/src/com/intellij/codeInsight/generation/EscapingCommenter.java index 461c58697676..c9116f624863 100644 --- a/xml/xml-psi-impl/src/com/intellij/lang/xml/XmlCommenter.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/generation/EscapingCommenter.java @@ -13,37 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.lang.xml; +package com.intellij.codeInsight.generation; import com.intellij.lang.Commenter; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.util.TextRange; /** - * @author max + * @author Dmitry Avdeev */ -public class XmlCommenter implements Commenter { +public interface EscapingCommenter extends Commenter { - @Override - public String getLineCommentPrefix() { - return null; - } + void escape(Document document, TextRange range); - @Override - public String getBlockCommentPrefix() { - return ""; - } - - @Override - public String getCommentedBlockCommentPrefix() { - return "<!–"; - } - - @Override - public String getCommentedBlockCommentSuffix() { - return "–>"; - } + void unescape(Document document, TextRange range); } diff --git a/xml/impl/src/com/intellij/lang/xml/XmlCommenter.java b/xml/impl/src/com/intellij/lang/xml/XmlCommenter.java new file mode 100644 index 000000000000..e33e09111fa5 --- /dev/null +++ b/xml/impl/src/com/intellij/lang/xml/XmlCommenter.java @@ -0,0 +1,79 @@ +/* + * Copyright 2000-2014 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.lang.xml; + +import com.intellij.codeInsight.generation.EscapingCommenter; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.util.TextRange; +import com.intellij.util.text.CharArrayUtil; +import org.jetbrains.annotations.NotNull; + +/** + * @author max + */ +public class XmlCommenter implements EscapingCommenter { + + private static final String DOUBLE_DASH = "--"; + private static final String ESCAPED = "--"; + + @Override + public String getLineCommentPrefix() { + return null; + } + + @NotNull + @Override + public String getBlockCommentPrefix() { + return ""; + } + + @Override + public String getCommentedBlockCommentPrefix() { + return "<!–"; + } + + @Override + public String getCommentedBlockCommentSuffix() { + return "–>"; + } + + @Override + public void escape(Document document, TextRange range) { + for (int i = range.getEndOffset() - getBlockCommentSuffix().length() - DOUBLE_DASH.length(); + i >= range.getStartOffset() + getBlockCommentPrefix().length(); + i--) { + if (CharArrayUtil.regionMatches(document.getCharsSequence(), i, DOUBLE_DASH) && + !CharArrayUtil.regionMatches(document.getCharsSequence(), i, getBlockCommentSuffix())) { + document.replaceString(i, i + DOUBLE_DASH.length(), ESCAPED); + } + } + } + + @Override + public void unescape(Document document, TextRange range) { + for (int i = range.getEndOffset(); i >= range.getStartOffset(); i--) { + if (CharArrayUtil.regionMatches(document.getCharsSequence(), i, ESCAPED)) { + document.replaceString(i, i + ESCAPED.length(), DOUBLE_DASH); + } + } + } +}