blob: 16239d4b2acee3c76c4e9d7bd07e1d65e20d14ff [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.netbeans.editor;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import javax.swing.text.BadLocationException;
import javax.swing.text.Segment;
/**
* Encapsulation of a special static segment used
* by syntax scanners. Unfortunately document cache cannot
* guarantee that its fragment(s) will hold more than one character
* at the time so syntax scanning cannot be done by finder. Instead
* all the syntax analyzes are done over the syntax segment's data.
* Although it's shared across all instances of editors
* the loads into it should be fast as they are done from cache fragments
* by arraycopy() method.
* The syntax segment is separated into the slots because there
* can be more scanning necessary at one time.
* All the scanning must be done
*
* @author Miloslav Metelka
* @version 1.00
*/
class SyntaxSeg extends Segment {
private static final char[] EMPTY_CHAR_ARRAY = new char[0];
private static final int MAX_SLOT_COUNT = 100;
private static final int REALLOC_INCREMENT = 2048;
private static ArrayList slotList = new ArrayList();
static synchronized Slot getFreeSlot() {
int cnt = slotList.size();
return (cnt > 0) ? (Slot)slotList.remove(cnt - 1) : new Slot();
}
static synchronized void releaseSlot(Slot slot) {
slotList.add(slot);
}
/** From this position on, the data in syntax segment must be marked
* invalid.
*/
static synchronized void invalidate(BaseDocument doc, int pos) {
int cnt = slotList.size();
for (int i = 0; i < cnt; i++) {
((Slot)slotList.get(i)).invalidate(doc, pos);
}
}
static class Slot extends Segment {
/** Document from which the data in syntax segment come from */
WeakReference segDocRef = new WeakReference(null);
/** Begining of valid data in syntax segment */
int segPos;
/** Begining of valid data in syntax segment */
int segLen;
Slot() {
this.array = EMPTY_CHAR_ARRAY;
}
/** Load the syntax segment if necessary from some location in some
* document. For best performance there's no pos or len correctness
* checking. Therefore caller must guarantee the correctness.
* @return real length that was loaded (syntax segment has limitation
* in size)
*/
int load(BaseDocument doc, int pos, int len)
throws BadLocationException {
if (len <= 0) {
if (len == 0) {
count = 0;
return 0;
}
throw new RuntimeException("len=" + len); // Critical error NOI18N
}
BaseDocument segDoc = (BaseDocument)segDocRef.get();
boolean difDoc = (doc != segDoc);
if (difDoc) {
segDoc = doc;
segDocRef = new WeakReference(segDoc);
}
if (difDoc // different documents
|| pos < segPos // position too low
|| pos > segPos + segLen // position too high
|| pos - segPos + len > array.length
) { // wouldn't fit
// possibly realloc the array
if (len > array.length) {
char tmp[] = new char[len + REALLOC_INCREMENT];
array = tmp; // original data are not recopied
}
segPos = pos;
segLen = len;
doc.getChars(pos, array, 0, len); // read chars into array
} else { // inside array and will fit
int endSegPos = segPos + segLen;
int restLen = pos + len - endSegPos;
if (restLen > 0) { // not fully inside
doc.getChars(endSegPos, array, segLen, restLen);
segLen += restLen;
}
}
offset = pos - segPos;
count = len;
if (offset < 0 || len < 0) {
throw new BadLocationException("pos=" + pos + ", offset=" + offset // NOI18N
+ "len=" + len, offset); // Critical error NOI18N
}
return len;
}
/** Is the area inside the segment? */
boolean isAreaInside(BaseDocument doc, int pos, int len) {
return (doc == (BaseDocument)segDocRef.get()
&& pos >= segPos && pos + len <= segPos + segLen);
}
/** Invalidate the slot if it contains the data from the given document.
* @param doc document in which the change occured
* @param pos position in the document where the change occured
*/
void invalidate(BaseDocument doc, int pos) {
if (doc == (BaseDocument)segDocRef.get()) {
if (pos < segPos) {
segLen = 0;
} else if (pos < segPos + segLen) {
segLen = pos - segPos;
}
}
}
}
}