PageRenderTime 35ms CodeModel.GetById 18ms app.highlight 13ms RepoModel.GetById 1ms app.codeStats 0ms

/jEdit/tags/jedit-4-3-pre5/org/gjt/sp/jedit/syntax/DisplayTokenHandler.java

#
Java | 234 lines | 146 code | 34 blank | 54 comment | 33 complexity | af5330082b09a59e1709c9b01caeee59 MD5 | raw file
  1/*
  2 * DisplayTokenHandler.java - converts tokens to chunks
  3 * :tabSize=8:indentSize=8:noTabs=false:
  4 * :folding=explicit:collapseFolds=1:
  5 *
  6 * Copyright (C) 2003 Slava Pestov
  7 *
  8 * This program is free software; you can redistribute it and/or
  9 * modify it under the terms of the GNU General Public License
 10 * as published by the Free Software Foundation; either version 2
 11 * of the License, or any later version.
 12 *
 13 * This program is distributed in the hope that it will be useful,
 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 16 * GNU General Public License for more details.
 17 *
 18 * You should have received a copy of the GNU General Public License
 19 * along with this program; if not, write to the Free Software
 20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 21 */
 22
 23package org.gjt.sp.jedit.syntax;
 24
 25//{{{ Imports
 26import javax.swing.text.*;
 27import java.awt.font.*;
 28import java.util.List;
 29import org.gjt.sp.jedit.syntax.*;
 30//}}}
 31
 32/**
 33 * Creates {@link Chunk} objects that can be painted on screen.
 34 */
 35public class DisplayTokenHandler extends DefaultTokenHandler
 36{
 37	// don't have chunks longer than 100 characters to avoid slowing things down
 38	public static final int MAX_CHUNK_LEN = 100;
 39
 40	//{{{ init() method
 41	public void init(SyntaxStyle[] styles,
 42		FontRenderContext fontRenderContext,
 43		TabExpander expander, List out,
 44		float wrapMargin)
 45	{
 46		super.init();
 47
 48		x = 0.0f;
 49
 50		this.styles = styles;
 51		this.fontRenderContext = fontRenderContext;
 52		this.expander = expander;
 53
 54		// SILLY: allow for anti-aliased characters' "fuzz"
 55		if(wrapMargin != 0.0f)
 56			this.wrapMargin = wrapMargin += 2.0f;
 57		else
 58			this.wrapMargin = 0.0f;
 59
 60		this.out = out;
 61
 62		seenNonWhitespace = false;
 63		endX = endOfWhitespace = 0.0f;
 64		end = null;
 65	} //}}}
 66
 67	//{{{ getChunkList() method
 68	/**
 69	 * Returns the list of chunks.
 70	 * @since jEdit 4.1pre7
 71	 */
 72	public List getChunkList()
 73	{
 74		return out;
 75	} //}}}
 76
 77	//{{{ handleToken() method
 78	/**
 79	 * Called by the token marker when a syntax token has been parsed.
 80	 * @param seg The segment containing the text
 81	 * @param id The token type (one of the constants in the
 82	 * {@link Token} class).
 83	 * @param offset The start offset of the token
 84	 * @param length The number of characters in the token
 85	 * @param context The line context
 86	 * @since jEdit 4.2pre3
 87	 */
 88	public void handleToken(Segment seg, byte id, int offset, int length,
 89		TokenMarker.LineContext context)
 90	{
 91		if(id == Token.END)
 92		{
 93			if(firstToken != null)
 94				out.add(merge((Chunk)firstToken,seg));
 95			return;
 96		}
 97
 98		for(int splitOffset = 0; splitOffset < length; splitOffset += MAX_CHUNK_LEN)
 99		{
100			int splitLength = Math.min(length - splitOffset,MAX_CHUNK_LEN);
101			Chunk chunk = createChunk(id,offset + splitOffset,splitLength,context);
102			addToken(chunk,context);
103
104			if(wrapMargin != 0.0f)
105			{
106				initChunk(chunk,seg);
107				x += chunk.width;
108
109				if(Character.isWhitespace(seg.array[
110					seg.offset + chunk.offset]))
111				{
112					if(seenNonWhitespace)
113					{
114						end = lastToken;
115						endX = x;
116					}
117					else
118						endOfWhitespace = x;
119				}
120				else
121				{
122					if(x > wrapMargin
123						&& end != null
124						&& seenNonWhitespace)
125					{
126						Chunk nextLine = new Chunk(endOfWhitespace,
127							end.offset + end.length,
128							getParserRuleSet(context));
129						initChunk(nextLine,seg);
130
131						nextLine.next = end.next;
132						end.next = null;
133
134						if(firstToken != null)
135							out.add(merge((Chunk)firstToken,seg));
136
137						firstToken = nextLine;
138
139						x = x - endX + endOfWhitespace;
140
141						end = null;
142						endX = x;
143					}
144
145					seenNonWhitespace = true;
146				}
147			}
148		}
149	} //}}}
150
151	//{{{ Private members
152
153	//{{{ Instance variables
154	private SyntaxStyle[] styles;
155	private FontRenderContext fontRenderContext;
156	private TabExpander expander;
157	private float x;
158
159	private List out;
160	private float wrapMargin;
161	private float endX;
162	private Token end;
163
164	private boolean seenNonWhitespace;
165	private float endOfWhitespace;
166	//}}}
167
168	//{{{ createChunk() method
169	private Chunk createChunk(byte id, int offset, int length,
170		TokenMarker.LineContext context)
171	{
172		return new Chunk(id,offset,length,
173			getParserRuleSet(context),styles,
174			context.rules.getDefault());
175	} //}}}
176
177	//{{{ initChunk() method
178	protected void initChunk(Chunk chunk, Segment seg)
179	{
180		chunk.init(seg,expander,x,fontRenderContext);
181	} //}}}
182
183	//{{{ merge() method
184	private Chunk merge(Chunk first, Segment seg)
185	{
186		if(first == null)
187			return null;
188
189		Chunk chunk = first;
190		while(chunk.next != null)
191		{
192			Chunk next = (Chunk)chunk.next;
193			if(canMerge(chunk,next,seg))
194			{
195				// in case already initialized; un-initialize it
196				chunk.initialized = false;
197				chunk.length += next.length;
198				chunk.width += next.width;
199				chunk.next = next.next;
200			}
201			else
202			{
203				if(!chunk.initialized)
204				{
205					initChunk(chunk,seg);
206					if(wrapMargin == 0.0f)
207						x += chunk.width;
208				}
209				chunk = next;
210			}
211		}
212
213		if(!chunk.initialized)
214			initChunk(chunk,seg);
215
216		return first;
217	} //}}}
218
219	//{{{ canMerge() method
220	private boolean canMerge(Chunk c1, Chunk c2, Segment seg)
221	{
222		if(!c1.accessable || !c2.accessable)
223			return false;
224
225		char ch1 = seg.array[seg.offset + c1.offset];
226		char ch2 = seg.array[seg.offset + c2.offset];
227
228		return ((c1.style == c2.style)
229			&& ch1 != '\t' && ch2 != '\t'
230			&& (c1.length + c2.length <= MAX_CHUNK_LEN));
231	} //}}}
232
233	//}}}
234}