Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
Copyright (c) 2010 itemis AG (http://www.itemis.eu) and others. All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html /
  
  package org.eclipse.xtext.ui.editor.model;
  
 import java.util.List;
 
 import  org.eclipse.core.runtime.Assert;
 import  org.eclipse.core.runtime.Platform;
 import  org.eclipse.jface.text.BadLocationException;
 import  org.eclipse.jface.text.BadPositionCategoryException;
 import  org.eclipse.jface.text.DefaultPositionUpdater;
 import  org.eclipse.jface.text.DocumentEvent;
 import  org.eclipse.jface.text.DocumentRewriteSession;
 import  org.eclipse.jface.text.IDocument;
 import  org.eclipse.jface.text.IDocumentPartitioner;
 import  org.eclipse.jface.text.IDocumentPartitionerExtension;
 import  org.eclipse.jface.text.IDocumentPartitionerExtension2;
 import  org.eclipse.jface.text.IDocumentPartitionerExtension3;
 import  org.eclipse.jface.text.IRegion;
 import  org.eclipse.jface.text.ITypedRegion;
 import  org.eclipse.jface.text.Position;
 import  org.eclipse.jface.text.Region;
 import  org.eclipse.jface.text.TextUtilities;
 import  org.eclipse.jface.text.TypedPosition;
 import  org.eclipse.jface.text.TypedRegion;
 import  org.eclipse.jface.text.rules.IPartitionTokenScanner;
 import  org.eclipse.jface.text.rules.IToken;
 
Initially copied from org.eclipse.jface.text.rules.FastPartitioner in order to be able to fix documentChanged2(DocumentEvent)

Author(s):
Sebastian Zarnekow - Initial contribution and API
Since:
2.2
 
 public class DocumentPartitioner implements IDocumentPartitioner, IDocumentPartitionerExtension,
 		IDocumentPartitionerExtension2, IDocumentPartitionerExtension3 {
 
 	private static final Logger log = Logger.getLogger(DocumentPartitioner.class);

The position category this partitioner uses to store the document's partitioning information.

Since:
2.2
 
 	protected static final String CONTENT_TYPES_CATEGORY = "__content_types_category"//$NON-NLS-1$
 	
The partitioner's scanner

Since:
2.2
 
 	protected final IPartitionTokenScanner fScanner;
The legal content types of this partitioner

Since:
2.2
 
 	protected final String[] fLegalContentTypes;
The partitioner's document

Since:
2.2
 
 	protected IDocument fDocument;
The position updater used to for the default updating of partitions

Since:
2.2
 
 	protected final DefaultPositionUpdater fPositionUpdater;
The offset at which the first changed partition starts

Since:
2.2
 
 	protected int fStartOffset;
The offset at which the last changed partition ends

Since:
2.2
 
 	protected int fEndOffset;
The offset at which a partition has been deleted

Since:
2.2
 
 	protected int fDeleteOffset;
The position category this partitioner uses to store the document's partitioning information.

Since:
2.2
	protected final String fPositionCategory;
The active document rewrite session.

Since:
2.2
	protected DocumentRewriteSession fActiveRewriteSession;
Flag indicating whether this partitioner has been initialized.

Since:
2.2
	protected boolean fIsInitialized = false;
The cached positions from our document, so we don't create a new array every time someone requests partition information.

Since:
2.2
	protected Position[] fCachedPositions = null;
Debug option for cache consistency checking.

Since:
2.2
	protected static final boolean CHECK_CACHE_CONSISTENCY = "true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.jface.text/debug/FastPartitioner/PositionCache")); //$NON-NLS-1$//$NON-NLS-2$;
Creates a new partitioner that uses the given scanner and may return partitions of the given legal content types.

