diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ContentsLines.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ContentsLines.java new file mode 100644 index 000000000000..768bb0788e6b --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ContentsLines.java @@ -0,0 +1,80 @@ +/* + * Copyright 2000-2011 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.openapi.vcs.actions; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.text.StringUtil; + +import java.util.ArrayList; +import java.util.List; + +/** +* @author irengrig +* Date: 4/27/11 +* Time: 3:42 PM +*/ +public class ContentsLines { + private final static Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.actions.ContentsLines"); + + private final SplittingIterator mySplittingIterator; + private final List myLinesStartOffsets; + private final String myContents; + private boolean myLineEndsFinished; + + public ContentsLines(final String contents) { + myContents = contents; + mySplittingIterator = new SplittingIterator(contents); + myLinesStartOffsets = new ArrayList(); + } + + public String getLineContents(final int number) { + assert !myLineEndsFinished || myLinesStartOffsets.size() > number; + + // we need to know end + if (myLineEndsFinished || (myLinesStartOffsets.size() > (number + 1))) { + return extractCalculated(number); + } + while (((myLinesStartOffsets.size() - 1) < (number + 1)) && (!myLineEndsFinished) && mySplittingIterator.hasNext()) { + final Integer nextStart = mySplittingIterator.next(); + myLinesStartOffsets.add(nextStart); + } + myLineEndsFinished = myLinesStartOffsets.size() < (number + 1); + return extractCalculated(number); + } + + private String extractCalculated(int number) { + try { + String text = myContents.substring(myLinesStartOffsets.get(number), + (number + 1 >= myLinesStartOffsets.size()) + ? myContents.length() + : myLinesStartOffsets.get(number + 1)); + text = text.endsWith("\r\n") ? text.substring(0, text.length() - 2) : text; + text = (text.endsWith("\r") || text.endsWith("\n")) ? text.substring(0, text.length() - 1) : text; + return text; + } catch (IndexOutOfBoundsException e) { + LOG.error("Loaded contents lines: " + StringUtil.getLineBreakCount(myContents), e); + throw e; + } + } + + public boolean isLineEndsFinished() { + return myLineEndsFinished; + } + + public int getKnownLinesNumber() { + return myLineEndsFinished ? myLinesStartOffsets.size() : -1; + } +} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ShowDiffFromAnnotation.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ShowDiffFromAnnotation.java index d506a54ebd0d..49915e6f9e1b 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ShowDiffFromAnnotation.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ShowDiffFromAnnotation.java @@ -42,10 +42,7 @@ import com.intellij.util.containers.CacheOneStepIterator; import org.jetbrains.annotations.NotNull; import java.io.File; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; +import java.util.*; /** * @author Konstantin Bulenkov @@ -162,7 +159,7 @@ class ShowDiffFromAnnotation extends AnAction implements LineNumberListener { // for current line number private DiffNavigationContext createDiffNavigationContext(final int actualLine) { - final MyContentsLines contentsLines = new MyContentsLines(myFileAnnotation.getAnnotatedContent()); + final ContentsLines contentsLines = new ContentsLines(myFileAnnotation.getAnnotatedContent()); final Pair pair = correctActualLineIfTextEmpty(contentsLines, actualLine); return new DiffNavigationContext(new Iterable() { @@ -175,7 +172,7 @@ class ShowDiffFromAnnotation extends AnAction implements LineNumberListener { private final static int ourVicinity = 5; - private Pair correctActualLineIfTextEmpty(final MyContentsLines contentsLines, final int actualLine) { + private Pair correctActualLineIfTextEmpty(final ContentsLines contentsLines, final int actualLine) { final VcsRevisionNumber revision = myFileAnnotation.getLineRevisionNumber(actualLine); for (int i = actualLine; (i < (actualLine + ourVicinity)) && (!contentsLines.isLineEndsFinished()); i++) { @@ -196,105 +193,11 @@ class ShowDiffFromAnnotation extends AnAction implements LineNumberListener { return new Pair(actualLine, contentsLines.getLineContents(actualLine)); } - private static class MySplittingIterator implements Iterator { - private final String myContents; - // always at the beginning of the _next_ line - private int myOffset; - - private MySplittingIterator(final String contents) { - myContents = contents; - myOffset = 0; - } - - @Override - public boolean hasNext() { - return myOffset < myContents.length(); - } - - @Override - public Integer next() { - final int start = myOffset; - while (myOffset < myContents.length()) { - // \r, \n, or \r\n - final char c = myContents.charAt(myOffset); - if ('\n' == c) { - ++myOffset; - break; - } - else if ('\r' == c) { - if (myOffset + 1 == myContents.length()) { - // at the end - ++myOffset; - break; - } - else { - myOffset += (('\n' == myContents.charAt(myOffset + 1)) ? 2 : 1); - break; - } - } - ++myOffset; - } - - return start; - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - } - - private static class MyContentsLines { - private final MySplittingIterator mySplittingIterator; - private final List myLinesStartOffsets; - private final String myContents; - private boolean myLineEndsFinished; - - private MyContentsLines(final String contents) { - myContents = contents; - mySplittingIterator = new MySplittingIterator(contents); - myLinesStartOffsets = new LinkedList(); - } - - public String getLineContents(final int number) { - assert !myLineEndsFinished || myLinesStartOffsets.size() > number; - - // we need to know end - if (myLineEndsFinished || (myLinesStartOffsets.size() > (number + 1))) { - return extractCalculated(number); - } - while (((myLinesStartOffsets.size() - 1) < (number + 1)) && (!myLineEndsFinished) && mySplittingIterator.hasNext()) { - final Integer nextStart = mySplittingIterator.next(); - myLinesStartOffsets.add(nextStart); - } - myLineEndsFinished = myLinesStartOffsets.size() < (number + 1); - return extractCalculated(number); - } - - private String extractCalculated(int number) { - String text = myContents.substring(myLinesStartOffsets.get(number), - (number + 1 >= myLinesStartOffsets.size()) - ? myContents.length() - : myLinesStartOffsets.get(number + 1)); - text = text.endsWith("\r\n") ? text.substring(0, text.length() - 2) : text; - text = (text.endsWith("\r") || text.endsWith("\n")) ? text.substring(0, text.length() - 1) : text; - return text; - } - - public boolean isLineEndsFinished() { - return myLineEndsFinished; - } - - public int getKnownLinesNumber() { - return myLineEndsFinished ? myLinesStartOffsets.size() : -1; - } - } - /** * Slightly break the contract: can return null from next() while had claimed hasNext() */ private static class ContextLineIterator implements Iterator { - private final MyContentsLines myContentsLines; + private final ContentsLines myContentsLines; private final VcsRevisionNumber myRevisionNumber; private final FileAnnotation myAnnotation; @@ -302,7 +205,7 @@ class ShowDiffFromAnnotation extends AnAction implements LineNumberListener { // we assume file has at least one line ;) private int myCurrentLine; // to start looking for next line with revision from - private ContextLineIterator(final MyContentsLines contentLines, final FileAnnotation annotation, final int stopAtLine) { + private ContextLineIterator(final ContentsLines contentLines, final FileAnnotation annotation, final int stopAtLine) { myAnnotation = annotation; myRevisionNumber = myAnnotation.originalRevision(stopAtLine); myStopAtLine = stopAtLine; diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/SplittingIterator.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/SplittingIterator.java new file mode 100644 index 000000000000..9ecf86d23af4 --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/SplittingIterator.java @@ -0,0 +1,71 @@ +/* + * Copyright 2000-2011 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.openapi.vcs.actions; + +import java.util.Iterator; + +/** +* @author irengrig +* Date: 4/27/11 +* Time: 3:42 PM +*/ +public class SplittingIterator implements Iterator { + private final String myContents; + // always at the beginning of the _next_ line + private int myOffset; + + public SplittingIterator(final String contents) { + myContents = contents; + myOffset = 0; + } + + @Override + public boolean hasNext() { + return myOffset < myContents.length(); + } + + @Override + public Integer next() { + final int start = myOffset; + while (myOffset < myContents.length()) { + // \r, \n, or \r\n + final char c = myContents.charAt(myOffset); + if ('\n' == c) { + ++myOffset; + break; + } + else if ('\r' == c) { + if (myOffset + 1 == myContents.length()) { + // at the end + ++myOffset; + break; + } + else { + myOffset += (('\n' == myContents.charAt(myOffset + 1)) ? 2 : 1); + break; + } + } + ++myOffset; + } + + return start; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } +}