* Contributors:
* Igor Malinin - initial contribution
*
- * $Id: AbstractPartitioner.java,v 1.3 2004-12-29 21:42:31 axelcl Exp $
+ * $Id: AbstractPartitioner.java,v 1.4 2006-10-21 23:13:53 pombredanne Exp $
*/
package net.sourceforge.phpeclipse.ui.text.rules;
import org.eclipse.jface.text.rules.IToken;
/**
- * Advanced partitioner which maintains partitions as views to connected document. Views have own partitioners themselves. This
- * class is designed as a base for complex partitioners such as for JSP, PHP, ASP, etc. languages.
+ * Advanced partitioner which maintains partitions as views to connected
+ * document. Views have own partitioners themselves. This class is designed as a
+ * base for complex partitioners such as for JSP, PHP, ASP, etc. languages.
*
* @author Igor Malinin
*/
-public abstract class AbstractPartitioner implements IDocumentPartitioner, IDocumentPartitionerExtension {
- public final static boolean DEBUG = false;
-
- /** Partition scanner */
- protected IPartitionTokenScanner scanner;
-
- /** Connected document */
- protected IDocument document;
-
- /** Flat structure of the document */
- protected List nodes = new ArrayList();
-
- /** The offset at which the first changed partition starts */
- protected int regionStart;
-
- /** The offset at which the last changed partition ends */
- protected int regionEnd;
-
- public AbstractPartitioner(IPartitionTokenScanner scanner) {
- this.scanner = scanner;
- }
-
- protected FlatNode createNode(String type, int offset, int length) {
- if (DEBUG) {
- Assert.isTrue(offset >= 0, Integer.toString(offset));
- }
- FlatNode node = new FlatNode(type);
- node.offset = offset;
- node.length = length;
- return node;
- }
-
- protected void addInnerRegion(FlatNode position) {
- nodes.add(computeFlatNodeIndex(position.offset), position);
- }
-
- protected void removeInnerRegion(FlatNode position) {
- nodes.remove(position); // TODO: Indexed remove?
- }
-
- protected void deleteInnerRegion(FlatNode position) {
- nodes.remove(position); // TODO: Indexed remove?
- }
-
- protected void resizeInnerRegion(FlatNode position) {
- }
-
- /*
- * @see org.eclipse.jface.text.IDocumentPartitioner#connect(IDocument)
- */
- public void connect(IDocument document) {
- this.document = document;
-
- initialize();
- }
-
- /*
- * @see org.eclipse.jface.text.IDocumentPartitioner#disconnect()
- */
- public void disconnect() {
- nodes.clear();
- document = null;
- }
-
- /**
- * Performs the initial partitioning of the partitioner's document.
- */
- protected void initialize() {
- scanner.setRange(document, 0, document.getLength());
- // axelcl start
- nodes.clear();
- // axelcl end
- IToken token = scanner.nextToken();
- while (!token.isEOF()) {
- String contentType = getTokenContentType(token);
-
- if (isSupportedContentType(contentType)) {
- addInnerRegion(createNode(contentType, scanner.getTokenOffset(), scanner.getTokenLength()));
- }
-
- token = scanner.nextToken();
- }
- }
-
- /*
- * @see org.eclipse.jface.text.IDocumentPartitioner#documentAboutToBeChanged(DocumentEvent)
- */
- public void documentAboutToBeChanged(DocumentEvent event) {
- regionStart = regionEnd = -1;
- }
-
- /*
- * @see org.eclipse.jface.text.IDocumentPartitioner#documentChanged(DocumentEvent)
- */
- public boolean documentChanged(DocumentEvent event) {
- return (documentChanged2(event) != null);
- }
-
- /*
- * @see org.eclipse.jface.text.IDocumentPartitionerExtension#documentChanged2(DocumentEvent)
- */
- public IRegion documentChanged2(DocumentEvent event) {
- int first = fixupPartitions(event);
-
- FlatNode[] category = (FlatNode[]) nodes.toArray(new FlatNode[nodes.size()]);
-
- // repartition changed region
-
- String contentType = IDocument.DEFAULT_CONTENT_TYPE;
-
- int offset;
-
- if (first == 0) {
- offset = 0; // Bug #697414: first offset
- } else {
- offset = event.getOffset();
-
- FlatNode partition = category[first - 1];
- if (partition.includes(offset)) {
- offset = partition.offset;
- contentType = partition.type;
- --first;
- } else if (offset == partition.offset + partition.length) {
- offset = partition.offset;
- contentType = partition.type;
- --first;
- } else {
- offset = partition.offset + partition.length;
- }
- }
-
- // should not be changed since last conversion
- // category = (FlatNode[]) nodes.toArray(new FlatNode[nodes.size()]);
- if (DEBUG) {
- Assert.isTrue(offset >= 0, Integer.toString(offset));
- }
- scanner.setPartialRange(document, offset, document.getLength(), contentType, offset);
-
- int lastScannedPosition = offset;
- IToken token = scanner.nextToken();
- while (!token.isEOF()) {
- contentType = getTokenContentType(token);
-
- if (!isSupportedContentType(contentType)) {
- token = scanner.nextToken();
- continue;
- }
-
- offset = scanner.getTokenOffset();
- if (DEBUG) {
- Assert.isTrue(offset >= 0, scanner.toString());
- }
- int length = scanner.getTokenLength();
-
- lastScannedPosition = offset + length;
-
- // remove all affected positions
- while (first < category.length) {
- FlatNode p = category[first];
- if (p.offset + p.length < lastScannedPosition
- || (p.overlapsWith(offset, length) && (!containsPosition(offset, length) || !contentType.equals(p.type)))) {
- removeInnerRegion(p);
- rememberRegion(p.offset, p.length);
- ++first;
- } else {
- break;
- }
- }
-
- // if position already exists we are done
- if (containsPosition(offset, length)) {
- if (lastScannedPosition > event.getOffset()) {
- // TODO: optional repartition till end of doc
- return createRegion();
- }
-
- ++first;
- } else {
- // insert the new type position
- addInnerRegion(createNode(contentType, offset, length));
- rememberRegion(offset, length);
- }
- // try {
- token = scanner.nextToken();
- // } catch (ArrayIndexOutOfBoundsException e) {
- // System.out.println(this.getClass().toString());
- // throw e;
- // }
- }
-
- // remove all positions behind lastScannedPosition
- // since there aren't any further types
-
- // Do not need to recalculate (lost remove events)!
- // first = computeIndexInInnerDocuments(lastScannedPosition);
- while (first < category.length) {
- FlatNode p = category[first++];
- removeInnerRegion(p);
- rememberRegion(p.offset, p.length);
- }
-
- return createRegion();
- }
-
- protected int fixupPartitions(DocumentEvent event) {
- int offset = event.getOffset();
- int length = event.getLength();
- int end = offset + length;
-
- // fixup flat nodes laying on change boundaries
-
- int first = computeFlatNodeIndex(offset);
- if (first > 0) {
- FlatNode p = (FlatNode) nodes.get(first - 1);
-
- int right = p.offset + p.length;
- if (offset < right) {
- // change overlaps with partition
- if (end < right) {
- // cahnge completely inside partition
- String text = event.getText();
- p.length -= length;
- if (text != null) {
- p.length += text.length();
- }
- } else {
- // cut partition at right
- int cut = p.offset + p.length - offset;
- p.length -= cut;
- }
- }
- }
-
- int last = computeFlatNodeIndex(end);
- if (first < last) {
- FlatNode p = (FlatNode) nodes.get(last - 1);
-
- int right = p.offset + p.length;
- if (end < right) {
- // cut partition at left
- int cut = end - p.offset;
- p.length -= cut;
- p.offset = offset;
-
- String text = event.getText();
- if (text != null) {
- p.offset += text.length();
- }
-
- --last;
- }
- }
-
- // fixup flat nodes laying afrer change
-
- String text = event.getText();
- if (text != null) {
- length -= text.length();
- }
-
- for (int i = last, size = nodes.size(); i < size; i++) {
- ((FlatNode) nodes.get(i)).offset -= length;
- }
-
- // delete flat nodes laying completely inside change boundaries
-
- if (first < last) {
- do {
- deleteInnerRegion((FlatNode) nodes.get(--last));
- } while (first < last);
-
- rememberRegion(offset, 0);
- }
-
- return first;
- }
-
- /**
- * Returns whether the given type is one of the legal content types.
- *
- * @param contentType
- * the content type to check
- * @return <code>true</code> if the content type is a legal content type
- */
- protected boolean isSupportedContentType(String contentType) {
- /* TODO: implementation */
- // if (contentType != null) {
- // for (int i= 0; i < fLegalContentTypes.length; i++) {
- // if (fLegalContentTypes[i].equals(contentType)) {
- // return true;
- // }
- // }
- // }
- // return false;
- return (contentType != null);
- }
-
- /**
- * Returns a content type encoded in the given token. If the token's data is not <code>null</code> and a string it is assumed
- * that it is the encoded content type.
- *
- * @param token
- * the token whose content type is to be determined
- * @return the token's content type
- */
- protected String getTokenContentType(IToken token) {
- Object data = token.getData();
- if (data instanceof String) {
- return (String) data;
- }
-
- return null;
- }
-
- /*
- * @see org.eclipse.jface.text.IDocumentPartitioner#getLegalContentTypes()
- */
- public String[] getLegalContentTypes() {
- // TODO: implementation
- return null;
- }
-
- /*
- * @see org.eclipse.jface.text.IDocumentPartitioner#getContentType(int)
- */
- public String getContentType(int offset) {
- return getPartition(offset).getType();
- }
-
- /*
- * @see org.eclipse.jface.text.IDocumentPartitioner#getPartition(int)
- */
- public ITypedRegion getPartition(int offset) {
- if (nodes.size() == 0) {
- return new TypedRegion(0, document.getLength(), IDocument.DEFAULT_CONTENT_TYPE);
- }
-
- int index = computeFlatNodeIndex(offset);
- if (index < nodes.size()) {
- FlatNode next = (FlatNode) nodes.get(index);
-
- if (offset == next.offset) {
- return new TypedRegion(next.offset, next.length, next.type);
- }
-
- if (index == 0) {
- return new TypedRegion(0, next.offset, IDocument.DEFAULT_CONTENT_TYPE);
- }
-
- FlatNode prev = (FlatNode) nodes.get(index - 1);
-
- if (prev.includes(offset)) {
- return new TypedRegion(prev.offset, prev.length, prev.type);
- }
-
- int end = prev.offset + prev.length;
- return new TypedRegion(end, next.offset - end, IDocument.DEFAULT_CONTENT_TYPE);
- }
-
- FlatNode prev = (FlatNode) nodes.get(nodes.size() - 1);
-
- if (prev.includes(offset)) {
- return new TypedRegion(prev.offset, prev.length, prev.type);
- }
-
- int end = prev.offset + prev.length;
-
- return new TypedRegion(end, document.getLength() - end, IDocument.DEFAULT_CONTENT_TYPE);
- }
-
- /*
- * @see org.eclipse.jface.text.IDocumentPartitioner#computePartitioning(int, int)
- */
- public ITypedRegion[] computePartitioning(int offset, int length) {
- List list = new ArrayList();
-
- int end = offset + length;
-
- int index = computeFlatNodeIndex(offset);
- while (true) {
- FlatNode prev = (index > 0) ? (FlatNode) nodes.get(index - 1) : null;
-
- if (prev != null) {
- if (prev.overlapsWith(offset, length)) {
- list.add(new TypedRegion(prev.offset, prev.length, prev.type));
- }
-
- if (end <= prev.offset + prev.length) {
- break;
- }
- }
-
- FlatNode next = (index < nodes.size()) ? (FlatNode) nodes.get(index) : null;
-
- if (next == null || offset < next.offset) {
- int off0 = offset;
- int off1 = offset + length;
-
- if (prev != null && off0 < prev.offset + prev.length) {
- off0 = prev.offset + prev.length;
- }
-
- if (next != null && next.offset < off1) {
- off1 = next.offset;
- }
-
- if (off0 < off1) {
- list.add(new TypedRegion(off0, off1 - off0, IDocument.DEFAULT_CONTENT_TYPE));
- }
- }
-
- if (next == null) {
- break;
- }
-
- ++index;
- }
-
- return (TypedRegion[]) list.toArray(new TypedRegion[list.size()]);
- }
-
- /**
- * Computes the index in the list of flat nodes at which an flat node with the given offset would be inserted. The flat node is
- * supposed to become the first in this list of all flat nodes with the same offset.
- *
- * @param offset
- * the offset for which the index is computed
- * @return the computed index
- */
- protected int computeFlatNodeIndex(int offset) {
- if (nodes.size() == 0) {
- return 0;
- }
-
- int left = 0, mid = 0;
- int right = nodes.size() - 1;
-
- FlatNode p = null;
-
- while (left < right) {
- mid = (left + right) / 2;
-
- p = (FlatNode) nodes.get(mid);
-
- if (offset < p.offset) {
- right = (left == mid) ? left : mid - 1;
- } else if (offset > p.offset) {
- left = (right == mid) ? right : mid + 1;
- } else if (offset == p.offset) {
- left = right = mid;
- }
- }
-
- int pos = left;
- p = (FlatNode) nodes.get(pos);
- if (offset > p.offset) {
- // append to the end
- pos++;
- } else {
- // entry will became the first of all entries with the same offset
- do {
- --pos;
- if (pos < 0) {
- break;
- }
- p = (FlatNode) nodes.get(pos);
- } while (offset == p.offset);
- ++pos;
- }
-
- return pos;
- }
-
- public boolean containsPosition(int offset, int length) {
- int size = nodes.size();
- if (size == 0) {
- return false;
- }
-
- int index = computeFlatNodeIndex(offset);
- if (index < size) {
- FlatNode p = (FlatNode) nodes.get(index);
-
- while (p.offset == offset) {
- if (p.length == length) {
- return true;
- }
-
- if (++index < size) {
- p = (FlatNode) nodes.get(index);
- } else {
- break;
- }
- }
- }
-
- return false;
- }
-
- /**
- * Helper method for tracking the minimal region containg all partition changes. If <code>offset</code> is smaller than the
- * remembered offset, <code>offset</code> will from now on be remembered. If <code>offset + length</code> is greater than the
- * remembered end offset, it will be remembered from now on.
- *
- * @param offset
- * the offset
- * @param length
- * the length
- */
- protected final void rememberRegion(int offset, int length) {
- // remember start offset
- if (regionStart == -1) {
- regionStart = offset;
- } else if (offset < regionStart) {
- regionStart = offset;
- }
-
- // remember end offset
- int endOffset = offset + length;
-
- if (regionEnd == -1) {
- regionEnd = endOffset;
- } else if (endOffset > regionEnd) {
- regionEnd = endOffset;
- }
- }
-
- /**
- * Creates the minimal region containing all partition changes using the remembered offsets.
- *
- * @return the minimal region containing all the partition changes
- */
- protected final IRegion createRegion() {
- if (regionStart == -1 || regionEnd == -1) {
- return null;
- }
-
- return new Region(regionStart, regionEnd - regionStart);
- }
+public abstract class AbstractPartitioner implements IDocumentPartitioner,
+ IDocumentPartitionerExtension {
+ public final static boolean DEBUG = false;
+
+ /** Partition scanner */
+ protected IPartitionTokenScanner scanner;
+
+ /** Connected document */
+ protected IDocument document;
+
+ /** Flat structure of the document */
+ protected List nodes = new ArrayList();
+
+ /** The offset at which the first changed partition starts */
+ protected int regionStart;
+
+ /** The offset at which the last changed partition ends */
+ protected int regionEnd;
+
+ public AbstractPartitioner(IPartitionTokenScanner scanner) {
+ this.scanner = scanner;
+ }
+
+ protected FlatNode createNode(String type, int offset, int length) {
+ if (DEBUG) {
+ Assert.isTrue(offset >= 0, Integer.toString(offset));
+ }
+ FlatNode node = new FlatNode(type);
+ node.offset = offset;
+ node.length = length;
+ return node;
+ }
+
+ protected void addInnerRegion(FlatNode position) {
+ nodes.add(computeFlatNodeIndex(position.offset), position);
+ }
+
+ protected void removeInnerRegion(FlatNode position) {
+ nodes.remove(position); // TODO: Indexed remove?
+ }
+
+ protected void deleteInnerRegion(FlatNode position) {
+ nodes.remove(position); // TODO: Indexed remove?
+ }
+
+ protected void resizeInnerRegion(FlatNode position) {
+ }
+
+ /*
+ * @see org.eclipse.jface.text.IDocumentPartitioner#connect(IDocument)
+ */
+ public void connect(IDocument document) {
+ this.document = document;
+
+ initialize();
+ }
+
+ /*
+ * @see org.eclipse.jface.text.IDocumentPartitioner#disconnect()
+ */
+ public void disconnect() {
+ nodes.clear();
+ document = null;
+ }
+
+ /**
+ * Performs the initial partitioning of the partitioner's document.
+ */
+ protected void initialize() {
+ scanner.setRange(document, 0, document.getLength());
+ // axelcl start
+ nodes.clear();
+ // axelcl end
+ IToken token = scanner.nextToken();
+ while (!token.isEOF()) {
+ String contentType = getTokenContentType(token);
+
+ if (isSupportedContentType(contentType)) {
+ addInnerRegion(createNode(contentType,
+ scanner.getTokenOffset(), scanner.getTokenLength()));
+ }
+
+ token = scanner.nextToken();
+ }
+ }
+
+ /*
+ * @see org.eclipse.jface.text.IDocumentPartitioner#documentAboutToBeChanged(DocumentEvent)
+ */
+ public void documentAboutToBeChanged(DocumentEvent event) {
+ regionStart = regionEnd = -1;
+ }
+
+ /*
+ * @see org.eclipse.jface.text.IDocumentPartitioner#documentChanged(DocumentEvent)
+ */
+ public boolean documentChanged(DocumentEvent event) {
+ return (documentChanged2(event) != null);
+ }
+
+ /*
+ * @see org.eclipse.jface.text.IDocumentPartitionerExtension#documentChanged2(DocumentEvent)
+ */
+ public IRegion documentChanged2(DocumentEvent event) {
+ int first = fixupPartitions(event);
+
+ FlatNode[] category = (FlatNode[]) nodes.toArray(new FlatNode[nodes
+ .size()]);
+
+ // repartition changed region
+
+ String contentType = IDocument.DEFAULT_CONTENT_TYPE;
+
+ int offset;
+
+ if (first == 0) {
+ offset = 0; // Bug #697414: first offset
+ } else {
+ offset = event.getOffset();
+
+ FlatNode partition = category[first - 1];
+ if (partition.includes(offset)) {
+ offset = partition.offset;
+ contentType = partition.type;
+ --first;
+ } else if (offset == partition.offset + partition.length) {
+ offset = partition.offset;
+ contentType = partition.type;
+ --first;
+ } else {
+ offset = partition.offset + partition.length;
+ }
+ }
+
+ // should not be changed since last conversion
+ // category = (FlatNode[]) nodes.toArray(new FlatNode[nodes.size()]);
+ if (DEBUG) {
+ Assert.isTrue(offset >= 0, Integer.toString(offset));
+ }
+ scanner.setPartialRange(document, offset, document.getLength(),
+ contentType, offset);
+
+ int lastScannedPosition = offset;
+ IToken token = scanner.nextToken();
+ while (!token.isEOF()) {
+ contentType = getTokenContentType(token);
+
+ if (!isSupportedContentType(contentType)) {
+ token = scanner.nextToken();
+ continue;
+ }
+
+ offset = scanner.getTokenOffset();
+ if (DEBUG) {
+ Assert.isTrue(offset >= 0, scanner.toString());
+ }
+ int length = scanner.getTokenLength();
+
+ lastScannedPosition = offset + length;
+
+ // remove all affected positions
+ while (first < category.length) {
+ FlatNode p = category[first];
+ if (p.offset + p.length < lastScannedPosition
+ || (p.overlapsWith(offset, length) && (!containsPosition(
+ offset, length) || !contentType.equals(p.type)))) {
+ removeInnerRegion(p);
+ rememberRegion(p.offset, p.length);
+ ++first;
+ } else {
+ break;
+ }
+ }
+
+ // if position already exists we are done
+ if (containsPosition(offset, length)) {
+ if (lastScannedPosition > event.getOffset()) {
+ // TODO: optional repartition till end of doc
+ return createRegion();
+ }
+
+ ++first;
+ } else {
+ // insert the new type position
+ addInnerRegion(createNode(contentType, offset, length));
+ rememberRegion(offset, length);
+ }
+ // try {
+ token = scanner.nextToken();
+ // } catch (ArrayIndexOutOfBoundsException e) {
+ // System.out.println(this.getClass().toString());
+ // throw e;
+ // }
+ }
+
+ // remove all positions behind lastScannedPosition
+ // since there aren't any further types
+
+ // Do not need to recalculate (lost remove events)!
+ // first = computeIndexInInnerDocuments(lastScannedPosition);
+ while (first < category.length) {
+ FlatNode p = category[first++];
+ removeInnerRegion(p);
+ rememberRegion(p.offset, p.length);
+ }
+
+ return createRegion();
+ }
+
+ protected int fixupPartitions(DocumentEvent event) {
+ int offset = event.getOffset();
+ int length = event.getLength();
+ int end = offset + length;
+
+ // fixup flat nodes laying on change boundaries
+
+ int first = computeFlatNodeIndex(offset);
+ if (first > 0) {
+ FlatNode p = (FlatNode) nodes.get(first - 1);
+
+ int right = p.offset + p.length;
+ if (offset < right) {
+ // change overlaps with partition
+ if (end < right) {
+ // cahnge completely inside partition
+ String text = event.getText();
+ p.length -= length;
+ if (text != null) {
+ p.length += text.length();
+ }
+ } else {
+ // cut partition at right
+ int cut = p.offset + p.length - offset;
+ p.length -= cut;
+ }
+ }
+ }
+
+ int last = computeFlatNodeIndex(end);
+ if (first < last) {
+ FlatNode p = (FlatNode) nodes.get(last - 1);
+
+ int right = p.offset + p.length;
+ if (end < right) {
+ // cut partition at left
+ int cut = end - p.offset;
+ p.length -= cut;
+ p.offset = offset;
+
+ String text = event.getText();
+ if (text != null) {
+ p.offset += text.length();
+ }
+
+ --last;
+ }
+ }
+
+ // fixup flat nodes laying afrer change
+
+ String text = event.getText();
+ if (text != null) {
+ length -= text.length();
+ }
+
+ for (int i = last, size = nodes.size(); i < size; i++) {
+ ((FlatNode) nodes.get(i)).offset -= length;
+ }
+
+ // delete flat nodes laying completely inside change boundaries
+
+ if (first < last) {
+ do {
+ deleteInnerRegion((FlatNode) nodes.get(--last));
+ } while (first < last);
+
+ rememberRegion(offset, 0);
+ }
+
+ return first;
+ }
+
+ /**
+ * Returns whether the given type is one of the legal content types.
+ *
+ * @param contentType
+ * the content type to check
+ * @return <code>true</code> if the content type is a legal content type
+ */
+ protected boolean isSupportedContentType(String contentType) {
+ /* TODO: implementation */
+ // if (contentType != null) {
+ // for (int i= 0; i < fLegalContentTypes.length; i++) {
+ // if (fLegalContentTypes[i].equals(contentType)) {
+ // return true;
+ // }
+ // }
+ // }
+ // return false;
+ return (contentType != null);
+ }
+
+ /**
+ * Returns a content type encoded in the given token. If the token's data is
+ * not <code>null</code> and a string it is assumed that it is the encoded
+ * content type.
+ *
+ * @param token
+ * the token whose content type is to be determined
+ * @return the token's content type
+ */
+ protected String getTokenContentType(IToken token) {
+ Object data = token.getData();
+ if (data instanceof String) {
+ return (String) data;
+ }
+
+ return null;
+ }
+
+ /*
+ * @see org.eclipse.jface.text.IDocumentPartitioner#getLegalContentTypes()
+ */
+ public String[] getLegalContentTypes() {
+ // TODO: implementation
+ return null;
+ }
+
+ /*
+ * @see org.eclipse.jface.text.IDocumentPartitioner#getContentType(int)
+ */
+ public String getContentType(int offset) {
+ return getPartition(offset).getType();
+ }
+
+ /*
+ * @see org.eclipse.jface.text.IDocumentPartitioner#getPartition(int)
+ */
+ public ITypedRegion getPartition(int offset) {
+ if (nodes.size() == 0) {
+ return new TypedRegion(0, document.getLength(),
+ IDocument.DEFAULT_CONTENT_TYPE);
+ }
+
+ int index = computeFlatNodeIndex(offset);
+ if (index < nodes.size()) {
+ FlatNode next = (FlatNode) nodes.get(index);
+
+ if (offset == next.offset) {
+ return new TypedRegion(next.offset, next.length, next.type);
+ }
+
+ if (index == 0) {
+ return new TypedRegion(0, next.offset,
+ IDocument.DEFAULT_CONTENT_TYPE);
+ }
+
+ FlatNode prev = (FlatNode) nodes.get(index - 1);
+
+ if (prev.includes(offset)) {
+ return new TypedRegion(prev.offset, prev.length, prev.type);
+ }
+
+ int end = prev.offset + prev.length;
+ return new TypedRegion(end, next.offset - end,
+ IDocument.DEFAULT_CONTENT_TYPE);
+ }
+
+ FlatNode prev = (FlatNode) nodes.get(nodes.size() - 1);
+
+ if (prev.includes(offset)) {
+ return new TypedRegion(prev.offset, prev.length, prev.type);
+ }
+
+ int end = prev.offset + prev.length;
+
+ return new TypedRegion(end, document.getLength() - end,
+ IDocument.DEFAULT_CONTENT_TYPE);
+ }
+
+ /*
+ * @see org.eclipse.jface.text.IDocumentPartitioner#computePartitioning(int,
+ * int)
+ */
+ public ITypedRegion[] computePartitioning(int offset, int length) {
+ List list = new ArrayList();
+
+ int end = offset + length;
+
+ int index = computeFlatNodeIndex(offset);
+ while (true) {
+ FlatNode prev = (index > 0) ? (FlatNode) nodes.get(index - 1)
+ : null;
+
+ if (prev != null) {
+ if (prev.overlapsWith(offset, length)) {
+ list.add(new TypedRegion(prev.offset, prev.length,
+ prev.type));
+ }
+
+ if (end <= prev.offset + prev.length) {
+ break;
+ }
+ }
+
+ FlatNode next = (index < nodes.size()) ? (FlatNode) nodes
+ .get(index) : null;
+
+ if (next == null || offset < next.offset) {
+ int off0 = offset;
+ int off1 = offset + length;
+
+ if (prev != null && off0 < prev.offset + prev.length) {
+ off0 = prev.offset + prev.length;
+ }
+
+ if (next != null && next.offset < off1) {
+ off1 = next.offset;
+ }
+
+ if (off0 < off1) {
+ list.add(new TypedRegion(off0, off1 - off0,
+ IDocument.DEFAULT_CONTENT_TYPE));
+ }
+ }
+
+ if (next == null) {
+ break;
+ }
+
+ ++index;
+ }
+
+ return (TypedRegion[]) list.toArray(new TypedRegion[list.size()]);
+ }
+
+ /**
+ * Computes the index in the list of flat nodes at which an flat node with
+ * the given offset would be inserted. The flat node is supposed to become
+ * the first in this list of all flat nodes with the same offset.
+ *
+ * @param offset
+ * the offset for which the index is computed
+ * @return the computed index
+ */
+ protected int computeFlatNodeIndex(int offset) {
+ if (nodes.size() == 0) {
+ return 0;
+ }
+
+ int left = 0, mid = 0;
+ int right = nodes.size() - 1;
+
+ FlatNode p = null;
+
+ while (left < right) {
+ mid = (left + right) / 2;
+
+ p = (FlatNode) nodes.get(mid);
+
+ if (offset < p.offset) {
+ right = (left == mid) ? left : mid - 1;
+ } else if (offset > p.offset) {
+ left = (right == mid) ? right : mid + 1;
+ } else if (offset == p.offset) {
+ left = right = mid;
+ }
+ }
+
+ int pos = left;
+ p = (FlatNode) nodes.get(pos);
+ if (offset > p.offset) {
+ // append to the end
+ pos++;
+ } else {
+ // entry will became the first of all entries with the same offset
+ do {
+ --pos;
+ if (pos < 0) {
+ break;
+ }
+ p = (FlatNode) nodes.get(pos);
+ } while (offset == p.offset);
+ ++pos;
+ }
+
+ return pos;
+ }
+
+ public boolean containsPosition(int offset, int length) {
+ int size = nodes.size();
+ if (size == 0) {
+ return false;
+ }
+
+ int index = computeFlatNodeIndex(offset);
+ if (index < size) {
+ FlatNode p = (FlatNode) nodes.get(index);
+
+ while (p.offset == offset) {
+ if (p.length == length) {
+ return true;
+ }
+
+ if (++index < size) {
+ p = (FlatNode) nodes.get(index);
+ } else {
+ break;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Helper method for tracking the minimal region containg all partition
+ * changes. If <code>offset</code> is smaller than the remembered offset,
+ * <code>offset</code> will from now on be remembered. If
+ * <code>offset + length</code> is greater than the remembered end offset,
+ * it will be remembered from now on.
+ *
+ * @param offset
+ * the offset
+ * @param length
+ * the length
+ */
+ protected final void rememberRegion(int offset, int length) {
+ // remember start offset
+ if (regionStart == -1) {
+ regionStart = offset;
+ } else if (offset < regionStart) {
+ regionStart = offset;
+ }
+
+ // remember end offset
+ int endOffset = offset + length;
+
+ if (regionEnd == -1) {
+ regionEnd = endOffset;
+ } else if (endOffset > regionEnd) {
+ regionEnd = endOffset;
+ }
+ }
+
+ /**
+ * Creates the minimal region containing all partition changes using the
+ * remembered offsets.
+ *
+ * @return the minimal region containing all the partition changes
+ */
+ protected final IRegion createRegion() {
+ if (regionStart == -1 || regionEnd == -1) {
+ return null;
+ }
+
+ return new Region(regionStart, regionEnd - regionStart);
+ }
}
\ No newline at end of file