/*
* 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.common.collect.Maps;
import com.google.dart.engine.ast.CompilationUnit;
import com.google.dart.engine.context.AnalysisContext;
import com.google.dart.tools.core.DartCore;
import com.google.dart.tools.ui.DartToolsPlugin;
import com.google.dart.tools.ui.internal.text.editor.DartEditor.EclipsePreferencesAdapter;
import com.google.dart.tools.ui.internal.text.editor.EditorUtility;
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.SemanticHighlightings;
import com.google.dart.tools.ui.internal.text.functions.PreferencesAdapter;
import com.google.dart.tools.ui.internal.util.RunnableObject;
import com.google.dart.tools.ui.internal.util.TimeboxUtils;
import com.google.dart.tools.ui.text.DartPartitions;
import com.google.dart.tools.ui.text.DartTextTools;
import com.google.dart.tools.ui.text.IColorManager;
import com.google.dart.tools.ui.text.IColorManagerExtension;
import com.google.dart.tools.wst.ui.DartReconcilerManager;
import com.google.dart.tools.wst.ui.EmbeddedDartReconcilerHook;
import com.google.dart.tools.wst.ui.StructuredTextViewerConfigurationDart;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ProjectScope;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferenceConverter;
import org.eclipse.jface.text.IDocumentExtension3;
import org.eclipse.jface.text.IDocumentPartitioner;
import org.eclipse.jface.text.ITypedRegion;
import org.eclipse.jface.text.TextAttribute;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.editors.text.EditorsUI;
import org.eclipse.ui.texteditor.ChainedPreferenceStore;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion;
import org.eclipse.wst.sse.ui.internal.provisional.style.AbstractLineStyleProvider;
import org.eclipse.wst.sse.ui.internal.provisional.style.LineStyleProvider;
import org.eclipse.wst.sse.ui.internal.provisional.style.ReconcilerHighlighter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@SuppressWarnings("restriction")
public class LineStyleProviderForDart extends AbstractLineStyleProvider implements
LineStyleProvider {
private static class StyleRangeComparator implements Comparator<StyleRange> {
@Override
public int compare(StyleRange arg0, StyleRange arg1) {
if (arg0 == arg1) {
return 0;
}
if (arg0.start < arg1.start) {
return -1;
}
if (arg0.start > arg1.start) {
return 1;
}
return 0;
}
}
public static CompilationUnit LINE_HACK_UNIT;
public static AnalysisContext LINE_HACK_CONTEXT;
private static final Map<Highlighting, SemanticHighlighting> styleToHighlighting = Maps.newHashMap();
private static final SemanticHighlighting[] highlighters = SemanticHighlightings.getSemanticHighlightings();
private static final Highlighting[] styles = new Highlighting[highlighters.length];
static {
for (int i = 0; i < highlighters.length; i++) {
styles[i] = new Highlighting(null, true);
styleToHighlighting.put(styles[i], highlighters[i]);
}
}
private SemanticHighlighting[] semanticHighlightings;
private Highlighting[] highlightings;
private IPreferenceStore preferenceStore;
private IColorManager colorManager = DartToolsPlugin.getDefault().getDartTextTools().getColorManager();
public LineStyleProviderForDart() {
super();
preferenceStore = createCombinedPreferenceStore(null);
initializeHighlightings();
}
@Override
public void init(IStructuredDocument doc, ReconcilerHighlighter lit) {
super.init(doc, lit);
}
@SuppressWarnings({"rawtypes", "unchecked"})
@Override
public boolean prepareRegions(ITypedRegion typedRegion, int lineRequestStart,
int lineRequestLength, Collection holdResults) {
if (!typedRegion.getType().equals(
StructuredTextViewerConfigurationDart.DART_SCRIPT_PARTITION_NAME)) {
return false;
}
List<StyleRange> positions = new ArrayList<StyleRange>();
IStructuredDocument document = getDocument();
// semantic highlighting
{
int offset = typedRegion.getOffset();
int length = typedRegion.getLength();
CompilationUnit unit = getParsedUnitTimeboxed(document, offset, length);
if (unit != null) {
SemanticHighlightingEngine engine = new SemanticHighlightingEngine(
semanticHighlightings,
highlightings);
engine.analyze(getDocument(), offset, unit, positions);
}
}
// syntax highlighting
{
DartTextTools tools = DartToolsPlugin.getDefault().getDartTextTools();
IDocumentPartitioner part = tools.createDocumentPartitioner();
part.connect(document);
IDocumentExtension3 doc3 = (IDocumentExtension3) document;
doc3.setDocumentPartitioner(DartPartitions.DART_PARTITIONING, part);
SyntacticHighlightingEngine engine = new SyntacticHighlightingEngine(
colorManager,
preferenceStore);
engine.analyze(document, typedRegion, positions);
doc3.setDocumentPartitioner(DartPartitions.DART_PARTITIONING, null);
part.disconnect();
}
Collections.sort(positions, new StyleRangeComparator());
holdResults.addAll(positions);
return true;
}
@Override
protected TextAttribute getAttributeFor(ITextRegion region) {
return null; // not used since prepareRegions() is defined
}
@Override
protected IPreferenceStore getColorPreferences() {
return preferenceStore;
}
@Override
protected void loadColors() {
// not used since prepareRegions() is defined
}
private void addColor(String colorKey) {
if (colorManager != null && colorKey != null && colorManager.getColor(colorKey) == null) {
RGB rgb = PreferenceConverter.getColor(preferenceStore, colorKey);
if (colorManager instanceof IColorManagerExtension) {
IColorManagerExtension ext = (IColorManagerExtension) colorManager;
ext.unbindColor(colorKey);
ext.bindColor(colorKey, rgb);
}
}
}
// TODO(messick) Refactor to unify with copy in DartEditor.
@SuppressWarnings("deprecation")
private IPreferenceStore createCombinedPreferenceStore(IEditorInput input) {
List<IPreferenceStore> stores = new ArrayList<IPreferenceStore>(3);
IProject project = EditorUtility.getProject(input);
if (project != null) {
stores.add(new EclipsePreferencesAdapter(new ProjectScope(project), DartCore.PLUGIN_ID));
}
stores.add(DartToolsPlugin.getDefault().getPreferenceStore());
stores.add(new PreferencesAdapter(DartCore.getPlugin().getPluginPreferences()));
stores.add(EditorsUI.getPreferenceStore());
return new ChainedPreferenceStore(stores.toArray(new IPreferenceStore[stores.size()]));
}
private CompilationUnit getParsedUnitTimeboxed(final IStructuredDocument document,
final int offset, final int length) {
DartReconcilerManager manager = DartReconcilerManager.getInstance();
final EmbeddedDartReconcilerHook reconciler = manager.reconcilerFor(document);
if (reconciler == null) {
return null;
}
return TimeboxUtils.runObject(new RunnableObject<CompilationUnit>() {
@Override
public CompilationUnit runObject() {
return reconciler.getParsedUnit(offset, length, document);
}
}, null, 200, TimeUnit.MILLISECONDS);
}
// Copied from SemanticHighlightingManager
private void initializeHighlightings() {
semanticHighlightings = SemanticHighlightings.getSemanticHighlightings();
highlightings = new Highlighting[semanticHighlightings.length];
for (int i = 0, n = semanticHighlightings.length; i < n; i++) {
SemanticHighlighting semanticHighlighting = semanticHighlightings[i];
String colorKey = SemanticHighlightings.getColorPreferenceKey(semanticHighlighting);
addColor(colorKey);
String boldKey = SemanticHighlightings.getBoldPreferenceKey(semanticHighlighting);
int style = preferenceStore.getBoolean(boldKey) ? SWT.BOLD : SWT.NORMAL;
String italicKey = SemanticHighlightings.getItalicPreferenceKey(semanticHighlighting);
if (preferenceStore.getBoolean(italicKey)) {
style |= SWT.ITALIC;
}
String strikethroughKey = SemanticHighlightings.getStrikethroughPreferenceKey(semanticHighlighting);
if (preferenceStore.getBoolean(strikethroughKey)) {
style |= TextAttribute.STRIKETHROUGH;
}
String underlineKey = SemanticHighlightings.getUnderlinePreferenceKey(semanticHighlighting);
if (preferenceStore.getBoolean(underlineKey)) {
style |= TextAttribute.UNDERLINE;
}
boolean isEnabled = preferenceStore.getBoolean(SemanticHighlightings.getEnabledPreferenceKey(semanticHighlighting));
highlightings[i] = new Highlighting(new TextAttribute(
colorManager.getColor(PreferenceConverter.getColor(preferenceStore, colorKey)),
null,
style), isEnabled);
}
}
}