Parameters:
scanner the scanner this partitioner is supposed to use
legalContentTypes the legal content types of this partitioner
Since:
2.2
	public DocumentPartitioner(IPartitionTokenScanner scannerString[] legalContentTypes) {
		 = scanner;
		 = TextUtilities.copy(legalContentTypes);
		 = new DefaultPositionUpdater();
	}
	public DocumentPartitioner(IPartitionTokenScanner scannerITokenTypeToPartitionTypeMapper mapper) {
		this(scannermapper.getSupportedPartitionTypes());
	}
	/*
	 * @see org.eclipse.jface.text.IDocumentPartitionerExtension2#getManagingPositionCategories()
	 */

Since:
2.2
		return new String[] {  };
	}
	/*
	 * @see org.eclipse.jface.text.IDocumentPartitioner#connect(org.eclipse.jface.text.IDocument)
	 */

Since:
2.2
	public final void connect(IDocument document) {
		connect(documentfalse);
	}

May be extended by subclasses.

Since:
2.2
	public synchronized void connect(IDocument documentboolean delayInitialization) {
		Assert.isNotNull(document);
		Assert.isTrue(!document.containsPositionCategory());
		 = document;
		.addPositionCategory();
		 = false;
		if (!delayInitialization)
	}

Calls initialize() if the receiver is not yet initialized.

Since:
2.2
	protected final void checkInitialization() {
	}

Performs the initial partitioning of the partitioner's document.

May be extended by subclasses.

