/* * Copyright (c) 2012 Sam Harwell, Tunnel Vision Laboratories LLC * All rights reserved. * * The source code of this document is proprietary work, and is not licensed for * distribution. For information about licensing, contact Sam Harwell at: * sam@tunnelvisionlabs.com */ package org.tvl.goworks.editor.go.highlighter; import com.tvl.spi.editor.completion.CompletionItem; import com.tvl.spi.editor.completion.CompletionProvider; import java.util.Collection; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import javax.swing.text.JTextComponent; import javax.swing.text.StyledDocument; import org.antlr.netbeans.editor.text.OffsetRegion; import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.Token; import org.antlr.works.editor.antlr4.completion.CompletionQueryResult; import org.antlr.works.editor.antlr4.highlighting.ANTLRHighlighterBaseV4; import org.antlr.works.editor.antlr4.highlighting.TokenSourceWithStateV4; import org.netbeans.api.editor.mimelookup.MimeLookup; import org.netbeans.api.editor.mimelookup.MimePath; import org.netbeans.api.editor.settings.AttributesUtilities; import org.netbeans.api.editor.settings.EditorStyleConstants; import org.netbeans.api.editor.settings.FontColorSettings; import org.netbeans.spi.editor.highlighting.HighlightAttributeValue; import org.openide.util.Lookup; import org.tvl.goworks.editor.GoEditorKit; import org.tvl.goworks.editor.go.completion.GoCompletionItem; import org.tvl.goworks.editor.go.completion.GoCompletionProvider; /** * * @author Sam Harwell */ public class GoHighlighter extends ANTLRHighlighterBaseV4<GoHighlighterLexerState> { // -J-Dorg.tvl.goworks.editor.go.highlighter.GoHighlighter.level=FINE private static final Logger LOGGER = Logger.getLogger(GoHighlighter.class.getName()); public static final String DOCUMENT_PROPERTY = "go-highlighter"; private static final AttributeSet TOOLTIP = AttributesUtilities.createImmutable(EditorStyleConstants.Tooltip, new TooltipResolver()); private final AttributeSet identifierAttributes; private final AttributeSet keywordAttributes; private final AttributeSet commentAttributes; private final AttributeSet stringLiteralAttributes; private final AttributeSet stringLiteralEscapeAttributes; private final AttributeSet stringLiteralInvalidEscapeAttributes; private final AttributeSet numberLiteralAttributes; private GoHighlighterLexerWrapper lexerWrapper; @SuppressWarnings("LeakingThisInConstructor") public GoHighlighter(final StyledDocument document) { super(document); document.putProperty(DOCUMENT_PROPERTY, this); Lookup lookup = MimeLookup.getLookup(MimePath.parse(GoEditorKit.GO_MIME_TYPE)); FontColorSettings settings = lookup.lookup(FontColorSettings.class); identifierAttributes = getFontAndColors(settings, "identifier", true); keywordAttributes = getFontAndColors(settings, "keyword", true); commentAttributes = getFontAndColors(settings, "comment"); stringLiteralAttributes = getFontAndColors(settings, "stringliteral"); stringLiteralEscapeAttributes = getFontAndColors(settings, "stringliteralescape"); stringLiteralInvalidEscapeAttributes = getFontAndColors(settings, "stringliteralinvalidescape"); numberLiteralAttributes = getFontAndColors(settings, "number"); } private static AttributeSet getFontAndColors(FontColorSettings settings, String category) { return getFontAndColors(settings, category, false); } private static AttributeSet getFontAndColors(FontColorSettings settings, String category, boolean tooltip) { AttributeSet attributes = settings.getTokenFontColors(category); if (tooltip) { attributes = AttributesUtilities.createComposite(attributes, TOOLTIP); } return attributes; } @Override protected CharStream createInputStream(OffsetRegion span) throws BadLocationException { return super.createInputStream(span); } @Override protected GoHighlighterLexerState getStartState() { return GoHighlighterLexerState.INITIAL; } @Override protected TokenSourceWithStateV4<GoHighlighterLexerState> createLexer(CharStream input, GoHighlighterLexerState startState) { if (lexerWrapper == null) { lexerWrapper = new GoHighlighterLexerWrapper(input, startState); } else { lexerWrapper.setState(input, startState); } return lexerWrapper; } @Override protected AttributeSet highlightToken(Token token) { switch (token.getType()) { // common keywords case GoHighlighterLexer.Break: case GoHighlighterLexer.Case: case GoHighlighterLexer.Chan: case GoHighlighterLexer.Const: case GoHighlighterLexer.Continue: case GoHighlighterLexer.Default: case GoHighlighterLexer.Defer: case GoHighlighterLexer.Else: case GoHighlighterLexer.Fallthrough: case GoHighlighterLexer.For: case GoHighlighterLexer.Func: case GoHighlighterLexer.Go: case GoHighlighterLexer.Goto: case GoHighlighterLexer.If: case GoHighlighterLexer.Import: case GoHighlighterLexer.Interface: case GoHighlighterLexer.Map: case GoHighlighterLexer.Package: case GoHighlighterLexer.Range: case GoHighlighterLexer.Return: case GoHighlighterLexer.Select: case GoHighlighterLexer.Struct: case GoHighlighterLexer.Switch: case GoHighlighterLexer.Type: case GoHighlighterLexer.Var: return keywordAttributes; case GoHighlighterLexer.INT_LITERAL: case GoHighlighterLexer.FLOAT_LITERAL: return numberLiteralAttributes; case GoHighlighterLexer.CharLiteral: case GoHighlighterLexer.InterpretedStringLiteral: case GoHighlighterLexer.RawStringLiteral: return stringLiteralAttributes; case GoHighlighterLexer.CharLiteralEscape: case GoHighlighterLexer.StringLiteralEscape: return stringLiteralEscapeAttributes; case GoHighlighterLexer.COMMENT: case GoHighlighterLexer.ML_COMMENT: return commentAttributes; case GoHighlighterLexer.IDENTIFIER: return identifierAttributes; default: return null; } } public static final class TooltipResolver implements HighlightAttributeValue<String> { @Override public String getValue(JTextComponent component, Document document, Object attributeKey, int startOffset, int endOffset) { if (attributeKey != EditorStyleConstants.Tooltip) { return null; } final Lookup lookup = MimeLookup.getLookup(MimePath.get(GoEditorKit.GO_MIME_TYPE)); Collection<? extends CompletionProvider> providers = lookup.lookupAll(CompletionProvider.class); GoCompletionProvider provider = null; for (CompletionProvider current : providers) { if (!(current instanceof GoCompletionProvider)) { continue; } provider = (GoCompletionProvider)current; } if (provider == null) { return "No suitable completion provider found."; } Future<CompletionQueryResult> futureQuery = provider.executeQuery(CompletionProvider.TOOLTIP_QUERY_TYPE, component, startOffset, true); if (futureQuery == null) { return ""; } CompletionQueryResult result; try { result = futureQuery.get(5, TimeUnit.SECONDS); } catch (InterruptedException | ExecutionException | TimeoutException ex) { LOGGER.log(Level.WARNING, "An exception occurred while resolving a tooltip query.", ex); return ""; } List<? extends CompletionItem> results = result.getResults(); if (results == null || results.isEmpty()) { return ""; } final String newline = System.getProperty("line.separator"); StringBuilder tipText = new StringBuilder(); for (CompletionItem item : results) { if (item instanceof GoCompletionItem) { if (tipText.length() > 0) { tipText.append(newline); } tipText.append(((GoCompletionItem)item).getToolTipText()); } } return tipText.toString(); } } }