| /*=============================================================================# |
| # 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; |
| } |
| } |
| } |
| |
| } |