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