⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rsyntaxdocument.java

📁 具有不同语法高亮的编辑器实例
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/*
 * 10/16/2004
 *
 * RSyntaxDocument.java - A document capable of syntax highlighting, used by
 * RSyntaxTextArea.
 * Copyright (C) 2004 Robert Futrell
 * email@address.com
 * www.website.com
 *
 * 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 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package org.fife.ui.rsyntaxtextarea;

import javax.swing.event.*;
import javax.swing.text.*;

import org.fife.ui.rsyntaxtextarea.modes.*;
import org.fife.ui.rtextarea.RTextAreaDocument;
import org.fife.util.DynamicIntArray;


/**
 * The document used by {@link org.fife.ui.rsyntaxtextarea.RSyntaxTextArea}.
 * This document is like <code>javax.swing.text.PlainDocument</code> except that
 * it also keeps track of syntax highlighting in the document.  It has a "style"
 * attribute associated with it that determines how syntax highlighting is done
 * (i.e., what language is being highlighted).<p>
 *
 * Instances of <code>RSyntaxTextArea</code> will only accept instances of
 * <code>RSyntaxDocument</code>, since it is this document that keeps
 * track of syntax highlighting.  All others will cause an exception to be
 * thrown.<p>
 *
 * To change the language being syntax highlighted at any time, you merely have
 * to call {@link #setSyntaxStyle}.  Other than that, this document can be
 * treated like any other save one caveat:  all <code>DocumentEvent</code>s of
 * type <code>CHANGE</code> use their offset and length values to represent the
 * first and last lines, respectively, that have had their syntax coloring
 * change.  This is really a hack to increase the speed of the painting code
 * and should really be corrected, but oh well.
 *
 * @author Robert Futrell
 * @version 0.1
 */
