blob: e64d8ff4b9ae036668e9d4e331ff60904adce9f5 [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.tex.r.core.source;
import static org.eclipse.statet.ecommons.text.core.treepartitioner.TreePartitionNode.END_UNCLOSED;
import org.eclipse.jface.text.rules.ICharacterScanner;
import org.eclipse.statet.ecommons.text.core.treepartitioner.TreePartitionNode;
import org.eclipse.statet.ecommons.text.core.treepartitioner.TreePartitionNodeScan;
import org.eclipse.statet.ecommons.text.core.treepartitioner.WrappedPartitionNodeScan;
import org.eclipse.statet.docmlet.tex.core.source.LtxPartitionNodeScanner;
import org.eclipse.statet.docmlet.tex.core.source.LtxPartitionNodeType;
import org.eclipse.statet.docmlet.tex.core.source.LtxPartitionNodeType.VerbatimInline;
import org.eclipse.statet.r.core.source.RPartitionNodeScanner;
import org.eclipse.statet.r.core.source.RPartitionNodeType;
/**
* Paritition scanner for LaTeX with chunks.
*
* Stops if find '&lt;&lt;' at column 0 and handles 'Sexpr' control word.
*/
public class LtxRweavePartitionNodeScanner extends LtxPartitionNodeScanner {
protected static final int S_RVERB= S_EXT_LTX + 1;
protected static final int S_RCHUNK= S_EXT_LTX + 2;
private static final VerbatimInline SEXPR_LTX_TYPE= new VerbatimInline('}') {
@Override
public byte getScannerState() {
return S_RVERB;
}
};
private static final LtxPartitionNodeType RCHUNK_LTX_TYPE= new LtxPartitionNodeType() {
@Override
public String getPartitionType() {
return TexRweaveDocumentConstants.RCHUNK_BASE_CONTENT_TYPE;
}
@Override
public byte getScannerState() {
return S_RCHUNK;
}
};
private static final char[] SEQ_Sexpr= "Sexpr".toCharArray(); //$NON-NLS-1$
private final RChunkPartitionNodeScanner rScanner= new RChunkPartitionNodeScanner();
private WrappedPartitionNodeScan rScan;
private int rStartOffset;
private TreePartitionNode rStartNode;
public LtxRweavePartitionNodeScanner() {
super();
}
public LtxRweavePartitionNodeScanner(final boolean templateMode) {
super(templateMode);
}
@Override
public void execute(final TreePartitionNodeScan scan) {
this.rScan= new WrappedPartitionNodeScan(scan);
super.execute(scan);
this.rScan= null;
}
@Override
protected void init() {
final TreePartitionNode beginNode= getScan().getBeginNode();
if (beginNode.getType() instanceof RPartitionNodeType) {
this.rStartOffset= getScan().getStartOffset();
this.rStartNode= beginNode;
final TreePartitionNode rRootNode= RPartitionNodeScanner.findRRootNode(beginNode);
if (rRootNode.getType() == RChunkPartitionNodeScanner.R_CHUNK_BASE_TYPE) {
initNode(rRootNode, RCHUNK_LTX_TYPE);
}
else {
initNode(rRootNode, SEXPR_LTX_TYPE);
}
return;
}
this.rStartNode= null;
super.init();
}
@Override
protected void handleNewLine(final LtxPartitionNodeType type) {
if (this.reader.readTemp('<', '<')) {
if (type == RCHUNK_LTX_TYPE) { // setup by #init
assert (this.rStartNode != null);
return;
}
assert (this.rStartNode == null);
this.rStartOffset= this.reader.getOffset();
addNode(RChunkPartitionNodeScanner.R_CHUNK_BASE_TYPE, RCHUNK_LTX_TYPE,
this.rStartOffset );
this.rStartNode= getNode();
}
}
@Override
protected boolean searchExtCommand(final int c) {
if (c == 'S' && this.reader.readConsuming2(SEQ_Sexpr)) {
this.reader.readConsumingWhitespace();
if (this.reader.read('{')) {
assert (this.rStartNode == null);
this.rStartOffset= this.reader.getOffset();
addNode(this.rScanner.getDefaultRootType(), SEXPR_LTX_TYPE,
this.rStartOffset );
this.rStartNode= getNode();
processExt(SEXPR_LTX_TYPE);
return true;
}
}
return false;
}
@Override
protected void processExt(final LtxPartitionNodeType type) {
final TreePartitionNode node;
switch (type.getScannerState()) {
case S_RVERB:
node= this.rStartNode;
this.rStartNode= null;
processInline(); // includes exitNode
if (node.getLength() > 0) {
this.rScan.init(this.rStartOffset, node.getEndOffset(), node);
this.rScanner.execute(this.rScan);
this.rScan.exit();
}
return;
case S_RCHUNK:
node= this.rStartNode;
this.rStartNode= null;
this.rScan.init(this.rStartOffset, this.rScan.getDocument().getLength(), node);
this.rScanner.execute(this.rScan);
this.rScan.exit();
final TreePartitionNode chunkNode= getNode();
exitNode();
setRange(chunkNode.getEndOffset(), getScan().getDocument().getLength());
return;
}
super.processExt(type);
}
protected void processInline() {
int expandVar= 0;
LOOP: while (true) {
switch (this.reader.read()) {
case ICharacterScanner.EOF:
exitNode(this.reader.getOffset(), END_UNCLOSED); // required for rweave
this.last= LAST_EOF;
return;
case '\r':
exitNode(this.reader.getOffset() - 1, END_UNCLOSED);
this.reader.read('\n');
this.last= LAST_NEWLINE;
return;
case '\n':
exitNode(this.reader.getOffset() - 1, END_UNCLOSED);
this.last= LAST_NEWLINE;
return;
case '{':
if (this.reader.read('{')) {
expandVar++;
continue LOOP;
}
continue LOOP;
case '}':
if (expandVar > 0 && this.reader.read('}')) {
expandVar--;
continue LOOP;
}
exitNode(this.reader.getOffset() - 1, 0);
this.last= LAST_OTHER;
return;
default:
continue LOOP;
}
}
}
}