blob: 985617b0ef8e9e95c6f0c608a4cbd27b420e702b [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2014, 2021 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.ecommons.text.core.treepartitioner;
import java.io.IOException;
import java.io.Writer;
import java.util.List;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.TextUtilities;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
import org.eclipse.statet.jcommons.text.core.BasicTextRegion;
import org.eclipse.statet.jcommons.text.core.TextRegion;
import org.eclipse.statet.ecommons.text.core.PartitionConstraint;
@NonNullByDefault
public class TreePartitionUtils {
public static class PartitionPrinter {
private final Writer writer;
private @Nullable IDocument document;
private int maxFragmentSize= 25;
public PartitionPrinter(final Writer writer) {
if (writer == null) {
throw new NullPointerException("writer"); //$NON-NLS-1$
}
this.writer= writer;
}
public void setMaxFragmentSize(final int size) {
this.maxFragmentSize= size;
}
public void print(final TreePartitionNode node, final IDocument document) throws IOException {
this.document= document;
try {
print(node, 0);
}
finally {
this.document= null;
}
}
public void print(final List<TreePartition> partitions, final IDocument document) throws IOException {
this.document= document;
try {
print(partitions);
}
finally {
this.document= null;
}
}
protected void print(final TreePartitionNode node, final int nodeDepth) throws IOException {
printIdent(nodeDepth);
final int startOffset= node.getStartOffset();
final int endOffset= node.getEndOffset();
this.writer.write('[');
this.writer.write(Integer.toString(startOffset));
this.writer.write(", "); //$NON-NLS-1$
this.writer.write(Integer.toString(endOffset));
this.writer.write(") "); //$NON-NLS-1$
this.writer.write(node.getType().toString());
printFragment(startOffset, endOffset);
this.writer.write('\n');
final int childCount= node.getChildCount();
for (int childIdx= 0; childIdx < childCount; childIdx++) {
print(node.getChild(childIdx), nodeDepth + 1);
}
}
protected void print(final List<TreePartition> partitions) throws IOException {
for (int i= 0; i < partitions.size(); i++) {
final TreePartition partition= partitions.get(i);
final int startOffset= partition.getOffset();
final int endOffset= partition.getEndOffset();
this.writer.write('[');
this.writer.write(Integer.toString(startOffset));
this.writer.write(", "); //$NON-NLS-1$
this.writer.write(Integer.toString(endOffset));
this.writer.write(") "); //$NON-NLS-1$
this.writer.write(partition.getType());
printFragment(startOffset, endOffset);
this.writer.append('\n');
}
}
protected void printIdent(final int depth) throws IOException {
for (int i= 0; i < depth; i++) {
this.writer.write(" "); //$NON-NLS-1$
}
}
protected void printFragment(final int startOffset, final int endOffset) throws IOException {
final IDocument document= this.document;
if (document != null && this.maxFragmentSize > 0) {
try {
this.writer.write(": "); //$NON-NLS-1$
int l= endOffset - startOffset;
if (l <= this.maxFragmentSize) {
writeEncoded(document.get(startOffset, l));
}
else if (this.maxFragmentSize < 13) {
writeEncoded(document.get(startOffset, this.maxFragmentSize - 3));
this.writer.write(" ... "); //$NON-NLS-1$
}
else {
l= (this.maxFragmentSize - 3) / 2;
writeEncoded(document.get(startOffset, l));
this.writer.write(" ... "); //$NON-NLS-1$
writeEncoded(document.get(endOffset - l, l));
}
}
catch (final BadLocationException e) {
this.writer.write("!!!ERROR!!!"); //$NON-NLS-1$
}
}
}
private void writeEncoded(final String s) throws IOException {
for (int i= 0; i < s.length(); i++) {
final int c= s.charAt(i);
if (c < 0x10) {
this.writer.write("<0x0"); //$NON-NLS-1$
this.writer.write(Integer.toHexString(c));
this.writer.write('>');
}
else if (c < 0x20) {
this.writer.write("<0x"); //$NON-NLS-1$
this.writer.write(Integer.toHexString(c));
this.writer.write('>');
}
else {
this.writer.write(c);
}
}
}
}
public final static TreePartitionNode getRootNode(final IDocument document, final String partitioning) {
try {
final TreePartition partition= (TreePartition) TextUtilities.getPartition(document, partitioning,
0, false );
TreePartitionNode node= partition.getTreeNode();
TreePartitionNode parent;
while ((parent= node.getParent()) != null) {
node= parent;
}
return node;
}
catch (final BadLocationException e) {
throw new IllegalStateException(e);
}
}
public final static @Nullable TreePartitionNode getNode(final IDocument document, final String partitioning,
final int offset, final boolean prefereOpen) throws BadLocationException {
final TreePartition partition= (TreePartition) TextUtilities.getPartition(document,
partitioning, offset, prefereOpen );
if (partition instanceof TreePartition) {
return partition.getTreeNode();
}
return null;
}
public final static @Nullable TreePartitionNode searchNodeUp(@Nullable TreePartitionNode node,
final TreePartitionNodeType type) {
while (node != null && type != node.getType()) {
node= node.getParent();
}
return node;
}
public final static @Nullable TreePartitionNode searchNodeUp(@Nullable TreePartitionNode node,
final String partitionType) {
while (node != null && partitionType != node.getType().getPartitionType()) {
node= node.getParent();
}
return node;
}
public final static @Nullable TreePartitionNode searchNodeUp(@Nullable TreePartitionNode node,
final PartitionConstraint partitionConstraint) {
while (node != null && !partitionConstraint.matches(node.getType().getPartitionType())) {
node= node.getParent();
}
return node;
}
public final static @Nullable TreePartitionNode searchNode(final IDocument document, final String partitioning,
final int offset, final boolean prefereOpen, final TreePartitionNodeType type)
throws BadLocationException {
final TreePartition partition= (TreePartition)TextUtilities.getPartition(document, partitioning,
offset, prefereOpen );
return searchNodeUp(partition.getTreeNode(), type);
}
public final static @Nullable TreePartitionNode searchNode(final IDocument document, final String partitioning,
final int offset, final boolean prefereOpen, final String partitionType)
throws BadLocationException {
final TreePartition partition= (TreePartition) TextUtilities.getPartition(document, partitioning,
offset, prefereOpen );
return searchNodeUp(partition.getTreeNode(), partitionType);
}
public final static @Nullable TreePartitionNode searchNode(final IDocument document, final String partitioning,
final int offset, final boolean prefereOpen, final PartitionConstraint partitionConstraint)
throws BadLocationException {
final TreePartition partition= (TreePartition) TextUtilities.getPartition(document, partitioning,
offset, prefereOpen );
return searchNodeUp(partition.getTreeNode(), partitionConstraint);
}
public final static @Nullable TextRegion searchPartitionRegion(final IDocument document, final String partitioning,
final int offset, final boolean prefereOpen, final PartitionConstraint partitionConstraint)
throws BadLocationException {
return searchPartitionRegion((TreePartition) TextUtilities.getPartition(document, partitioning,
offset, prefereOpen ), partitionConstraint );
}
public final static @Nullable TextRegion searchPartitionRegion(final TreePartition partition,
final PartitionConstraint partitionConstraint) {
if (partition == null) {
throw new NullPointerException("partition");
}
if (!partitionConstraint.matches(partition.getType())) {
return null;
}
final int begin= searchBegin(partition.getTreeNode(), partition.getOffset(), partitionConstraint);
final int end= searchEnd(partition.getTreeNode(), partition.getEndOffset(), partitionConstraint);
return new BasicTextRegion(begin, end);
}
private static int searchBegin(final TreePartitionNode node, final int offset,
final PartitionConstraint partitionConstraint) {
final int childCount= node.getChildCount();
int childIdx= node.indexOfChild(offset);
if (childIdx < 0) {
childIdx= -(childIdx + 1);
}
if (childIdx == childCount) {
childIdx--;
}
for (; childIdx >= 0; childIdx--) {
final TreePartitionNode child= node.getChild(childIdx);
if (!partitionConstraint.matches(child.getType().getPartitionType())) {
return child.getEndOffset();
}
final int stop= searchBeginChild(node, partitionConstraint);
if (stop >= 0) {
return stop;
}
}
final TreePartitionNode parent= node.getParent();
if (parent == null
|| !partitionConstraint.matches(parent.getType().getPartitionType())) {
return node.getStartOffset();
}
return searchBegin(parent, offset, partitionConstraint);
}
private static int searchBeginChild(final TreePartitionNode node,
final PartitionConstraint partitionConstraint) {
final int childCount= node.getChildCount();
for (int childIdx= childCount - 1; childIdx >= 0; childIdx--) {
final TreePartitionNode child= node.getChild(childIdx);
if (!partitionConstraint.matches(child.getType().getPartitionType())) {
return child.getEndOffset();
}
final int stop= searchBeginChild(child, partitionConstraint);
if (stop >= 0) {
return stop;
}
}
return -1;
}
private static int searchEnd(final TreePartitionNode node, final int offset,
final PartitionConstraint partitionConstraint) {
final int childCount= node.getChildCount();
int childIdx= (offset == node.getStartOffset()) ? 0 : node.indexOfChild(offset);
if (childIdx < 0) {
childIdx= -(childIdx + 1);
}
for (; childIdx < childCount; childIdx++) {
final TreePartitionNode child= node.getChild(childIdx);
if (!partitionConstraint.matches(child.getType().getPartitionType())) {
return child.getStartOffset();
}
final int stop= searchEndChild(node, partitionConstraint);
if (stop >= 0) {
return stop;
}
}
final TreePartitionNode parent= node.getParent();
if (parent == null
|| !partitionConstraint.matches(parent.getType().getPartitionType())) {
return node.getEndOffset();
}
return searchEnd(parent, offset, partitionConstraint);
}
private static int searchEndChild(final TreePartitionNode node,
final PartitionConstraint partitionConstraint) {
final int childCount= node.getChildCount();
for (int childIdx= 0; childIdx < childCount; childIdx++) {
final TreePartitionNode child= node.getChild(childIdx);
if (!partitionConstraint.matches(child.getType().getPartitionType())) {
return child.getStartOffset();
}
final int stop= searchEndChild(child, partitionConstraint);
if (stop >= 0) {
return stop;
}
}
return -1;
}
private TreePartitionUtils() {}
}