blob: 94798c75214fef4d48ace8132a2bd0116f407b0e [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2007, 2020 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.redocs.r.core.source;
import static org.eclipse.statet.ecommons.text.core.treepartitioner.TreePartitionNode.END_UNCLOSED;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.rules.ICharacterScanner;
import org.eclipse.statet.ecommons.text.core.treepartitioner.TreePartitionNode;
import org.eclipse.statet.r.core.source.RPartitionNodeScanner;
import org.eclipse.statet.r.core.source.RPartitionNodeType;
/**
* Abstract partition scanner for R chunks e.g. in Sweave files.
*/
public abstract class AbstractRChunkPartitionNodeScanner extends RPartitionNodeScanner {
private static final int S_CHUNKCONTROL= 8;
private static final int S_CHUNKCOMMENT= 9;
public static final RPartitionNodeType R_CHUNK_BASE_TYPE= new RPartitionNodeType() {
@Override
public String getPartitionType() {
return RweaveDocumentConstants.RCHUNK_BASE_CONTENT_TYPE;
}
@Override
public byte getScannerState() {
return S_CHUNKCONTROL;
}
};
public static final RPartitionNodeType R_CHUNK_CONTROL_TYPE= new RPartitionNodeType() {
@Override
public String getPartitionType() {
return RweaveDocumentConstants.RCHUNK_CONTROL_CONTENT_TYPE;
}
@Override
public byte getScannerState() {
return S_CHUNKCONTROL;
}
@Override
public boolean prefereAtBegin(final TreePartitionNode node, final IDocument document) {
return true;
}
@Override
public boolean prefereAtEnd(final TreePartitionNode node, final IDocument document) {
return true;
}
};
public static final RPartitionNodeType R_CHUNK_COMMENT_TYPE= new RPartitionNodeType.Comment() {
@Override
public String getPartitionType() {
return RweaveDocumentConstants.RCHUNK_COMMENT_CONTENT_TYPE;
}
@Override
public byte getScannerState() {
return S_CHUNKCOMMENT;
}
@Override
public boolean prefereAtBegin(final TreePartitionNode node, final IDocument document) {
return true;
}
};
protected static final byte NONE= 0;
protected static final byte START_LINE= 1;
protected static final byte REF_LINE= 2;
protected static final byte STOP_LINE= 3;
private TreePartitionNode chunkNode;
private byte chunkLine;
public AbstractRChunkPartitionNodeScanner() {
}
@Override
protected void init() {
this.chunkNode= null;
super.init();
final TreePartitionNode rootNode= getRootNode();
if (rootNode.getType().getPartitionType() == RweaveDocumentConstants.RCHUNK_BASE_CONTENT_TYPE) {
this.chunkNode= rootNode;
}
this.chunkLine= NONE;
}
protected final TreePartitionNode getChunkNode() {
return this.chunkNode;
}
protected final byte getChunkLine() {
return this.chunkLine;
}
protected final void exitToChunkBase(final byte chunkLine, final int offset) {
exitNodesTo(this.chunkNode, offset, END_UNCLOSED);
this.chunkLine= chunkLine;
}
@Override
protected abstract void handleNewLine(final RPartitionNodeType type);
@Override
protected void handleEOF(final RPartitionNodeType type) {
final TreePartitionNode rootNode= getRootNode();
final int offset= this.reader.getOffset();
exitNodesTo(rootNode, offset, END_UNCLOSED);
getScan().expand(rootNode, offset, (this.chunkLine == STOP_LINE) ? 0 : END_UNCLOSED, true);
}
@Override
protected void processExt(final RPartitionNodeType type) {
if (this.chunkNode != null) {
switch (type.getScannerState()) {
case S_CHUNKCONTROL:
processChunkControlOpen(this.chunkLine);
return;
case S_CHUNKCOMMENT:
processChunkComment();
return;
default:
break;
}
}
super.processExt(type);
}
protected abstract void processChunkControlOpen(byte chunkLink);
protected void processChunkComment() {
LOOP: while (true) {
switch (this.reader.read()) {
case ICharacterScanner.EOF:
this.last= LAST_EOF;
return;
case '\r':
this.reader.read('\n');
//$FALL-THROUGH$
case '\n':
exitNode(this.reader.getOffset(), 0);
if (this.chunkLine == STOP_LINE) {
this.last= LAST_EOF;
return;
}
else {
addNode(getDefaultRootType(), this.reader.getOffset());
this.last= LAST_NEWLINE;
return;
}
default:
continue LOOP;
}
}
}
}