/* * Copyright (c) 2013, the Dart project authors. * * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.eclipse.org/legal/epl-v10.html * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.dart.tools.wst.ui.style; import com.google.dart.engine.ast.AstNode; import com.google.dart.engine.ast.SimpleIdentifier; import com.google.dart.engine.ast.visitor.GeneralizingAstVisitor; import com.google.dart.engine.utilities.source.SourceRange; import com.google.dart.tools.ui.internal.text.editor.SemanticHighlighting; import com.google.dart.tools.ui.internal.text.editor.SemanticHighlightingManager.Highlighting; import com.google.dart.tools.ui.internal.text.editor.SemanticToken; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.TextAttribute; import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.graphics.Color; import java.util.Collection; import java.util.List; /** * Analyze a document to produce semantic highlighting ranges. Adapted from * SemanticHighlightingRecolciler. */ public class SemanticHighlightingEngine { /** * Collects styled text regions from the AST for highlighting. */ private class PositionCollector extends GeneralizingAstVisitor<Void> { /** * Cache tokens for performance. */ private SemanticToken token = new SemanticToken(); private Collection<StyleRange> positions; public PositionCollector(Collection<StyleRange> positions) { this.positions = positions; } @Override public Void visitNode(AstNode node) { processNode(token, node); return super.visitNode(node); } /** * Add a position with the given range and highlighting iff it does not exist already. * * @param offset The range offset * @param length The range length * @param highlighting The highlighting */ protected void addPosition(int offset, int length, Highlighting highlighting) { TextAttribute attr = highlighting.getTextAttribute(); Color fore = attr.getForeground(); Color back = attr.getBackground(); int style = attr.getStyle(); StyleRange range = new StyleRange(offset + deltaOffset, length, fore, back, style); if ((attr.getStyle() & TextAttribute.STRIKETHROUGH) != 0) { range.strikeout = true; } if ((attr.getStyle() & TextAttribute.UNDERLINE) != 0) { range.underline = true; } positions.add(range); } } private IDocument document; private int deltaOffset; private SemanticHighlighting[] semanticHighlightings; private Highlighting[] highlightings; private PositionCollector collector; public SemanticHighlightingEngine(SemanticHighlighting[] semanticHighlightings, Highlighting[] highlightings) { this.semanticHighlightings = semanticHighlightings; this.highlightings = highlightings; } public void analyze(IDocument document, int deltaOffset, AstNode node, Collection<StyleRange> positions) { this.document = document; this.deltaOffset = deltaOffset; this.collector = new PositionCollector(positions); node.accept(this.collector); } private final void processNode(SemanticToken token, AstNode node) { // update token token.update(node); token.attachSource(document); // try SemanticHighlighting instances for (int i = 0, n = semanticHighlightings.length; i < n; i++) { if (highlightings[i].isEnabled()) { SemanticHighlighting semanticHighlighting = semanticHighlightings[i]; // try multiple positions { List<SourceRange> ranges = semanticHighlighting.consumesMulti(token); if (ranges != null) { for (SourceRange range : ranges) { int offset = range.getOffset(); int length = range.getLength(); if (offset > -1 && length > 0) { collector.addPosition(offset, length, highlightings[i]); } } break; } } // try single position boolean consumes; if (node instanceof SimpleIdentifier) { consumes = semanticHighlighting.consumesIdentifier(token); } else { consumes = semanticHighlighting.consumes(token); } if (consumes) { int offset = node.getOffset(); int length = node.getLength(); if (offset > -1 && length > 0) { collector.addPosition(offset, length, highlightings[i]); } break; } } } token.clear(); } }