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
;
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;
43 private TextAttributes myTextAttributes
;
44 private int myNextExpanded
;
46 public RangeIterator(Gaps foldingModel
, Equality
<TextAttributes
> equality
,
47 HighlighterIterator source
, Condition
<TextAttributes
> filter
) {
49 myGaps
= foldingModel
;
50 myEquality
= equality
;
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;
62 while (!mySource
.atEnd() && !checkOutOfRange()) {
63 if (myFilter
.value(mySource
.getTextAttributes())) break;
67 if (mySource
.atEnd() || mySourceOutOfRange
) myNextExpanded
= NO_NEXT
;
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
) {
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;
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);
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;
126 public int getStart() {
130 public int getEnd() {
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
);