Since:
2.2
	protected void initialize() {
		.setRange(, 0, .getLength());
		try {
			IToken token = .nextToken();
			while (!token.isEOF()) {
				String contentType = getTokenContentType(token);
				if (isSupportedContentType(contentType)) {
					TypedPosition p = new TypedPosition(.getTokenOffset(), .getTokenLength(),
							contentType);
					.addPosition(p);
				}
				token = .nextToken();
			}
catch (BadLocationException x) {
			// cannot happen as offsets come from scanner
catch (BadPositionCategoryException x) {
			// cannot happen if document has been connected before
		}
	}

May be extended by subclasses.

Since:
2.2
	public synchronized void disconnect() {
		Assert.isTrue(.containsPositionCategory());
		try {
			.removePositionCategory();
catch (BadPositionCategoryException x) {
			// can not happen because of Assert
		}
	}

May be extended by subclasses.

Since:
2.2
	public synchronized void documentAboutToBeChanged(DocumentEvent e) {
			Assert.isTrue(e.getDocument() == );
			 = -1;
		}
	}
	/*
	 * @see IDocumentPartitioner#documentChanged(DocumentEvent)
	 */

Since:
2.2
	public synchronized final boolean documentChanged(DocumentEvent e) {
			IRegion region = documentChanged2(e);
			return (region != null);
		}
		return false;
	}

Helper method for tracking the minimal region containing all partition changes. If offset is smaller than the remembered offset, offset will from now on be remembered. If offset + length is greater than the remembered end offset, it will be remembered from now on.

Parameters:
offset the offset
length the length
	private void rememberRegion(int offsetint length) {
		// remember start offset
		if ( == -1)
			 = offset;
		else if (offset < )
			 = offset;
		// remember end offset
		int endOffset = offset + length;
		if ( == -1)
			 = endOffset;
		else if (endOffset > )
			 = endOffset;
	}

Remembers the given offset as the deletion offset.

Parameters:
offset the offset
	private void rememberDeletedOffset(int offset) {
		 = offset;
	}

Creates the minimal region containing all partition changes using the remembered offset, end offset, and deletion offset.

Returns:
the minimal region containing all the partition changes
	private IRegion createRegion() {
		if ( == -1) {
			if ( == -1 ||  == -1)
				return null;
			return new Region( - );
else if ( == -1 ||  == -1) {
			return new Region(, 0);
else {
			int offset = Math.min();
			int endOffset = Math.max();
			return new Region(offsetendOffset - offset);
		}
	}

May be extended by subclasses.

Since:
2.2
	public synchronized IRegion documentChanged2(DocumentEvent e) {
			return null;
		try {
			Assert.isTrue(e.getDocument() == );
			Position[] category = getPositions();
			int reparseStart = e.getOffset();
			String contentType = null;
			int newLength = e.getText() == null ? 0 : e.getText().length();
			int oldPosition = .computeIndexInCategory(reparseStart);
			if (oldPosition > 0) {
				Position oldPartition = category[oldPosition - 1];
				if (oldPartition.offset + oldPartition.length > reparseStart)
					reparseStart = category[oldPosition - 1].offset;
			}
			.setPartialRange(reparseStart.getLength() - reparseStart/* ignore contentType */
					nullreparseStart);
			int behindLastScannedPosition = reparseStart;
			IToken token = .nextToken();
			int actualReparseStart = .getTokenOffset();
			int partitionStart = -1;
			int first = .computeIndexInCategory(actualReparseStart);
			if (first > 0) {
				TypedPosition partition = (TypedPosition) category[first - 1];
				if (partition.includes(actualReparseStart)) {
					partitionStart = partition.getOffset();
					contentType = partition.getType();
					if (e.getOffset() == partition.getOffset() + partition.getLength())
						actualReparseStart = partitionStart;
					--first;
else if (actualReparseStart == e.getOffset()
						&& actualReparseStart == partition.getOffset() + partition.getLength()) {
					partitionStart = partition.getOffset();
					contentType = partition.getType();
					actualReparseStart = partitionStart;
					--first;
else {
					partitionStart = partition.getOffset() + partition.getLength();
					contentType = IDocument.DEFAULT_CONTENT_TYPE;
					if (actualReparseStart != partitionStart) {
						String message = String.format(
								"Detected unexpected state in document partitioner. Please file a bug with the following information attached:%n" +
								"Document content after the event was applied:%n" +
								">>>%s<<<%n" +
								"Document event: %s".get(), String.valueOf(e));
						.error(message);
					}
				}
			}
			.setPartialRange(actualReparseStart.getLength() - actualReparseStartcontentType
					actualReparseStart);
			behindLastScannedPosition = actualReparseStart;
			token = .nextToken();
			for (int i = firsti < category.length; i++) {
				Position p = category[i];
				if (p.isDeleted) {
					rememberDeletedOffset(e.getOffset());
					break;
				}
			}
			category = getPositions();
			while (!token.isEOF()) {
				contentType = getTokenContentType(token);
				if (!isSupportedContentType(contentType)) {
					token = .nextToken();
					continue;
				}
				int start = .getTokenOffset();
				int length = .getTokenLength();
				behindLastScannedPosition = start + length;
				int lastScannedPosition = behindLastScannedPosition - 1;
				// remove all affected positions
				while (first < category.length) {
					TypedPosition p = (TypedPosition) category[first];
					if (lastScannedPosition >= p.offset + p.length
							|| (p.overlapsWith(startlength) && (!.containsPosition(start,
									length) || !contentType.equals(p.getType())))) {
						rememberRegion(p.offset, p.length);
						.removePosition(p);
						++first;
else
						break;
				}
				// if position already exists and we have scanned at least the
				// area covered by the event, we are done
				if (.containsPosition(startlength)) {
					if (lastScannedPosition >= e.getOffset() + newLength)
						return createRegion();
					++first;
else {
					// insert the new type position
					try {
						.addPosition(new TypedPosition(startlengthcontentType));
						rememberRegion(startlength);
catch (BadPositionCategoryException x) {
catch (BadLocationException x) {
					}
				}
				token = .nextToken();
			}
			first = .computeIndexInCategory(behindLastScannedPosition);
			category = getPositions();
			TypedPosition p;
			while (first < category.length) {
				p = (TypedPosition) category[first++];
				.removePosition(p);
				rememberRegion(p.offset, p.length);
			}
catch (BadPositionCategoryException x) {
			// should never happen on connected documents
catch (BadLocationException x) {
finally {
		}
		return createRegion();
	}

Returns the position in the partitoner's position category which is close to the given offset. This is, the position has either an offset which is the same as the given offset or an offset which is smaller than the given offset. This method profits from the knowledge that a partitioning is a ordered set of disjoint position.

May be extended or replaced by subclasses.

Parameters:
offset the offset for which to search the closest position
Returns:
the closest position in the partitioner's category
Since:
2.2
	protected TypedPosition findClosestPosition(int offset) {
		try {
			int index = .computeIndexInCategory(offset);
			Position[] category = getPositions();
			if (category.length == 0)
				return null;
			if (index < category.length) {
				if (offset == category[index].offset)
					return (TypedPosition) category[index];
			}
			if (index > 0)
				index--;
			return (TypedPosition) category[index];
catch (BadPositionCategoryException x) {
catch (BadLocationException x) {
		}
		return null;
	}

May be replaced or extended by subclasses.

Since:
2.2
	public synchronized String getContentType(int offset) {
		TypedPosition p = findClosestPosition(offset);
		if (p != null && p.includes(offset))
			return p.getType();
		return IDocument.DEFAULT_CONTENT_TYPE;
	}

May be replaced or extended by subclasses.

Since:
2.2
	public synchronized ITypedRegion getPartition(int offset) {
		try {
			Position[] category = getPositions();
			if (category == null || category.length == 0)
				return new TypedRegion(0, .getLength(), IDocument.DEFAULT_CONTENT_TYPE);
			int index = .computeIndexInCategory(offset);
			if (index < category.length) {
				TypedPosition next = (TypedPosition) category[index];
				if (offset == next.offset)
					return new TypedRegion(next.getOffset(), next.getLength(), next.getType());
				if (index == 0)
					return new TypedRegion(0, next.offset, IDocument.DEFAULT_CONTENT_TYPE);
				TypedPosition previous = (TypedPosition) category[index - 1];
				if (previous.includes(offset))
					return new TypedRegion(previous.getOffset(), previous.getLength(), previous.getType());
				int endOffset = previous.getOffset() + previous.getLength();
				return new TypedRegion(endOffsetnext.getOffset() - endOffset, IDocument.DEFAULT_CONTENT_TYPE);
			}
			TypedPosition previous = (TypedPosition) category[category.length - 1];
			if (previous.includes(offset)) {
				return new TypedRegion(previous.getOffset(), previous.getLength(), previous.getType());
			}
			if (isOpenSingleLineCommentPartition(previousoffset)) {
				return new TypedRegion(previous.getOffset(), previous.getLength() + 1, previous.getType());
			}
			int endOffset = previous.getOffset() + previous.getLength();
			return new TypedRegion(endOffset.getLength() - endOffset, IDocument.DEFAULT_CONTENT_TYPE);
catch (BadPositionCategoryException x) {
catch (BadLocationException x) {
		}
		return new TypedRegion(0, .getLength(), IDocument.DEFAULT_CONTENT_TYPE);
	}
	private boolean isOpenSingleLineCommentPartition(TypedPosition positionint offsetthrows BadLocationException {
		if (position.isDeleted()) {
			return false;
		}
		int endOffset = position.getOffset() + position.getLength();
		if (offset != endOffset) {
			return false;
		}
			return false;
		}
		int line = .getLineOfOffset(offset - 1);
		return .getLineDelimiter(line) == null;
	}
	/*
	 * @see IDocumentPartitioner#computePartitioning(int, int)
	 */

Since:
2.2
	public final ITypedRegion[] computePartitioning(int offsetint length) {
		return computePartitioning(offsetlengthfalse);
	}

May be replaced or extended by subclasses.

Since:
2.2
		return TextUtilities.copy();
	}

Returns whether the given type is one of the legal content types.

May be extended by subclasses.

Parameters:
contentType the content type to check
Returns:
true if the content type is a legal content type
Since:
2.2
	protected boolean isSupportedContentType(String contentType) {
		if (contentType != null) {
			for (int i = 0; i < .i++) {
				if ([i].equals(contentType))
					return true;
			}
		}
		return false;
	}

Returns a content type encoded in the given token. If the token's data is not null and a string it is assumed that it is the encoded content type.

May be replaced or extended by subclasses.

Parameters:
token the token whose content type is to be determined
Returns:
the token's content type
Since:
2.2
	protected String getTokenContentType(IToken token) {
		Object data = token.getData();
		if (data instanceof String)
			return (Stringdata;
		return null;
	}
	/* zero-length partition support */

May be replaced or extended by subclasses.

Since:
2.2
	public String getContentType(int offsetboolean preferOpenPartitions) {
		return getPartition(offsetpreferOpenPartitions).getType();
	}

May be replaced or extended by subclasses.

Since:
2.2
	public synchronized ITypedRegion getPartition(int offsetboolean preferOpenPartitions) {
		ITypedRegion region = getPartition(offset);
		if (preferOpenPartitions) {
			if (region.getOffset() == offset && !region.getType().equals(IDocument.DEFAULT_CONTENT_TYPE)) {
				if (offset > 0) {
					region = getPartition(offset - 1);
					if (region.getType().equals(IDocument.DEFAULT_CONTENT_TYPE))
						return region;
				}
				return new TypedRegion(offset, 0, IDocument.DEFAULT_CONTENT_TYPE);
			}
		}
		return region;
	}

May be replaced or extended by subclasses.

Since:
2.2
	public synchronized ITypedRegion[] computePartitioning(int offsetint lengthboolean includeZeroLengthPartitions) {
		List<ITypedRegion> list = new ArrayList<ITypedRegion>();
		try {
			int endOffset = offset + length;
			Position[] category = getPositions();
			TypedPosition previous = nullcurrent = null;
			int startendgapOffset;
			Position gap = new Position(0);
			int startIndex = getFirstIndexEndingAfterOffset(categoryoffset);
			int endIndex = getFirstIndexStartingAfterOffset(categoryendOffset);
			for (int i = startIndexi < endIndexi++) {
				current = (TypedPosition) category[i];
				gapOffset = (previous != null) ? previous.getOffset() + previous.getLength() : 0;
				gap.setOffset(gapOffset);
				gap.setLength(current.getOffset() - gapOffset);
				if ((includeZeroLengthPartitions && overlapsOrTouches(gapoffsetlength))
						|| (gap.getLength() > 0 && gap.overlapsWith(offsetlength))) {
					start = Math.max(offsetgapOffset);
					end = Math.min(endOffsetgap.getOffset() + gap.getLength());
					list.add(new TypedRegion(startend - start, IDocument.DEFAULT_CONTENT_TYPE));
				}
				if (current.overlapsWith(offsetlength)) {
					start = Math.max(offsetcurrent.getOffset());
					end = Math.min(endOffsetcurrent.getOffset() + current.getLength());
					list.add(new TypedRegion(startend - startcurrent.getType()));
				}
				previous = current;
			}
			if (previous != null) {
				gapOffset = previous.getOffset() + previous.getLength();
				gap.setOffset(gapOffset);
				int gapLength = .getLength() - gapOffset;
				if(gapLength < 0) {
					return new TypedRegion[0];
else {
					gap.setLength(gapLength);
					if ((includeZeroLengthPartitions && overlapsOrTouches(gapoffsetlength))
							|| (gap.getLength() > 0 && gap.overlapsWith(offsetlength))) {
						start = Math.max(offsetgapOffset);
						end = Math.min(endOffset.getLength());
						list.add(new TypedRegion(startend - start, IDocument.DEFAULT_CONTENT_TYPE));
					}
				}
			}
			if (list.isEmpty())
				list.add(new TypedRegion(offsetlength, IDocument.DEFAULT_CONTENT_TYPE));
catch (BadPositionCategoryException ex) {
			// Make sure we clear the cache
catch (RuntimeException ex) {
			// Make sure we clear the cache
			throw ex;
		}
		TypedRegion[] result = new TypedRegion[list.size()];
		list.toArray(result);
		return result;
	}

Returns true if the given ranges overlap with or touch each other.

Parameters:
gap the first range
offset the offset of the second range
length the length of the second range
Returns:
true if the given ranges overlap with or touch each other
	private boolean overlapsOrTouches(Position gapint offsetint length) {
		return gap.getOffset() <= offset + length && offset <= gap.getOffset() + gap.getLength();
	}

Returns the index of the first position which ends after the given offset.

Parameters:
positions the positions in linear order
offset the offset
Returns:
the index of the first position which ends after the offset
	private int getFirstIndexEndingAfterOffset(Position[] positionsint offset) {
		int i = -1, j = positions.length;
		while (j - i > 1) {
			int k = (i + j) >> 1;
			Position p = positions[k];
			if (p.getOffset() + p.getLength() > offset)
				j = k;
			else
				i = k;
		}
		return j;
	}

Returns the index of the first position which starts at or after the given offset.

Parameters:
positions the positions in linear order
offset the offset
Returns:
the index of the first position which starts after the offset
	private int getFirstIndexStartingAfterOffset(Position[] positionsint offset) {
		int i = -1, j = positions.length;
		while (j - i > 1) {
			int k = (i + j) >> 1;
			Position p = positions[k];
			if (p.getOffset() >= offset)
				j = k;
			else
				i = k;
		}
		return j;
	}
	/*
	 * @see org.eclipse.jface.text.IDocumentPartitionerExtension3#startRewriteSession(org.eclipse.jface.text.DocumentRewriteSession)
	 */

Since:
2.2
	public void startRewriteSession(DocumentRewriteSession sessionthrows IllegalStateException {
		if ( != null)
			throw new IllegalStateException();
	}

May be extended by subclasses.

Since:
2.2
	public void stopRewriteSession(DocumentRewriteSession session) {
		if ( == session)
	}

May be extended by subclasses.

Since:
2.2
	public DocumentRewriteSession getActiveRewriteSession() {
	}

Flushes the active rewrite session.

Since:
2.2
	protected synchronized final void flushRewriteSession() {
		// remove all position belonging to the partitioner position category
		try {
			.removePositionCategory();
catch (BadPositionCategoryException x) {
		}
		.addPositionCategory();
		 = false;
	}

Clears the position cache. Needs to be called whenever the positions have been updated.

Since:
2.2
	protected final void clearPositionCache() {
		if ( != null) {
		}
	}

Returns the partitioners positions.

Returns:
the partitioners positions
Throws:
BadPositionCategoryException if getting the positions from the document fails
Since:
2.2
	protected synchronized final Position[] getPositions() throws BadPositionCategoryException {
		if ( == null) {
else if () {
			Position[] positions = .getPositions();
			int len = Math.min(positions.length, .);
			for (int i = 0; i < leni++) {
				if (!positions[i].equals([i]))
							.println("FastPartitioner.getPositions(): cached position is not up to date: from document: " + toString(positions[i]) + " in cache: " + toString([i])); //$NON-NLS-1$ //$NON-NLS-2$
			}
			for (int i = leni < positions.length; i++)
						.println("FastPartitioner.getPositions(): new position in document: " + toString(positions[i])); //$NON-NLS-1$
			for (int i = leni < .i++)
						.println("FastPartitioner.getPositions(): stale position in cache: " + toString([i])); //$NON-NLS-1$
		}
	}

Pretty print a Position.

Parameters:
position the position to format
Returns:
a formatted string
	private String toString(Position position) {
		return "P[" + position.getOffset() + "+" + position.getLength() + "]"//$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
	}
New to GrepCode? Check out our FAQ X