All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.netbeans.editor.SyntaxSeg Maven / Gradle / Ivy

/*
 * 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;
                }
            }
        }

    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy