IDEA-51739
[fedora-idea.git] / platform / platform-impl / src / com / intellij / openapi / editor / impl / RangeIterator.java
blob9837464fbb81cf049c9351bdba03998033342904
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.openapi.editor.impl;
18 import com.intellij.openapi.diagnostic.Logger;
19 import com.intellij.openapi.editor.FoldingModel;
20 import com.intellij.openapi.editor.highlighter.HighlighterIterator;
21 import com.intellij.openapi.editor.markup.TextAttributes;
22 import com.intellij.openapi.util.Condition;
23 import com.intellij.openapi.util.TextRange;
24 import gnu.trove.Equality;
26 class RangeIterator {
27 private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.editor.impl.RangeIterator");
28 private static final int NO_NEXT = -1;
29 private int myRangeEnd;
31 public interface Gaps {
32 boolean isGapAt(int offset);
35 private final HighlighterIterator mySource;
36 private final Equality<TextAttributes> myEquality;
37 private final Gaps myGaps;
38 private final Condition<TextAttributes> myFilter;
39 private boolean mySourceOutOfRange = false;
41 private int myStart;
42 private int myEnd;
43 private TextAttributes myTextAttributes;
44 private int myNextExpanded;
46 public RangeIterator(Gaps foldingModel, Equality<TextAttributes> equality,
47 HighlighterIterator source, Condition<TextAttributes> filter) {
48 mySource = source;
49 myGaps = foldingModel;
50 myEquality = equality;
51 myFilter = filter;
54 public void init(TextRange range) {
55 int rangeStart = range.getStartOffset();
56 myRangeEnd = range.getEndOffset();
57 while(!mySource.atEnd()) {
58 boolean sourceBeforeRange = rangeStart > mySource.getEnd();
59 if (!sourceBeforeRange) break;
60 mySource.advance();
62 while (!mySource.atEnd() && !checkOutOfRange()) {
63 if (myFilter.value(mySource.getTextAttributes())) break;
64 mySource.advance();
67 if (mySource.atEnd() || mySourceOutOfRange) myNextExpanded = NO_NEXT;
68 else {
69 myNextExpanded = findExpanded(mySource.getStart());
70 if (myNextExpanded == NO_NEXT) myStart = NO_NEXT;
74 private boolean checkOutOfRange() {
75 if (mySourceOutOfRange) return true;
76 mySourceOutOfRange = mySource.getStart() > myRangeEnd;
77 return mySourceOutOfRange;
80 private void doAdvanceFrom(int start) {
81 myStart = start;
82 myEnd = myStart;
83 doAdvance();
84 if (mySource.atEnd()) myNextExpanded = NO_NEXT;
85 else myNextExpanded = findExpanded(Math.max(myEnd, mySource.getStart()));
88 private void doAdvance() {
89 myStart = findExpanded(myStart);
90 myEnd = findFolding(myStart, mySource.getEnd(), true);
91 myTextAttributes = mySource.getTextAttributes();
92 while (myEnd == mySource.getEnd()) {
93 if (!advanceSource()) return;
94 if (mySource.getStart() != myEnd) return;
95 if (!myEquality.equals(myTextAttributes, mySource.getTextAttributes())) return;
96 myEnd = findFolding(myEnd, mySource.getEnd(), true);
100 private boolean advanceSource() {
101 if (mySource.atEnd()) return false;
102 do {
103 mySource.advance();
104 } while (!(mySource.atEnd() || checkOutOfRange() || myFilter.value(mySource.getTextAttributes())));
105 return !mySource.atEnd();
108 private int findExpanded(int start) {
109 start = findFolding(start, mySource.getEnd(), false);
110 while (start == mySource.getEnd()) {
111 if (!advanceSource()) return NO_NEXT;
112 start = findFolding(mySource.getStart(), mySource.getEnd(), false);
114 return start;
117 private int findFolding(int start, int end, boolean collapsed) {
118 int position = start;
119 while (position < end) {
120 if (myGaps.isGapAt(position) == collapsed) break;
121 else position++;
123 return position;
126 public int getStart() {
127 return myStart;
130 public int getEnd() {
131 return myEnd;
134 public TextAttributes getTextAttributes() {
135 LOG.assertTrue(myFilter.value(myTextAttributes));
136 return myTextAttributes;
139 public void advance() {
140 doAdvanceFrom(myNextExpanded);
143 public boolean atEnd() {
144 return myStart == NO_NEXT || mySourceOutOfRange ||
145 (mySource.atEnd() && (myNextExpanded == NO_NEXT ||
146 myNextExpanded == mySource.getEnd()));
149 public static class FoldingGaps implements Gaps {
150 private final FoldingModel myFoldingModel;
152 public FoldingGaps(FoldingModel foldingModel) {
153 myFoldingModel = foldingModel;
156 public boolean isGapAt(int offset) {
157 return myFoldingModel.isOffsetCollapsed(offset);