blob: 91f868ff7f196e1106de13095b5da5fe832dc531 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2009, 2019 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.docmlet.tex.core.source;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.BadPartitioningException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentPartitioner;
import org.eclipse.jface.text.ITypedRegion;
import org.eclipse.statet.ecommons.text.BasicHeuristicTokenScanner;
import org.eclipse.statet.ecommons.text.core.PartitionConstraint;
import org.eclipse.statet.ecommons.text.core.sections.DocContentSections;
public class LtxHeuristicTokenScanner extends BasicHeuristicTokenScanner {
public static final int CURLY_BRACKET_TYPE= 0;
public static final int SQUARE_BRACKET_TYPE= 1;
public static final int PARATHESIS_TYPE= 2;
public static int getBracketType(final char c) {
switch (c) {
case '{':
case '}':
return CURLY_BRACKET_TYPE;
case '[':
case ']':
return SQUARE_BRACKET_TYPE;
case '(':
case ')':
return PARATHESIS_TYPE;
default:
throw new IllegalArgumentException();
}
}
public static boolean isEscaped(final IDocument document, int offset)
throws BadLocationException {
boolean escaped= false;
while (offset > 0 && document.getChar(--offset) == '\\') {
escaped= !escaped;
}
return escaped;
}
public static int getSafeMathPartitionOffset(final IDocumentPartitioner partitioner, int offset) throws BadLocationException, BadPartitioningException {
int startOffset= offset;
while (offset > 0) {
final ITypedRegion partition= partitioner.getPartition(offset - 1);
final String partitionType= partition.getType();
if (partitionType == TexDocumentConstants.LTX_DEFAULT_CONTENT_TYPE
|| partitionType == TexDocumentConstants.LTX_COMMENT_CONTENT_TYPE
|| partitionType == TexDocumentConstants.LTX_VERBATIM_CONTENT_TYPE) {
return startOffset;
}
if (partitionType == TexDocumentConstants.LTX_MATH_CONTENT_TYPE) {
offset= startOffset= partition.getOffset();
continue;
}
offset= partition.getOffset();
continue;
}
return startOffset;
}
private class BracketBalanceCondition extends PartitionBasedCondition {
private int type;
private boolean open;
@Override
protected boolean matchesChar() {
switch (LtxHeuristicTokenScanner.this.ch) {
case '{':
this.type= CURLY_BRACKET_TYPE;
this.open= true;
return true;
case '}':
this.type= CURLY_BRACKET_TYPE;
this.open= false;
return true;
case '[':
this.type= SQUARE_BRACKET_TYPE;
this.open= true;
return true;
case ']':
this.type= SQUARE_BRACKET_TYPE;
this.open= false;
return true;
case '(':
this.type= PARATHESIS_TYPE;
this.open= true;
return true;
case ')':
this.type= PARATHESIS_TYPE;
this.open= false;
this.open= false;
return true;
}
return false;
}
}
public static LtxHeuristicTokenScanner create(final DocContentSections documentContentInfo) {
return (documentContentInfo.getPrimaryType() == TexDocumentConstants.LTX_PARTITIONING) ?
new LtxHeuristicTokenScanner(documentContentInfo) :
new LtxChunkHeuristicTokenScanner(documentContentInfo);
}
protected LtxHeuristicTokenScanner(final DocContentSections documentContentInfo) {
super(documentContentInfo, TexDocumentConstants.LTX_DEFAULT_CONTENT_CONSTRAINT);
}
@Override
public void configure(final IDocument document, final String partitionType) {
if (partitionType == TexDocumentConstants.LTX_MATH_CONTENT_TYPE) {
super.configure(document, new PartitionConstraint() {
private boolean never;
@Override
public boolean matches(final String partitionType) {
if (this.never) {
return false;
}
if (partitionType == TexDocumentConstants.LTX_MATH_CONTENT_TYPE) {
return true;
}
if (getDefaultPartitionConstraint().matches(partitionType)) {
this.never= true;
}
return false;
}
});
return;
}
super.configure(document, partitionType);
}
// @Override
// protected int createForwardBound(final int start) throws BadLocationException {
// final PartitionConstraint matcher= getPartitionConstraint();
// if (matcher.matches(TexDocumentConstants.LTX_DEFAULT_CONTENT_TYPE)) {
// return UNBOUND;
// }
// final ITypedRegion partition= TextUtilities.getPartition(document, getPartitioning(), start, false);
// return partition.getOffset()+partition.getLength();
// }
//
// @Override
// protected int createBackwardBound(final int start) throws BadLocationException {
// final PartitionConstraint matcher= getPartitionConstraint();
// if (matcher.matches(TexDocumentConstants.LTX_DEFAULT_CONTENT_TYPE)) {
// return -1;
// }
// final ITypedRegion partition= TextUtilities.getPartition(document, getPartitioning(), start, false);
// return partition.getOffset();
// }
/**
* Computes bracket balance
*
* @param backwardOffset searching backward before this offset
* @param forwardOffset searching forward after (including) this offset
* @param initial initial balance (e.g. known or not yet inserted between backward and forward offset)
* @param searchType interesting bracket type
* @return
* @see #getBracketType(char)
*/
public int[] computeBracketBalance(int backwardOffset, int forwardOffset, final int[] initial, final int searchType) {
final int[] balance= new int[3];
final BracketBalanceCondition condition= new BracketBalanceCondition();
int breakType= -1;
ITER_BACKWARD : while (--backwardOffset >= 0) {
backwardOffset= scanBackward(backwardOffset, -1, condition);
if (backwardOffset != NOT_FOUND) {
if (condition.open) {
balance[condition.type]++;
if (condition.type != searchType && balance[condition.type] > 0) {
breakType= condition.type;
break ITER_BACKWARD;
}
}
else {
balance[condition.type]--;
}
}
else {
break ITER_BACKWARD;
}
}
final int bound= getDocument().getLength();
for (int i= 0; i < balance.length; i++) {
if (balance[i] < 0) {
balance[i]= 0;
}
balance[i]+= initial[i];
}
ITER_FORWARD : while (forwardOffset < bound) {
forwardOffset= scanForward(forwardOffset, bound, condition);
if (forwardOffset != NOT_FOUND) {
if (condition.open) {
balance[condition.type]++;
}
else {
balance[condition.type]--;
}
if (breakType >= 0 && balance[breakType] == 0) {
break ITER_FORWARD;
}
forwardOffset++;
}
else {
break ITER_FORWARD;
}
}
return balance;
}
}