DocumentReader.java
/*
* This file is part of the programmer editor demo
* Copyright (C) 2001-2005 Stephen Ostermiller
* http://ostermiller.org/contact.pl?regarding=Syntax+Highlighting
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* See COPYING.TXT for details.
*/
package com.jsql.view.swing.sql.lexer;
import com.jsql.util.LogLevelUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javax.swing.text.AbstractDocument;
import javax.swing.text.BadLocationException;
import java.io.Reader;
/**
* A reader interface for an abstract document. Since
* the syntax highlighting packages only accept Stings and
* Readers, this must be used.
* Since the close() method does nothing and a seek() method
* has been added, this allows us to get some performance
* improvements through reuse. It can be used even after the
* lexer explicitly closes it by seeking to the place that
* we want to read next, and reseting the lexer.
*/
class DocumentReader extends Reader {
/**
* Log4j logger sent to view.
*/
private static final Logger LOGGER = LogManager.getRootLogger();
/**
* Current position in the document. Incremented
* whenever a character is read.
*/
private long position = 0;
/**
* Saved position used in the mark and reset methods.
*/
private long mark = -1;
/**
* The document that we are working with.
*/
private final AbstractDocument document;
/**
* Construct a reader on the given document.
*
* @param document the document to be read.
*/
public DocumentReader(AbstractDocument document) {
this.document = document;
}
/**
* Modifying the document while the reader is working is like
* pulling the rug out from under the reader. Alerting the
* reader with this method (in a nice thread safe way, this
* should not be called at the same time as a read) allows
* the reader to compensate.
*/
public void update(int position, int adjustment) {
if (position < this.position) {
if (this.position < position - adjustment) {
this.position = position;
} else {
this.position += adjustment;
}
}
}
/**
* Has no effect. This reader can be used even after
* it has been closed.
*/
@Override
public void close() {
// nothing
}
/**
* Save a position for reset.
*
* @param readAheadLimit ignored.
*/
@Override
public void mark(int readAheadLimit) {
this.mark = this.position;
}
/**
* This reader support mark and reset.
*
* @return true
*/
@Override
public boolean markSupported() {
return true;
}
/**
* Read a single character.
*
* @return the character or -1 if the end of the document has been reached.
*/
@Override
public int read() {
if (this.position < this.document.getLength()) {
try {
char c = this.document.getText((int)this.position, 1).charAt(0);
this.position++;
return c;
} catch (BadLocationException e) {
LOGGER.log(LogLevelUtil.IGNORE, e);
return -1;
}
} else {
return -1;
}
}
/**
* Read and fill the buffer.
* This method will always fill the buffer unless the end of the document is reached.
*
* @param cbuf the buffer to fill.
* @return the number of characters read or -1 if no more characters are available in the document.
*/
@Override
public int read(char[] cbuf) {
return this.read(cbuf, 0, cbuf.length);
}
/**
* Read and fill the buffer.
* This method will always fill the buffer unless the end of the document is reached.
*
* @param cbuf the buffer to fill.
* @param off offset into the buffer to begin the fill.
* @param len maximum number of characters to put in the buffer.
* @return the number of characters read or -1 if no more characters are available in the document.
*/
@Override
public int read(char[] cbuf, int off, int len) {
if (this.position < this.document.getLength()) {
int length = len;
if (this.position + length >= this.document.getLength()) {
length = this.document.getLength() - (int)this.position;
}
if (off + length >= cbuf.length) {
length = cbuf.length - off;
}
try {
String s = this.document.getText((int)this.position, length);
this.position += length;
for (int i=0; i<length; i++) {
cbuf[off+i] = s.charAt(i);
}
return length;
} catch (BadLocationException e) {
LOGGER.log(LogLevelUtil.IGNORE, e);
return -1;
}
} else {
return -1;
}
}
/**
* @return true
*/
@Override
public boolean ready() {
return true;
}
/**
* Reset this reader to the last mark, or the beginning of the document if a mark has not been set.
*/
@Override
public void reset() {
if (this.mark == -1) {
this.position = 0;
} else {
this.position = this.mark;
}
this.mark = -1;
}
/**
* Skip characters of input.
* This method will always skip the maximum number of characters unless
* the end of the file is reached.
*
* @param n number of characters to skip.
* @return the actual number of characters skipped.
*/
@Override
public long skip(long n) {
if (this.position + n <= this.document.getLength()) {
this.position += n;
return n;
} else {
long oldPos = this.position;
this.position = this.document.getLength();
return this.document.getLength() - oldPos;
}
}
/**
* Seek to the given position in the document.
*
* @param n the offset to which to seek.
*/
public void seek(long n) {
if (n <= this.document.getLength()) {
this.position = n;
} else {
this.position = this.document.getLength();
}
}
}