blob: a741d706c8e00ee92f9f8904dffca346e04b35a6 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2009, 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.docmlet.tex.ui.text;
import static org.eclipse.statet.jcommons.collections.CollectionUtils.putAll;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.rules.IToken;
import org.eclipse.jface.text.rules.ITokenScanner;
import org.eclipse.jface.text.rules.Token;
import org.eclipse.statet.jcommons.collections.ImCollections;
import org.eclipse.statet.jcommons.collections.ImList;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
import org.eclipse.statet.jcommons.string.CharArrayString;
import org.eclipse.statet.ecommons.collections.IntArrayMap;
import org.eclipse.statet.ecommons.text.core.input.DocumentParserInput;
import org.eclipse.statet.ecommons.text.ui.presentation.TextStyleManager;
import org.eclipse.statet.docmlet.tex.core.parser.LtxLexer;
@NonNullByDefault
public class LtxDefaultTextStyleScanner extends DocumentParserInput implements ITokenScanner {
private final LtxLexer lexer;
private final IToken[] tokens;
private final TextStyleManager textStyles;
private final IToken defaultToken;
private @Nullable IToken nextToken;
private final Map<CharArrayString, IToken> specialWords;
private int currentOffset;
private int currentLength;
public LtxDefaultTextStyleScanner(final TextStyleManager textStyles) {
this.lexer= createLexer();
this.lexer.setReportAsterisk(false);
this.textStyles= textStyles;
final IntArrayMap<IToken> tokens= new IntArrayMap<>();
registerTokens(tokens);
this.defaultToken= tokens.get(LtxLexer.DEFAULT_TEXT);
this.tokens= tokens.toArray(IToken.class);
this.specialWords= new HashMap<>();
updateWords(this.specialWords);
}
protected LtxLexer createLexer() {
return new LtxLexer();
}
protected IToken getToken(final String key) {
return this.textStyles.getToken(key);
}
@Override
public void setRange(final IDocument document, final int offset, final int length) {
reset(document);
init(offset, offset + length);
this.lexer.reset(this);
this.currentOffset= offset;
this.currentLength= 0;
}
@Override
public IToken nextToken() {
this.currentOffset+= this.currentLength;
IToken token= this.nextToken;
if (token != null) {
this.nextToken= null;
}
else {
do {
token= getTokenFromScannerToken(this.lexer.next());
} while (token == this.defaultToken);
}
this.currentLength= this.lexer.getOffset() - this.currentOffset;
if (this.currentLength != 0) {
this.nextToken= token;
return this.defaultToken;
}
this.currentLength= this.lexer.getLength();
return token;
}
protected IToken getTokenFromScannerToken(final int lexerToken) {
IToken token;
switch (lexerToken) {
case LtxLexer.EOF:
return Token.EOF;
case LtxLexer.CONTROL_WORD:
final CharArrayString label= getTmpString(1, this.lexer.getLength());
if (label.length() > 0) {
token= this.specialWords.get(label);
if (token != null) {
return token;
}
}
return this.tokens[LtxLexer.CONTROL_WORD];
default:
token= this.tokens[lexerToken];
if (token != null) {
return token;
}
return this.defaultToken;
}
}
@Override
public int getTokenOffset() {
return this.currentOffset;
}
@Override
public int getTokenLength() {
return this.currentLength;
}
protected void registerTokens(final IntArrayMap<IToken> map) {
map.put(LtxLexer.DEFAULT_TEXT, getToken(TexTextStyles.TS_DEFAULT));
map.put(LtxLexer.CONTROL_WORD, getToken(TexTextStyles.TS_CONTROL_WORD));
map.put(LtxLexer.CONTROL_CHAR, getToken(TexTextStyles.TS_CONTROL_CHAR));
map.put(LtxLexer.CONTROL_NONE, getToken(TexTextStyles.TS_CONTROL_WORD));
map.put(LtxLexer.CURLY_BRACKET_OPEN, getToken(TexTextStyles.TS_CURLY_BRACKETS));
map.put(LtxLexer.CURLY_BRACKET_CLOSE, getToken(TexTextStyles.TS_CURLY_BRACKETS));
map.put(LtxLexer.SQUARED_BRACKET_OPEN, getToken(TexTextStyles.TS_CURLY_BRACKETS));
map.put(LtxLexer.SQUARED_BRACKET_CLOSE, getToken(TexTextStyles.TS_CURLY_BRACKETS));
map.put(LtxLexer.LINE_COMMENT, getToken(TexTextStyles.TS_COMMENT));
map.put(LtxLexer.VERBATIM_TEXT, getToken(TexTextStyles.TS_VERBATIM));
}
private static final ImList<CharArrayString> SECTION_WORDS= ImCollections.newList(
new CharArrayString("part"), //$NON-NLS-1$
new CharArrayString("chapter"), //$NON-NLS-1$
new CharArrayString("section"), //$NON-NLS-1$
new CharArrayString("subsection"), //$NON-NLS-1$
new CharArrayString("subsubsection") ); //$NON-NLS-1$
protected void updateWords(final Map<CharArrayString, IToken> map) {
final IToken sectioningToken= getToken(TexTextStyles.TS_CONTROL_WORD_SUB_SECTIONING);
putAll(map, SECTION_WORDS, sectioningToken);
}
}