Update of /cvsroot/squirrel-sql/mavenize/thirdparty-non-maven/ostermiller-syntax/src/main/java/com/Ostermiller/Syntax
In directory sfp-cvsdas-3.v30.ch3.sourceforge.com:/tmp/cvs-serv32334/thirdparty-non-maven/ostermiller-syntax/src/main/java/com/Ostermiller/Syntax
Added Files:
Colorer.java ToHTMLAntTask.java TokenStyles.java ToHTML.java
ProgrammerEditorDemo.java DocPosition.java
DocPositionComparator.java HighlightedDocument.java
DocumentReader.java
Log Message:
Source for thirdparty dependency. Maven central requires a valid source code repository for artifacts that it hosts. This project has none, so we host it here for the time being.
--- NEW FILE: ToHTML.java ---
/*
* This file is part of a syntax highlighting package
* Copyright (C) 1999-2002 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.Ostermiller.Syntax;
[...1294 lines suppressed...]
break;
}
}
}
}
/**
* Write the string after escaping characters that would hinder
* it from rendering in html.
* <P>
* Conversions between characters and bytes will be done
* using the default character set for the system.
*
* @param text The string to be escaped and written
* @param out output gets written here
*/
public static void writeEscapedHTML(String text, PrintStream out){
writeEscapedHTML(text, new PrintWriter(out));
}
}
--- NEW FILE: DocPosition.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.Ostermiller.Syntax;
/**
* A wrapper for a position in a document appropriate for storing
* in a collection.
*/
class DocPosition {
/**
* The actual position
*/
private int position;
/**
* Get the position represented by this DocPosition
*
* @return the position
*/
int getPosition(){
return position;
}
/**
* Construct a DocPosition from the given offset into the document.
*
* @param position The position this DocObject will represent
*/
public DocPosition(int position){
this.position = position;
}
/**
* Adjust this position.
* This is useful in cases that an amount of text is inserted
* or removed before this position.
*
* @param adjustment amount (either positive or negative) to adjust this position.
* @return the DocPosition, adjusted properly.
*/
public DocPosition adjustPosition(int adjustment){
position += adjustment;
return this;
}
/**
* Two DocPositions are equal iff they have the same internal position.
*
* @return if this DocPosition represents the same position as another.
*/
public boolean equals(Object obj){
if (obj instanceof DocPosition){
DocPosition d = (DocPosition)(obj);
if (this.position == d.position){
return true;
} else {
return false;
}
} else {
return false;
}
}
/**
* A string representation useful for debugging.
*
* @return A string representing the position.
*/
public String toString(){
return "" + position;
}
}
--- NEW FILE: HighlightedDocument.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.Ostermiller.Syntax;
import javax.swing.text.*;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import com.Ostermiller.Syntax.Lexer.*;
/**
* A <a href="http://ostermiller.org/syntax/editor.html">demonstration text
* editor</a> that uses syntax highlighting.
*/
public class HighlightedDocument extends DefaultStyledDocument {
public static final Object C_STYLE = CLexer.class;
public static final Object HTML_STYLE = HTMLLexer.class;
public static final Object HTML_KEY_STYLE = HTMLLexer1.class;
public static final Object JAVA_STYLE = JavaLexer.class;
public static final Object JAVASCRIPT_STYLE = JavaScriptLexer.class;
public static final Object LATEX_STYLE = LatexLexer.class;
public static final Object PLAIN_STYLE = PlainLexer.class;
public static final Object PROPERTIES_STYLE = PropertiesLexer.class;
public static final Object SQL_STYLE = SQLLexer.class;
public static final Object GRAYED_OUT_STYLE = new Object();
/**
* A reader wrapped around the document so that the document can be fed into
* the lexer.
*/
private DocumentReader documentReader;
/** If non-null, all is drawn with this style (no lexing). */
private AttributeSet globalStyle = null;
/**
* The lexer that tells us what colors different words should be.
*/
private Lexer syntaxLexer;
/**
* A thread that handles the actual coloring.
*/
private Colorer colorer;
/**
* A lock for modifying the document, or for actions that depend on the
* document not being modified.
*/
private Object docLock = new Object();
/**
* Create a new Demo
*/
public HighlightedDocument() {
// Start the thread that does the coloring
colorer = new Colorer(this);
colorer.start();
// create the new document.
documentReader = new DocumentReader(this);
syntaxLexer = new JavaLexer(documentReader);
}
/**
* Color or recolor the entire document
*/
public void colorAll() {
color(0, getLength());
}
/**
* Color a section of the document. The actual coloring will start somewhere
* before the requested position and continue as long as needed.
*
* @param position
* the starting point for the coloring.
* @param adjustment
* amount of text inserted or removed at the starting point.
*/
public void color(int position, int adjustment) {
colorer.color(position, adjustment);
}
public void setGlobalStyle(AttributeSet value) {
globalStyle = value;
colorAll();
}
public void setHighlightStyle(Object value) {
if (value == HighlightedDocument.GRAYED_OUT_STYLE) {
setGlobalStyle(TokenStyles.getStyle("grayedOut"));
return;
}
if (!(value instanceof Class))
value = HighlightedDocument.PLAIN_STYLE;
Class source = (Class) value;
Class[] parms = { Reader.class };
Object[] args = { documentReader };
try {
Constructor cons = source.getConstructor(parms);
syntaxLexer = (Lexer) cons.newInstance(args);
globalStyle = null;
colorAll();
} catch (SecurityException e) {
System.err.println("HighlightEditor.SecurityException");
} catch (NoSuchMethodException e) {
System.err.println("HighlightEditor.NoSuchMethod");
} catch (InstantiationException e) {
System.err.println("HighlightEditor.InstantiationException");
} catch (InvocationTargetException e) {
System.err.println("HighlightEditor.InvocationTargetException");
} catch (IllegalAccessException e) {
System.err.println("HighlightEditor.IllegalAccessException");
}
}
//
// Intercept inserts and removes to color them.
//
public void insertString(int offs, String str, AttributeSet a)
throws BadLocationException {
synchronized (docLock) {
super.insertString(offs, str, a);
color(offs, str.length());
documentReader.update(offs, str.length());
}
}
public void remove(int offs, int len) throws BadLocationException {
synchronized (docLock) {
super.remove(offs, len);
color(offs, -len);
documentReader.update(offs, -len);
}
}
// methods for Colorer to retrieve information
DocumentReader getDocumentReader() { return documentReader; }
Object getDocumentLock() { return docLock; }
Lexer getSyntaxLexer() { return syntaxLexer; }
AttributeSet getGlobalStyle() { return globalStyle; }
}
--- NEW FILE: ToHTMLAntTask.java ---
/*
* This file is part of a syntax highlighting package
* Copyright (C) 2003 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.Ostermiller.Syntax;
import org.apache.tools.ant.taskdefs.*;
import org.apache.tools.ant.*;
import org.apache.tools.ant.util.*;
import org.apache.tools.ant.types.*;
import java.io.*;
import java.net.*;
public class ToHTMLAntTask extends MatchingTask {
/**
* The compiler that does to work for this task.
*/
private ToHTML toHTML = new ToHTML();
public ToHTMLAntTask(){
toHTML.setStyleSheet("syntax.css");
}
private File srcDir;
/**
* Set the source dir to find the source files.
*/
public void setSrcdir(File srcDir) {
this.srcDir = srcDir;
}
private File destDir = null;
/**
* Set the destination where the fixed files should be placed.
* Default is to replace the original file.
*/
public void setDestdir(File destDir) {
this.destDir = destDir;
}
/**
* Set the mime-type for files to be highlighted.
* text/html, text/x-java...
*/
public void setMime(String mime) {
toHTML.setMimeType(mime);
}
/**
* Java class name of the lexer to use.
*/
public void setLexer(String lexer) {
toHTML.setLexerType(lexer);
}
/**
* Use the given title in the html page.
*/
public void setTitle(String title) {
toHTML.setTitle(title);
}
/**
* BTE template to use. see: ostermiller.org/bte
*/
public void setTemplate(String template) throws MalformedURLException {
toHTML.setTemplate(new URL(getProject().getBaseDir().toURL(), template).toString());
}
/**
* Cascading Style Sheet to which html should be linked.
*/
public void setCSS(String css) {
toHTML.setStyleSheet(css);
}
public void addConfiguredParameter(Parameter param) throws BuildException {
if (param.getType().equals("ignore")){
if (param.getName() == null){
throw new BuildException("ignore parameter must have a name!");
}
if (param.getValue() != null){
throw new BuildException("ignore parameter does not take a value!");
}
toHTML.addIgnoreStyle(param.getName());
} else if (param.getType().equals("translate")){
if (param.getName() == null || param.getValue() == null){
throw new BuildException("translate parameter must have a name and value!");
}
toHTML.translateStyle(param.getName(), param.getValue());
} else {
throw new BuildException("unknown parameter type: " + param.getType());
}
}
/**
* Executes the task.
*/
public void execute() throws BuildException {
if (srcDir == null) {
srcDir = getProject().getBaseDir();
}
if (!srcDir.exists()) {
throw new BuildException("srcdir does not exist!");
}
if (!srcDir.isDirectory()) {
throw new BuildException("srcdir is not a directory!");
}
if (destDir == null) {
destDir = srcDir;
}
if (!destDir.exists()) {
throw new BuildException("destdir does not exist!");
}
if (!destDir.isDirectory()) {
throw new BuildException("destdir is not a directory!");
}
DirectoryScanner ds = super.getDirectoryScanner(srcDir);
String[] files = ds.getIncludedFiles();
SourceFileScanner sfs = new SourceFileScanner(this);
String[] newFiles = sfs.restrict(
files,
srcDir,
destDir,
new FileNameMapper(){
public void setFrom(String from){}
public void setTo(String to){}
public String[] mapFileName(String f){
return new String[]{f+".html"};
}
}
);
try {
if (newFiles.length > 0){
System.out.println("Applying syntax highlighting to " + newFiles.length + " files.");
}
for (int i = 0; i < newFiles.length; i++) {
File destFile = new File(destDir, newFiles[i]+".html");
File destParent = destFile.getParentFile();
if (destParent != null && !destParent.exists()){
if (!destParent.mkdirs()){
throw new BuildException("could not create directory: " + destParent);
}
}
toHTML.setInput(new FileReader(new File(srcDir, newFiles[i])));
toHTML.setOutput(new FileWriter(destFile));
toHTML.setDocNameFromFileName(newFiles[i]);
toHTML.setExtFromFileName(newFiles[i]);
toHTML.writeFullHTML();
}
} catch (Exception x){
throw new BuildException(x);
}
}
}
--- NEW FILE: DocPositionComparator.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.Ostermiller.Syntax;
import java.util.Comparator;
/**
* A comparator appropriate for use with Collections of
* DocPositions.
*/
class DocPositionComparator implements Comparator {
public static final DocPositionComparator instance = new DocPositionComparator();
private DocPositionComparator() { }
/**
* Does this Comparator equal another?
* Since all DocPositionComparators are the same, they
* are all equal.
*
* @return true for DocPositionComparators, false otherwise.
*/
public boolean equals(Object obj){
return this == obj;
}
/**
* Compare two DocPositions
*
* @param o1 first DocPosition
* @param o2 second DocPosition
* @return negative if first < second, 0 if equal, positive if first > second
*/
public int compare(Object o1, Object o2){
if (o1 instanceof DocPosition && o2 instanceof DocPosition){
DocPosition d1 = (DocPosition)(o1);
DocPosition d2 = (DocPosition)(o2);
return (d1.getPosition() - d2.getPosition());
} else if (o1 instanceof DocPosition){
return -1;
} else if (o2 instanceof DocPosition){
return 1;
} else if (o1.hashCode() < o2.hashCode()){
return -1;
} else if (o2.hashCode() > o1.hashCode()){
return 1;
} else {
return 0;
}
}
}
--- NEW FILE: ProgrammerEditorDemo.java ---
/*
* A simple text editor that demonstrates the integration of the
* com.Ostermiller.Syntax Syntax Highlighting package with a text editor.
* Copyright (C) 2001 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.Ostermiller.Syntax;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/**
* A <a href="http://ostermiller.org/syntax/editor.html">demonstration text editor</a>
* that uses syntax highlighting.
*/
public class ProgrammerEditorDemo extends JFrame {
/** The document holding the text being edited. */
private HighlightedDocument document = new HighlightedDocument();
/** The text pane displaying the document. */
private JTextPane textPane = new JTextPane(document);
/**
* Create a new Demo
*/
public ProgrammerEditorDemo() {
// initial set up that sets the title
super("Programmer's Editor Demonstration");
setLocation(50, 50);
// Create a scroll pane wrapped around the text pane
JScrollPane scrollPane = new JScrollPane(textPane);
scrollPane.setPreferredSize(new Dimension(620, 460));
// Add the components to the frame.
JPanel contentPane = new JPanel(new BorderLayout());
contentPane.add(scrollPane, BorderLayout.CENTER);
setContentPane(contentPane);
// Set up the menu bar.
JMenu styleMenu = createStyleMenu();
JMenuBar mb = new JMenuBar();
mb.add(styleMenu);
setJMenuBar(mb);
// Make the window so that it can close the application
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
public void windowActivated(WindowEvent e) {
// focus magic
textPane.requestFocus();
}
});
// Put the initial text into the text pane and
// set it's initial coloring style.
initDocument();
// put it all together and show it.
pack();
setVisible(true);
}
private class StyleMenuItem extends JRadioButtonMenuItem
implements ActionListener {
Object style;
StyleMenuItem(String name, Object style) {
super(name);
this.style = style;
addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
document.setHighlightStyle(style);
}
}
/**
* Create the style menu.
*
* @return the style menu.
*/
private JMenu createStyleMenu() {
JRadioButtonMenuItem[] items = {
new StyleMenuItem("Java", HighlightedDocument.JAVA_STYLE),
new StyleMenuItem("C/C++", HighlightedDocument.C_STYLE),
new StyleMenuItem("HTML (Simple)", HighlightedDocument.HTML_STYLE),
new StyleMenuItem("HTML (Complex)", HighlightedDocument.HTML_KEY_STYLE),
new StyleMenuItem("LaTeX", HighlightedDocument.LATEX_STYLE),
new StyleMenuItem("SQL", HighlightedDocument.SQL_STYLE),
new StyleMenuItem("Java Properties", HighlightedDocument.PROPERTIES_STYLE),
new StyleMenuItem("Plain", HighlightedDocument.PLAIN_STYLE),
new StyleMenuItem("Grayed Out", HighlightedDocument.GRAYED_OUT_STYLE),
};
JMenu menu = new JMenu("Style");
ButtonGroup group = new ButtonGroup();
for(int i = 0; i < items.length; i++) {
group.add(items[i]);
menu.add(items[i]);
}
return menu;
}
/**
* Initialize the document with some default text and set
* they initial type of syntax highlighting.
*/
private void initDocument() {
String initString = (
"/**\n" +
" * Simple common test program.\n" +
" */\n" +
"public class HelloWorld {\n" +
" public static void main(String[] args) {\n" +
" // Display the greeting.\n" +
" System.out.println(\"Hello World!\");\n" +
" }\n" +
"}\n"
);
textPane.setText(initString);
}
/**
* Run the demo.
*
* @param args ignored
*/
public static void main(String[] args) {
// create the demo
ProgrammerEditorDemo frame = new ProgrammerEditorDemo();
}
}
--- NEW FILE: Colorer.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.Ostermiller.Syntax;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.NoSuchElementException;
import java.util.SortedSet;
import java.util.TreeSet;
import javax.swing.text.AttributeSet;
import com.Ostermiller.Syntax.Lexer.Lexer;
import com.Ostermiller.Syntax.Lexer.Token;
/**
* Run the Syntax Highlighting as a separate thread. Things that need to be
* colored are messaged to the thread and put in a list.
*/
class Colorer extends Thread {
/**
* A simple wrapper representing something that needs to be colored. Placed
* into an object so that it can be stored in a Vector.
*/
private static class RecolorEvent {
public int position;
public int adjustment;
public RecolorEvent(int position, int adjustment) {
this.position = position;
this.adjustment = adjustment;
}
}
/**
* Stores the document we are coloring. We use a WeakReference
* so that the document is eligible for garbage collection when
* it is no longer being used. At that point, this thread will
* shut down itself.
*/
private WeakReference document;
/**
* Keep a list of places in the file that it is safe to restart the
* highlighting. This happens whenever the lexer reports that it has
* returned to its initial state. Since this list needs to be sorted and
* we need to be able to retrieve ranges from it, it is stored in a
* balanced tree.
*/
private TreeSet iniPositions = new TreeSet(DocPositionComparator.instance);
/**
* As we go through and remove invalid positions we will also be finding
* new valid positions. Since the position list cannot be deleted from
* and written to at the same time, we will keep a list of the new
* positions and simply add it to the list of positions once all the old
* positions have been removed.
*/
private HashSet newPositions = new HashSet();
/**
* Vector that stores the communication between the two threads.
*/
private volatile LinkedList events = new LinkedList();
/**
* When accessing the linked list, we need to create a critical section.
* we will synchronize on this object to ensure that we don't get unsafe
* thread behavior.
*/
private Object eventsLock = new Object();
/**
* The amount of change that has occurred before the place in the
* document that we are currently highlighting (lastPosition).
*/
private volatile int change = 0;
/**
* The last position colored
*/
private volatile int lastPosition = -1;
/**
* Creates the coloring thread for the given document.
*
* @param document The document to be colored.
*/
public Colorer(HighlightedDocument document) {
this.document = new WeakReference(document);
}
/**
* Tell the Syntax Highlighting thread to take another look at this
* section of the document. It will process this as a FIFO. This method
* should be done inside a docLock.
*/
public void color(int position, int adjustment) {
// figure out if this adjustment effects the current run.
// if it does, then adjust the place in the document
// that gets highlighted.
if (position < lastPosition) {
if (lastPosition < position - adjustment) {
change -= lastPosition - position;
} else {
change += adjustment;
}
}
synchronized (eventsLock) {
if(!events.isEmpty()) {
// check whether to coalesce with current last element
RecolorEvent curLast = (RecolorEvent) events.getLast();
if(adjustment < 0 && curLast.adjustment < 0) {
// both are removals
if(position == curLast.position) {
curLast.adjustment += adjustment;
return;
}
} else if(adjustment >= 0 && curLast.adjustment >= 0) {
// both are insertions
if(position == curLast.position + curLast.adjustment) {
curLast.adjustment += adjustment;
return;
} else if(curLast.position == position + adjustment) {
curLast.position = position;
curLast.adjustment += adjustment;
return;
}
}
}
events.add(new RecolorEvent(position, adjustment));
eventsLock.notifyAll();
}
}
/**
* The colorer runs forever and may sleep for long periods of time. It
* should be interrupted every time there is something for it to do.
*/
public void run() {
while(document.get() != null) {
try {
RecolorEvent re;
synchronized (eventsLock) {
// get the next event to process - stalling until the
// event becomes available
while(events.isEmpty() && document.get() != null) {
// stop waiting after a second in case document
// has been cleared.
eventsLock.wait(1000);
}
re = (RecolorEvent) events.removeFirst();
}
processEvent(re.position, re.adjustment);
Thread.sleep(100);
} catch(InterruptedException e) { }
}
}
private void processEvent(int position, int adjustment) {
HighlightedDocument doc = (HighlightedDocument) document.get();
if(doc == null) return;
// slurp everything up into local variables in case another
// thread changes them during coloring process
AttributeSet globalStyle = doc.getGlobalStyle();
Lexer syntaxLexer = doc.getSyntaxLexer();
DocumentReader documentReader = doc.getDocumentReader();
Object docLock = doc.getDocumentLock();
if(globalStyle != null) {
int start = Math.min(position, position + adjustment);
int stop = Math.max(position, position + adjustment);
synchronized(docLock) {
doc.setCharacterAttributes(start, stop - start,
globalStyle, true);
}
return;
}
SortedSet workingSet;
Iterator workingIt;
DocPosition startRequest = new DocPosition(position);
DocPosition endRequest = new DocPosition(position + Math.abs(adjustment));
DocPosition dp;
DocPosition dpStart = null;
DocPosition dpEnd = null;
// find the starting position. We must start at least one
// token before the current position
try {
// all the good positions before
workingSet = iniPositions.headSet(startRequest);
// the last of the stuff before
dpStart = (DocPosition) workingSet.last();
} catch (NoSuchElementException x) {
// if there were no good positions before the requested
// start,
// we can always start at the very beginning.
dpStart = new DocPosition(0);
}
// if stuff was removed, take any removed positions off the
// list.
if (adjustment < 0) {
workingSet = iniPositions.subSet(startRequest,
endRequest);
workingIt = workingSet.iterator();
while (workingIt.hasNext()) {
workingIt.next();
workingIt.remove();
}
}
// adjust the positions of everything after the
// insertion/removal.
workingSet = iniPositions.tailSet(startRequest);
workingIt = workingSet.iterator();
while (workingIt.hasNext()) {
((DocPosition) workingIt.next()).adjustPosition(adjustment);
}
// now go through and highlight as much as needed
workingSet = iniPositions.tailSet(dpStart);
workingIt = workingSet.iterator();
dp = null;
if (workingIt.hasNext()) {
dp = (DocPosition) workingIt.next();
}
try {
Token t;
boolean done = false;
dpEnd = dpStart;
synchronized (docLock) {
// we are playing some games with the lexer for
// efficiency.
// we could just create a new lexer each time here,
// but instead,
// we will just reset it so that it thinks it is
// starting at the
// beginning of the document but reporting a funny
// start position.
// Reseting the lexer causes the close() method on
// the reader
// to be called but because the close() method has
// no effect on the
// DocumentReader, we can do this.
syntaxLexer.reset(documentReader, 0, dpStart
.getPosition(), 0);
// After the lexer has been set up, scroll the
// reader so that it
// is in the correct spot as well.
documentReader.seek(dpStart.getPosition());
// we will highlight tokens until we reach a good
// stopping place.
// the first obvious stopping place is the end of
// the document.
// the lexer will return null at the end of the
// document and wee
// need to stop there.
t = syntaxLexer.getNextToken();
}
newPositions.add(dpStart);
while (!done && t != null) {
// this is the actual command that colors the stuff.
// Color stuff with the description of the styles
// stored in tokenStyles.
if (t.getCharEnd() <= doc.getLength()) {
doc.setCharacterAttributes(t.getCharBegin() + change,
t.getCharEnd() - t.getCharBegin(),
TokenStyles.getStyle(t.getDescription()),
true);
// record the position of the last bit of
// text that we colored
dpEnd = new DocPosition(t.getCharEnd());
}
lastPosition = (t.getCharEnd() + change);
// The other more complicated reason for doing no
// more highlighting
// is that all the colors are the same from here on
// out anyway.
// We can detect this by seeing if the place that
// the lexer returned
// to the initial state last time we highlighted is
// the same as the
// place that returned to the initial state this
// time.
// As long as that place is after the last changed
// text, everything
// from there on is fine already.
if (t.getState() == Token.INITIAL_STATE) {
// look at all the positions from last time that
// are less than or
// equal to the current position
while (dp != null
&& dp.getPosition() <= t.getCharEnd()) {
if (dp.getPosition() == t.getCharEnd()
&& dp.getPosition() >= endRequest
.getPosition()) {
// we have found a state that is the
// same
done = true;
dp = null;
} else if (workingIt.hasNext()) {
// didn't find it, try again.
dp = (DocPosition) workingIt.next();
} else {
// didn't find it, and there is no more
// info from last
// time. This means that we will just
// continue
// until the end of the document.
dp = null;
}
}
// so that we can do this check next time,
// record all the
// initial states from this time.
newPositions.add(dpEnd);
}
synchronized (docLock) {
t = syntaxLexer.getNextToken();
}
}
// remove all the old initial positions from the place
// where
// we started doing the highlighting right up through
// the last
// bit of text we touched.
workingIt = iniPositions.subSet(dpStart, dpEnd)
.iterator();
while (workingIt.hasNext()) {
workingIt.next();
workingIt.remove();
}
// Remove all the positions that are after the end of
// the file.:
workingIt = iniPositions.tailSet(
new DocPosition(doc.getLength())).iterator();
while (workingIt.hasNext()) {
workingIt.next();
workingIt.remove();
}
// and put the new initial positions that we have found
// on the list.
iniPositions.addAll(newPositions);
newPositions.clear();
} catch (IOException x) {
}
synchronized (docLock) {
lastPosition = -1;
change = 0;
}
}
}
--- NEW FILE: 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.Ostermiller.Syntax;
import java.io.Reader;
import javax.swing.text.AbstractDocument;
import javax.swing.text.BadLocationException;
/**
* 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 {
/**
* 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;
}
}
}
/**
* 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 AbstractDocument document;
/**
* Construct a reader on the given document.
*
* @param document the document to be read.
*/
public DocumentReader(AbstractDocument document){
this.document = document;
}
/**
* Has no effect. This reader can be used even after
* it has been closed.
*/
public void close() {
}
/**
* Save a position for reset.
*
* @param readAheadLimit ignored.
*/
public void mark(int readAheadLimit){
mark = position;
}
/**
* This reader support mark and reset.
*
* @return true
*/
public boolean markSupported(){
return true;
}
/**
* Read a single character.
*
* @return the character or -1 if the end of the document has been reached.
*/
public int read(){
if (position < document.getLength()){
try {
char c = document.getText((int)position, 1).charAt(0);
position++;
return c;
} catch (BadLocationException x){
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.
*/
public int read(char[] cbuf){
return 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.
*/
public int read(char[] cbuf, int off, int len){
if (position < document.getLength()){
int length = len;
if (position + length >= document.getLength()){
length = document.getLength() - (int)position;
}
if (off + length >= cbuf.length){
length = cbuf.length - off;
}
try {
String s = document.getText((int)position, length);
position += length;
for (int i=0; i<length; i++){
cbuf[off+i] = s.charAt(i);
}
return length;
} catch (BadLocationException x){
return -1;
}
} else {
return -1;
}
}
/**
* @return true
*/
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.
*/
public void reset(){
if (mark == -1){
position = 0;
} else {
position = mark;
}
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.
*/
public long skip(long n){
if (position + n <= document.getLength()){
position += n;
return n;
} else {
long oldPos = position;
position = document.getLength();
return (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 <= document.getLength()){
position = n;
} else {
position = document.getLength();
}
}
}
--- NEW FILE: TokenStyles.java ---
/*
* This file is part of the programmer editor demo
* Copyright (C) 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.Ostermiller.Syntax;
import java.awt.Color;
import java.util.HashMap;
import javax.swing.text.AttributeSet;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
class TokenStyles {
private TokenStyles() { } // disable constructor
/**
* A hash table containing the text styles. Simple attribute sets are hashed
* by name (String)
*/
private static HashMap styles = new HashMap();
/**
* Create the styles and place them in the hash table.
*/
static {
Color maroon = new Color(0xB03060);
Color darkBlue = new Color(0x000080);
Color darkGreen = Color.GREEN.darker();
Color darkPurple = new Color(0xA020F0).darker();
addStyle("body", Color.WHITE, Color.BLACK, false, false);
addStyle("tag", Color.WHITE, Color.BLUE, true, false);
addStyle("endtag", Color.WHITE, Color.BLUE, false, false);
addStyle("reference", Color.WHITE, Color.BLACK, false, false);
addStyle("name", Color.WHITE, maroon, true, false);
addStyle("value", Color.WHITE, maroon, false, true);
addStyle("text", Color.WHITE, Color.BLACK, true, false);
addStyle("reservedWord", Color.WHITE, Color.BLUE, false, false);
addStyle("identifier", Color.WHITE, Color.BLACK, false, false);
addStyle("literal", Color.WHITE, maroon, false, false);
addStyle("separator", Color.WHITE, darkBlue, false, false);
addStyle("operator", Color.WHITE, Color.BLACK, true, false);
addStyle("comment", Color.WHITE, darkGreen, false, false);
addStyle("preprocessor", Color.WHITE, darkPurple, false, false);
addStyle("whitespace", Color.WHITE, Color.BLACK, false, false);
addStyle("error", Color.WHITE, Color.RED, false, false);
addStyle("unknown", Color.WHITE, Color.ORANGE, false, false);
addStyle("grayedOut", Color.WHITE, Color.GRAY, false, false);
}
private static void addStyle(String name, Color bg, Color fg, boolean bold,
boolean italic) {
SimpleAttributeSet style = new SimpleAttributeSet();
StyleConstants.setFontFamily(style, "Monospaced");
StyleConstants.setFontSize(style, 12);
StyleConstants.setBackground(style, bg);
StyleConstants.setForeground(style, fg);
StyleConstants.setBold(style, bold);
StyleConstants.setItalic(style, italic);
styles.put(name, style);
}
/**
* Retrieve the style for the given type of token.
*
* @param styleName
* the label for the type of text ("tag" for example) or null if
* the styleName is not known.
* @return the style
*/
public static AttributeSet getStyle(String styleName) {
return (AttributeSet) styles.get(styleName);
}
}
|