1 package com
.intellij
.openapi
.editor
.impl
;
3 import com
.intellij
.openapi
.diagnostic
.Logger
;
4 import com
.intellij
.openapi
.editor
.FoldingModel
;
5 import com
.intellij
.openapi
.editor
.highlighter
.HighlighterIterator
;
6 import com
.intellij
.openapi
.editor
.markup
.TextAttributes
;
7 import com
.intellij
.openapi
.util
.Condition
;
8 import com
.intellij
.openapi
.util
.TextRange
;
9 import gnu
.trove
.Equality
;
12 private static final Logger LOG
= Logger
.getInstance("#com.intellij.openapi.editor.impl.RangeIterator");
13 private static final int NO_NEXT
= -1;
14 private int myRangeEnd
;
16 public interface Gaps
{
17 boolean isGapAt(int offset
);
20 private final HighlighterIterator mySource
;
21 private final Equality
<TextAttributes
> myEquality
;
22 private final Gaps myGaps
;
23 private final Condition
<TextAttributes
> myFilter
;
24 private boolean mySourceOutOfRange
= false;
28 private TextAttributes myTextAttributes
;
29 private int myNextExpanded
;
31 public RangeIterator(Gaps foldingModel
, Equality
<TextAttributes
> equality
,
32 HighlighterIterator source
, Condition
<TextAttributes
> filter
) {
34 myGaps
= foldingModel
;
35 myEquality
= equality
;
39 public void init(TextRange range
) {
40 int rangeStart
= range
.getStartOffset();
41 myRangeEnd
= range
.getEndOffset();
42 while(!mySource
.atEnd()) {
43 boolean sourceBeforeRange
= rangeStart
> mySource
.getEnd();
44 if (!sourceBeforeRange
) break;
47 while (!mySource
.atEnd() && !checkOutOfRange()) {
48 if (myFilter
.value(mySource
.getTextAttributes())) break;
52 if (mySource
.atEnd() || mySourceOutOfRange
) myNextExpanded
= NO_NEXT
;
54 myNextExpanded
= findExpanded(mySource
.getStart());
55 if (myNextExpanded
== NO_NEXT
) myStart
= NO_NEXT
;
59 private boolean checkOutOfRange() {
60 if (mySourceOutOfRange
) return true;
61 mySourceOutOfRange
= mySource
.getStart() > myRangeEnd
;
62 return mySourceOutOfRange
;
65 private void doAdvanceFrom(int start
) {
69 if (mySource
.atEnd()) myNextExpanded
= NO_NEXT
;
70 else myNextExpanded
= findExpanded(Math
.max(myEnd
, mySource
.getStart()));
73 private void doAdvance() {
74 myStart
= findExpanded(myStart
);
75 myEnd
= findFolding(myStart
, mySource
.getEnd(), true);
76 myTextAttributes
= mySource
.getTextAttributes();
77 while (myEnd
== mySource
.getEnd()) {
78 if (!advanceSource()) return;
79 if (mySource
.getStart() != myEnd
) return;
80 if (!myEquality
.equals(myTextAttributes
, mySource
.getTextAttributes())) return;
81 myEnd
= findFolding(myEnd
, mySource
.getEnd(), true);
85 private boolean advanceSource() {
86 if (mySource
.atEnd()) return false;
89 } while (!(mySource
.atEnd() || checkOutOfRange() || myFilter
.value(mySource
.getTextAttributes())));
90 return !mySource
.atEnd();
93 private int findExpanded(int start
) {
94 start
= findFolding(start
, mySource
.getEnd(), false);
95 while (start
== mySource
.getEnd()) {
96 if (!advanceSource()) return NO_NEXT
;
97 start
= findFolding(mySource
.getStart(), mySource
.getEnd(), false);
102 private int findFolding(int start
, int end
, boolean collapsed
) {
103 int position
= start
;
104 while (position
< end
) {
105 if (myGaps
.isGapAt(position
) == collapsed
) break;
111 public int getStart() {
115 public int getEnd() {
119 public TextAttributes
getTextAttributes() {
120 LOG
.assertTrue(myFilter
.value(myTextAttributes
));
121 return myTextAttributes
;
124 public void advance() {
125 doAdvanceFrom(myNextExpanded
);
128 public boolean atEnd() {
129 return myStart
== NO_NEXT
|| mySourceOutOfRange
||
130 (mySource
.atEnd() && (myNextExpanded
== NO_NEXT
||
131 myNextExpanded
== mySource
.getEnd()));
134 public static class FoldingGaps
implements Gaps
{
135 private final FoldingModel myFoldingModel
;
137 public FoldingGaps(FoldingModel foldingModel
) {
138 myFoldingModel
= foldingModel
;
141 public boolean isGapAt(int offset
) {
142 return myFoldingModel
.isOffsetCollapsed(offset
);