/*
* @(#)JavaDocument.java 1.2 98/05/04
*
* Copyright (c) 1998 Sun Microsystems, Inc. All Rights Reserved.
*
* This software is the confidential and proprietary information of Sun
* Microsystems, Inc. ("Confidential Information"). You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Sun.
*
* SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
* SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
* SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
* THIS SOFTWARE OR ITS DERIVATIVES.
*
*/
package examples.javakit;
import java.io.*;
import java.util.Vector;
import java.awt.Color;
import com.sun.java.swing.event.*;
import com.sun.java.swing.text.*;
/**
* A document to represent text in the form of the
* java programming language. This is quite primitive
* in that it simply provides support for lexically
* analyzing the text.
*
* @author Timothy Prinzing
* @version 1.2 05/04/98
*/
public class JavaDocument extends PlainDocument {
public JavaDocument() {
super(new GapContent(1024));
}
/**
* Create a lexical analyzer for this document.
*/
public Scanner createScanner() {
Scanner s;
try {
s = new Scanner();
} catch (IOException e) {
s = null;
}
return s;
}
/**
* Fetch a reasonable location to start scanning
* given the desired start location. This allows
* for adjustments needed to accomodate multiline
* comments.
*/
public int getScannerStart(int p) {
Element elem = getDefaultRootElement();
int lineNum = elem.getElementIndex(p);
Element line = elem.getElement(lineNum);
AttributeSet a = line.getAttributes();
while (a.isDefined(CommentAttribute) && lineNum > 0) {
lineNum -= 1;
line = elem.getElement(lineNum);
a = line.getAttributes();
}
return line.getStartOffset();
}
// --- AbstractDocument methods ----------------------------
/**
* Updates document structure as a result of text insertion. This
* will happen within a write lock. The superclass behavior of
* updating the line map is executed followed by marking any comment
* areas that should backtracked before scanning.
*
* @param chng the change event
* @param attr the set of attributes
*/
protected void insertUpdate(DefaultDocumentEvent chng, AttributeSet attr) {
super.insertUpdate(chng, attr);
// update comment marks
Element root = getDefaultRootElement();
DocumentEvent.ElementChange ec = chng.getChange(root);
if (ec != null) {
Element[] added = ec.getChildrenAdded();
boolean inComment = false;
for (int i = 0; i < added.length; i++) {
Element elem = added[i];
int p0 = elem.getStartOffset();
int p1 = elem.getEndOffset();
String s;
try {
s = getText(p0, p1 - p0);
} catch (BadLocationException bl) {
s = null;
}
if (inComment) {
MutableAttributeSet a = (MutableAttributeSet) elem.getAttributes();
a.addAttribute(CommentAttribute, CommentAttribute);
int index = s.indexOf("*/");
if (index >= 0) {
// found an end of comment, turn off marks
inComment = false;
}
} else {
// scan for multiline comment
int index = s.indexOf("/*");
if (index >= 0) {
// found a start of comment, see if it spans lines
index = s.indexOf("*/", index);
if (index < 0) {
// it spans lines
inComment = true;
}
}
}
}
}
}
/**
* Updates any document structure as a result of text removal.
* This will happen within a write lock. The superclass behavior of
* updating the line map is executed followed by placing a lexical
* update command on the analyzer queue.
*
* @param chng the change event
*/
protected void removeUpdate(DefaultDocumentEvent chng) {
super.removeUpdate(chng);
// update comment marks
}
// --- variables ------------------------------------------------
/**
* Key to be used in AttributeSet's holding a value of Token.
*/
static final Object CommentAttribute = new AttributeKey();
static class AttributeKey {
private AttributeKey() {
}
public String toString() {
return "comment";
}
}
public class Scanner extends sun.tools.java.Scanner {
Scanner() throws IOException {
super(new LocalEnvironment(), new DocumentInputStream(0, getLength()));
scanComments = true;
}
/**
* Sets the range of the scanner. This should be called
* to reinitialize the scanner to the desired range of
* coverage.
*/
public void setRange(int p0, int p1) throws IOException {
useInputStream(new DocumentInputStream(p0, p1));
this.p0 = p0;
}
/**
* This fetches the starting location of the current
* token in the document.
*/
public final int getStartOffset() {
int begOffs = (int) (pos & MAXFILESIZE);
return p0 + begOffs;
}
/**
* This fetches the ending location of the current
* token in the document.
*/
public final int getEndOffset() {
int endOffs = (int) (getEndPos() & MAXFILESIZE);
return p0 + endOffs;
}
int p0;
}
/**
* Class to provide InputStream functionality from a portion of a
* Document. This really should be a Reader, but not enough
* things use it yet.
*/
class DocumentInputStream extends InputStream {
public DocumentInputStream(int p0, int p1) {
this.segment = new Segment();
this.p0 = p0;
this.p1 = Math.min(getLength(), p1);
pos = p0;
try {
loadSegment();
} catch (IOException ioe) {
throw new Error("unexpected: " + ioe);
}
}
/**
* Reads the next byte of data from this input stream. The value
* byte is returned as an int in the range
* 0 to 255. If no byte is available
* because the end of the stream has been reached, the value
* -1 is returned. This method blocks until input data
* is available, the end of the stream is detected, or an exception
* is thrown.
*
* A subclass must provide an implementation of this method.
*
* @return the next byte of data, or -1 if the end of the
* stream is reached.
* @exception IOException if an I/O error occurs.
* @since JDK1.0
*/
public int read() throws IOException {
if (index >= segment.offset + segment.count) {
if (pos >= p1) {
// no more data
return -1;
}
loadSegment();
}
return segment.array[index++];
}
void loadSegment() throws IOException {
try {
int n = Math.min(1024, p1 - pos);
getText(pos, n, segment);
pos += n;
index = segment.offset;
} catch (BadLocationException e) {
throw new IOException("Bad location");
}
}
Segment segment;
int p0; // start position
int p1; // end position
int pos; // pos in document
int index; // index into array of the segment
}
static class LocalEnvironment extends sun.tools.java.Environment {
public void error(Object source, int where, String err,
Object arg1, Object arg2, Object arg3) {
// should do something useful...
System.err.println(err);
System.err.println("location: " + where);
}
}
}