public class RSyntaxDocument extends RTextAreaDocument
										implements SyntaxConstants {

	/**
	 * 
	 */
	private static final long serialVersionUID = -6255404347412937685L;

	private TokenMaker tokenMaker;

	/**
	 * Array of values representing the "last token type" on each line.  This
	 * is used in cases such as multiline comments:  if the previous line
	 * ended with an (unclosed) multiline comment, we can use this knowledge
	 * and start the current line's syntax highlighting in multiline comment
	 * state.
	 */
	protected DynamicIntArray lastTokensOnLines;

	private transient Segment s;


/*****************************************************************************/


	/**
	 * Constructs a plain text document.  A default root element is created,
	 * and the tab size set to 5.
	 *
	 * @param syntaxStyle The syntax highlighting scheme to use.
	 */
	public RSyntaxDocument(int syntaxStyle) {
		super(new GapContent());
		putProperty(tabSizeAttribute, new Integer(5));
		lastTokensOnLines = new DynamicIntArray(500);
		lastTokensOnLines.add(Token.NULL); // Initial (empty) line.
		s = new Segment();
		setSyntaxStyle(syntaxStyle);
	}


/*****************************************************************************/


	/**
	 * Creates a token element.  Line elements contain these, representing
	 * syntax-highlighting tokens.
	 */
	protected Element createTokenElement(Element parent, int p0,int p1,
									int type) {
		return new TokenElement(parent, p0, p1, type);
	}


/*****************************************************************************/

	/**
	 * Alerts all listeners to this document of an insertion.  This is
	 * overridden so we can update our syntax highlighting stuff.<p>
	 * The syntax highlighting stuff has to be here instead of in
	 * <code>insertUpdate</code> because <code>insertUpdate</code> is not
	 * called by the undo/redo actions, but this method is.
	 *
	 * @param e The change.
	 */
	protected void fireInsertUpdate(DocumentEvent e) {

		/*
		 * Now that the text is actually inserted into the content and
		 * element structure, we can update our token elements and "last
		 * tokens on lines" structure.
		 */

		Element lineMap = getDefaultRootElement();
		DocumentEvent.ElementChange change = e.getChange(lineMap);
		Element[] added = change==null ? null : change.getChildrenAdded();

		int numLines = lineMap.getElementCount();
		int line = lineMap.getElementIndex(e.getOffset());
		int previousLine = line - 1;
		int previousTokenType = (previousLine>-1 ?
					lastTokensOnLines.get(previousLine) : Token.NULL);

		// If entire lines were added...
		if (added!=null && added.length>0) {

			Element[] removed = change.getChildrenRemoved();
			int numRemoved = removed!=null ? removed.length : 0;

			int endBefore = line + added.length - numRemoved;
			//System.err.println("... adding lines: " + line + " - " + (endBefore-1));
			//System.err.println("... ... added: " + added.length + ", removed:" + numRemoved);
			for (int i=line; i<endBefore; i++) {

				setSharedSegment(i); // Loads line i's text into s.

				int tokenType = tokenMaker.getLastTokenTypeOnLine(s, previousTokenType);
				lastTokensOnLines.add(i, tokenType);
				//System.err.println("--------- lastTokensOnLines.size() == " + lastTokensOnLines.getSize());

				previousTokenType = tokenType;

			} // End of for (int i=line; i<endBefore; i++).

			// Update last tokens for lines below until they stop changing.
			updateLastTokensBelow(endBefore, numLines, previousTokenType);

		} // End of if (added!=null && added.length>0).

		// Otherwise, text was inserted on a single line...
		else {

			// Update last tokens for lines below until they stop changing.
			updateLastTokensBelow(line, numLines, previousTokenType);

		} // End of else.

		// Let all listeners know about the insertion.
		super.fireInsertUpdate(e);

	}


/*****************************************************************************/


	/**
	 * This method is called AFTER the content has been inserted into the
	 * document and the element structure has been updated.<p>
	 * The syntax-highlighting updates need to be done here (as opposed to
	 * an override of <code>postRemoveUpdate</code>) as this method is called
	 * in response to undo/redo events, whereas <code>postRemoveUpdate</code>
	 * is not.<p>
	 * Now that the text is actually inserted into the content and element
	 * structure, we can update our token elements and "last tokens on
	 * lines" structure.
	 *
	 * @param chng The change that occured.
	 * @see #removeUpdate
	 */
	protected void fireRemoveUpdate(DocumentEvent chng) {

		Element lineMap = getDefaultRootElement();
		int numLines = lineMap.getElementCount();

		DocumentEvent.ElementChange change = chng.getChange(lineMap);
		Element[] removed = change==null ? null : change.getChildrenRemoved();

		// If entire lines were removed...
		if (removed!=null && removed.length>0) {

			int line = change.getIndex();	// First line entirely removed.
			int previousLine = line - 1;	// Line before that.
			int previousTokenType = (previousLine>-1 ? lastTokensOnLines.get(previousLine) : Token.NULL);

			Element[] added = change.getChildrenAdded();
			int numAdded = added==null ? 0 : added.length;

			// Remove the cached last-token values for the removed lines.
			int endBefore = line + removed.length - numAdded;
			//System.err.println("... removing lines: " + line + " - " + (endBefore-1));
			//System.err.println("... added: " + numAdded + ", removed: " + removed.length);

			lastTokensOnLines.removeRange(line, endBefore); // Removing values for lines [line-(endBefore-1)].
			//System.err.println("--------- lastTokensOnLines.size() == " + lastTokensOnLines.getSize());

			// Update last tokens for lines below until they've stopped changing.
			updateLastTokensBelow(line, numLines, previousTokenType);

		} // End of if (removed!=null && removed.size()>0).

		// Otherwise, text was removed from just one line...
		else {

			int line = lineMap.getElementIndex(chng.getOffset());
			if (line>=lastTokensOnLines.getSize())
				return;	// If we're editing the last line in a document...

			int previousLine = line - 1;
			int previousTokenType = (previousLine>-1 ? lastTokensOnLines.get(previousLine) : Token.NULL);
			//System.err.println("previousTokenType for line : " + previousLine + " is " + previousTokenType);
			// Update last tokens for lines below until they've stopped changing.
			updateLastTokensBelow(line, numLines, previousTokenType);

		}

		// Let all of our listeners know about the removal.
		super.fireRemoveUpdate(chng);

	}


/*****************************************************************************/


	/**
	 * Returns the token type of the last token on the given line.
	 *
	 * @param line The line to inspect.
	 * @return The token type of the last token on the specified line.  If
	 *         the line is invalid, an exception is thrown.
	 */
	public int getLastTokenTypeOnLine(int line) {
		return lastTokensOnLines.get(line);
	}


/*****************************************************************************/


	/**
	 * Returns a token list for the specified segment of text representing
	 * the specified line number.  This method is basically a wrapper for
	 * <code>tokenMaker.getTokenList</code> that takes into account the last
	 * token on the previous line to assure token accuracy.
	 *
	 * @param line The line number of <code>text</code> in the document, >= 0.
	 * @return A token list representing the specified line.
	 */
	public final Token getTokenListForLine(int line) {
// FIXME:  This is where we would use the "token elements" instead of calling
// getTokenList().  But for the time being, we'll do ig the old-fashioned way.
// When ready, remove the old version below, uncomment these lines of code, and
// implement the rest.
/*
		Element map = getDefaultRootElement();
		LineElement elem = (LineElement)map.getElement(line);
		int startOffset = elem.getStartOffset();
		int endOffset = elem.getEndOffset() - 1; // Why always "-1"?
		try {
			getText(startOffset,endOffset-startOffset, s);
		} catch (BadLocationException ble) {
			ble.printStackTrace();
			return null;
		}
		Enumeration e = elem.children();
		if (e!=null) {
			Token tokenList = null;
			Token t2 = null;
			Token t3 = null;
			while (e.hasMoreElements()) {
				TokenElement te = (TokenElement)e.nextElement();
				int so = te.getStartOffset();
				int eo = te.getEndOffset();
System.err.println(so + "-" + eo + ", " + te.getType());
				if (tokenList==null) {
					tokenList = new DefaultToken(s, s.offset+(so-startOffset),
											s.offset+(eo-startOffset),
											so, te.getType());
					t2 = tokenList;
				}
				else {
					t3 = new DefaultToken(s, s.offset+(so-startOffset),
											s.offset+(eo-startOffset),
											so, te.getType());
					t2.nextToken = t3;
					t2 = t3;
				}
			}
			return tokenList;
		}
		else
			return new DefaultToken();
*/

		Element map = getDefaultRootElement();
		Element elem = map.getElement(line);
		int startOffset = elem.getStartOffset();
		//int endOffset = (line==map.getElementCount()-1 ? elem.getEndOffset() - 1:
		//									elem.getEndOffset() - 1);
		int endOffset = elem.getEndOffset() - 1; // Why always "-1"?
		try {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -