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
.event
.DocumentEvent
;
20 import com
.intellij
.openapi
.editor
.ex
.DocumentEx
;
21 import com
.intellij
.openapi
.editor
.ex
.RangeMarkerEx
;
22 import com
.intellij
.openapi
.util
.UserDataHolderBase
;
23 import org
.jetbrains
.annotations
.NonNls
;
24 import org
.jetbrains
.annotations
.NotNull
;
26 import java
.util
.concurrent
.atomic
.AtomicLong
;
28 public class RangeMarkerImpl
extends UserDataHolderBase
implements RangeMarkerEx
{
29 private static final Logger LOG
= Logger
.getInstance("#com.intellij.openapi.editor.impl.RangeMarkerImpl");
31 protected final DocumentEx myDocument
;
32 protected volatile int myStart
;
33 protected volatile int myEnd
;
34 private volatile boolean isValid
= true;
35 private boolean isExpandToLeft
= false;
36 private boolean isExpandToRight
= false;
38 private static final AtomicLong counter
= new AtomicLong();
39 private final long myId
;
40 private volatile int modCount
;
42 protected RangeMarkerImpl(@NotNull DocumentEx document
, int start
, int end
) {
44 throw new IllegalArgumentException("Wrong start: " + start
+"; end="+end
);
46 else if (end
> document
.getTextLength()) {
47 throw new IllegalArgumentException("Wrong end: " + end
+ "; document length="+document
.getTextLength()+"; start="+start
);
49 else if (start
> end
){
50 throw new IllegalArgumentException("start > end: start=" + start
+"; end="+end
);
53 myDocument
= document
;
56 myId
= counter
.getAndIncrement();
60 protected void registerInDocument() {
61 myDocument
.addRangeMarker(this);
68 public int getStartOffset() {
72 public int getEndOffset() {
76 public boolean isValid() {
80 public void invalidate() {
85 public DocumentEx
getDocument() {
89 public void setGreedyToLeft(boolean greedy
) {
90 isExpandToLeft
= greedy
;
93 public void setGreedyToRight(boolean greedy
) {
94 isExpandToRight
= greedy
;
97 public boolean isGreedyToLeft() {
98 return isExpandToLeft
;
101 public boolean isGreedyToRight() {
102 return isExpandToRight
;
105 public final void documentChanged(DocumentEvent e
) {
106 int modCount
= this.modCount
++;
107 int oldStart
= myStart
;
109 int docLength
= myDocument
.getTextLength();
111 LOG
.error("Invalid range marker "+ (isExpandToLeft ?
"[" : "(") + oldStart
+ ", " + oldEnd
+ (isExpandToRight ?
"]" : ")") +
112 ". Event = " + e
+ ". Doc length=" + docLength
+ "; "+getClass());
115 if (myStart
> myEnd
|| myStart
< 0 || myEnd
> docLength
- e
.getNewLength() + e
.getOldLength()) {
116 LOG
.error("RangeMarker" + (isExpandToLeft ?
"[" : "(") + oldStart
+ ", " + oldEnd
+ (isExpandToRight ?
"]" : ")") +
117 " is invalid before update. Event = " + e
+ ". Doc length=" + docLength
+ "; "+getClass());
121 changedUpdateImpl(e
);
122 if (isValid
&& (myStart
> myEnd
|| myStart
< 0 || myEnd
> docLength
)) {
123 LOG
.error("RangeMarker" + (isExpandToLeft ?
"[" : "(") + oldStart
+ ", " + oldEnd
+ (isExpandToRight ?
"]" : ")") +
124 " update failed. Event = " + e
+ ". Result[" + myStart
+ ", " + myEnd
+ "], " +
125 "old doc length=" + docLength
+ "; real doc length = "+myDocument
.getTextLength()+
126 "; old mod count="+modCount
+"; mod count="+this.modCount
+
132 protected void changedUpdateImpl(DocumentEvent e
) {
133 if (!isValid
) return;
135 // Process if one point.
136 if (myStart
== myEnd
) {
137 processIfOnePoint(e
);
141 final int offset
= e
.getOffset();
142 final int oldLength
= e
.getOldLength();
143 final int newLength
= e
.getNewLength();
145 // changes after the end.
146 if (myEnd
< offset
|| !isExpandToRight
&& myEnd
== offset
) {
150 // changes before start
151 if (myStart
> offset
+ oldLength
|| !isExpandToLeft
&& myStart
== offset
+ oldLength
) {
152 myStart
+= newLength
- oldLength
;
153 myEnd
+= newLength
- oldLength
;
157 // Changes inside marker's area. Expand/collapse.
158 if (myStart
<= offset
&& myEnd
>= offset
+ oldLength
) {
159 myEnd
+= newLength
- oldLength
;
163 // At this point we either have (myStart xor myEnd inside changed area) or whole area changed.
165 // Replacing prefix or suffix...
166 if (myStart
>= offset
&& myStart
<= offset
+ oldLength
&& myEnd
> offset
+ oldLength
) {
167 myEnd
+= newLength
- oldLength
;
168 myStart
= offset
+ newLength
;
172 if (myEnd
>= offset
&& myEnd
<= offset
+ oldLength
&& myStart
< offset
) {
180 private void processIfOnePoint(DocumentEvent e
) {
181 int offset
= e
.getOffset();
182 int oldLength
= e
.getOldLength();
183 int oldEnd
= offset
+ oldLength
;
184 if (offset
< myStart
&& myStart
< oldEnd
) {
189 if (offset
== myStart
&& oldLength
== 0 && isExpandToRight
) {
190 myEnd
+= e
.getNewLength();
194 if (myStart
> oldEnd
|| myStart
== oldEnd
&& oldLength
> 0) {
195 myStart
+= e
.getNewLength() - oldLength
;
196 myEnd
+= e
.getNewLength() - oldLength
;
201 public String
toString() {
202 return "RangeMarker" + (isGreedyToLeft() ?
"[" : "(") + (isValid ?
"valid" : "invalid") + "," + getStartOffset() + "," + getEndOffset() + (
203 isGreedyToRight() ?
"]" : ")");