1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-07-30 16:24:09 +03:00

Restoring keyword.txt loading and parsing. Added token type identifiers and related style in theme.txt

This commit is contained in:
Federico Fissore
2015-04-27 17:23:44 +02:00
parent 5eca70b1d0
commit 9ebe916fac
12 changed files with 474 additions and 410 deletions

View File

@ -53,6 +53,7 @@ import processing.app.legacy.PApplet;
import processing.app.macosx.ThinkDifferent;
import processing.app.packages.LibraryList;
import processing.app.packages.UserLibrary;
import processing.app.syntax.PdeKeywords;
import processing.app.tools.MenuScroller;
import processing.app.tools.ZipDeflater;
@ -118,6 +119,8 @@ public class Base {
private List<JMenu> boardsCustomMenus;
private volatile Action openBoardsManager;
private final PdeKeywords pdeKeywords;
static public void main(String args[]) throws Exception {
System.setProperty("awt.useSystemAAFontSettings", "on");
System.setProperty("swing.aatext", "true");
@ -345,6 +348,9 @@ public class Base {
// them.
PreferencesData.save();
this.pdeKeywords = new PdeKeywords();
this.pdeKeywords.reload();
if (parser.isInstallBoard()) {
ContributionsIndexer indexer = new ContributionsIndexer(BaseNoGui.getSettingsFolder());
ContributionInstaller installer = new ContributionInstaller(indexer) {
@ -2771,4 +2777,8 @@ public class Base {
public Action getOpenBoardsManager() {
return openBoardsManager;
}
public PdeKeywords getPdeKeywords() {
return pdeKeywords;
}
}

View File

@ -958,7 +958,7 @@ public class Editor extends JFrame implements RunnerListener {
protected SketchTextArea createTextArea() throws IOException {
SketchTextArea textArea = new SketchTextArea();
SketchTextArea textArea = new SketchTextArea(base.getPdeKeywords());
textArea.requestFocusInWindow();
textArea.setMarkOccurrences(true);
textArea.setMarginLineEnabled(false);
@ -1757,7 +1757,7 @@ public class Editor extends JFrame implements RunnerListener {
RSyntaxDocument document = (RSyntaxDocument) codeDoc.getDocument();
if (document == null) { // this document not yet inited
document = new RSyntaxDocument(RSyntaxDocument.SYNTAX_STYLE_CPLUSPLUS);
document = new RSyntaxDocument(new ArduinoTokenMakerFactory(base.getPdeKeywords()), RSyntaxDocument.SYNTAX_STYLE_CPLUSPLUS);
document.putProperty(PlainDocument.tabSizeAttribute, Preferences.getInteger("editor.tabs.size"));
// insert the program text into the document object
@ -1953,7 +1953,7 @@ public class Editor extends JFrame implements RunnerListener {
protected void handleFindReference() {
String text = getCurrentKeyword();
String referenceFile = PdeKeywords.getReference(text);
String referenceFile = base.getPdeKeywords().getReference(text);
if (referenceFile == null) {
statusNotice(I18n.format(_("No reference available for \"{0}\""), text));
} else {
@ -2897,7 +2897,7 @@ public class Editor extends JFrame implements RunnerListener {
@Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
String referenceFile = PdeKeywords.getReference(getCurrentKeyword());
String referenceFile = base.getPdeKeywords().getReference(getCurrentKeyword());
referenceItem.setEnabled(referenceFile != null);
int offset = textarea.getCaretPosition();

View File

@ -21,19 +21,20 @@
package processing.app;
import static processing.app.I18n._;
import java.awt.Color;
import java.awt.Font;
import java.awt.SystemColor;
import java.io.File;
import javax.swing.text.StyleContext;
import processing.app.helpers.OSUtils;
import processing.app.helpers.PreferencesHelper;
import processing.app.helpers.PreferencesMap;
import javax.swing.text.StyleContext;
import java.awt.*;
import java.awt.font.TextAttribute;
import java.io.File;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import static processing.app.I18n._;
/**
* Storage class for theme settings. This was separated from the Preferences
* class for 1.0 so that the coloring wouldn't conflict with previous releases
@ -41,9 +42,13 @@ import processing.app.helpers.PreferencesMap;
*/
public class Theme {
/** Copy of the defaults in case the user mangles a preference. */
/**
* Copy of the defaults in case the user mangles a preference.
*/
static PreferencesMap defaults;
/** Table of attributes/values for the theme. */
/**
* Table of attributes/values for the theme.
*/
static PreferencesMap table = new PreferencesMap();
static protected void init() {
@ -51,7 +56,7 @@ public class Theme {
table.load(new File(BaseNoGui.getContentFile("lib"), "theme/theme.txt"));
} catch (Exception te) {
Base.showError(null, _("Could not read color theme settings.\n" +
"You'll need to reinstall Arduino."), te);
"You'll need to reinstall Arduino."), te);
}
// other things that have to be set explicitly for the defaults
@ -106,8 +111,8 @@ public class Theme {
}
return font;
}
/**
/**
* Returns the default font for text areas.
*
* @return The default font.
@ -129,8 +134,7 @@ public class Theme {
font = sc.getFont("Monospaced", Font.PLAIN, 13);
}
}
}
else {
} else {
// Consolas added in Vista, used by VS2010+.
font = sc.getFont("Consolas", Font.PLAIN, 13);
if (!"Consolas".equals(font.getFamily())) {
@ -140,6 +144,30 @@ public class Theme {
//System.out.println(font.getFamily() + ", " + font.getName());
return font;
}
public static Map<String, Object> getStyledFont(String what, Font font) {
String split[] = get("editor." + what + ".style").split(",");
Color color = PreferencesHelper.parseColor(split[0]);
String style = split[1];
boolean bold = style.contains("bold");
boolean italic = style.contains("italic");
boolean underlined = style.contains("underlined");
Font styledFont = new Font(font.getFamily(), (bold ? Font.BOLD : 0) | (italic ? Font.ITALIC : 0), font.getSize());
if (underlined) {
Map<TextAttribute, Object> attr = new Hashtable<TextAttribute, Object>();
attr.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
styledFont = styledFont.deriveFont(attr);
}
Map<String, Object> result = new HashMap<String, Object>();
result.put("color", color);
result.put("font", styledFont);
return result;
}
}

View File

@ -0,0 +1,25 @@
package processing.app.syntax;
import org.fife.ui.rsyntaxtextarea.AbstractTokenMakerFactory;
import org.fife.ui.rsyntaxtextarea.RSyntaxDocument;
import org.fife.ui.rsyntaxtextarea.TokenMaker;
public class ArduinoTokenMakerFactory extends AbstractTokenMakerFactory {
private final PdeKeywords pdeKeywords;
public ArduinoTokenMakerFactory(PdeKeywords pdeKeywords) {
this.pdeKeywords = pdeKeywords;
}
@Override
protected TokenMaker getTokenMakerImpl(String key) {
return new SketchTokenMaker(pdeKeywords);
}
@Override
protected void initTokenMakerMap() {
putMapping(RSyntaxDocument.SYNTAX_STYLE_CPLUSPLUS, SketchTokenMaker.class.getName());
}
}

View File

@ -25,6 +25,7 @@
package processing.app.syntax;
import cc.arduino.contributions.libraries.ContributedLibrary;
import org.fife.ui.rsyntaxtextarea.TokenMap;
import org.fife.ui.rsyntaxtextarea.TokenTypes;
import processing.app.Base;
import processing.app.BaseNoGui;
@ -35,130 +36,146 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
public class PdeKeywords {
// Value is org.fife.ui.rsyntaxtextarea.TokenTypes
private static HashMap<String, Integer> keywords = new HashMap<String, Integer>();
private static final Map<String, Integer> KNOWN_TOKEN_TYPES = new HashMap<String, Integer>();
private static final Pattern ALPHA = Pattern.compile("\\w");
private static HashMap<String, String> keywordToReference = new HashMap<String, String>();
public static HashMap<String, Integer> reload() {
keywords.clear();
keywordToReference.clear();
return get();
static {
KNOWN_TOKEN_TYPES.put("RESERVED_WORD", TokenTypes.RESERVED_WORD);
KNOWN_TOKEN_TYPES.put("RESERVED_WORD_2", TokenTypes.RESERVED_WORD_2);
KNOWN_TOKEN_TYPES.put("VARIABLE", TokenTypes.VARIABLE);
KNOWN_TOKEN_TYPES.put("OPERATOR", TokenTypes.OPERATOR);
KNOWN_TOKEN_TYPES.put("DATA_TYPE", TokenTypes.DATA_TYPE);
KNOWN_TOKEN_TYPES.put("LITERAL_BOOLEAN", TokenTypes.LITERAL_BOOLEAN);
KNOWN_TOKEN_TYPES.put("LITERAL_CHAR", TokenTypes.LITERAL_CHAR);
}
public static HashMap<String, Integer> get() {
// lookup table for the TokenMarker subclass, handles coloring
private final TokenMap keywordTokenType;
private final Map<String, String> keywordOldToken;
private final Map<String, String> keywordTokenTypeAsString;
if (keywords.isEmpty()) {
try {
load(new File(BaseNoGui.getContentFile("lib"), "keywords.txt"));
if (Base.getLibraries() != null) {
for (ContributedLibrary lib : Base.getLibraries()) {
File keywords = new File(lib.getInstalledFolder(), "keywords.txt");
if (keywords.exists()) load(keywords);
}
// lookup table that maps keywords to their html reference pages
private final Map<String, String> keywordToReference;
public PdeKeywords() {
this.keywordTokenType = new TokenMap();
this.keywordOldToken = new HashMap<String, String>();
this.keywordTokenTypeAsString = new HashMap<String, String>();
this.keywordToReference = new HashMap<String, String>();
}
/**
* Handles loading of keywords file.
* <p/>
* Uses getKeywords() method because that's part of the
* TokenMarker classes.
* <p/>
* It is recommended that a # sign be used for comments
* inside keywords.txt.
*/
public void reload() {
try {
parseKeywordsTxt(new File(BaseNoGui.getContentFile("lib"), "keywords.txt"));
for (ContributedLibrary lib : Base.getLibraries()) {
File keywords = new File(lib.getInstalledFolder(), "keywords.txt");
if (keywords.exists()) {
parseKeywordsTxt(keywords);
}
} catch (Exception e) {
Base.showError("Problem loading keywords",
"Could not load keywords.txt,\n" +
"please re-install Arduino.", e);
System.exit(1);
}
} catch (Exception e) {
Base.showError("Problem loading keywords", "Could not load keywords.txt,\nplease re-install Arduino.", e);
System.exit(1);
}
return keywords;
}
static private void load(File input) throws Exception {
private void parseKeywordsTxt(File input) throws Exception {
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(new FileInputStream(input)));
String line = null;
String line;
while ((line = reader.readLine()) != null) {
//System.out.println("line is " + line);
// in case there's any garbage on the line
//if (line.trim().length() == 0) continue;
line = line.trim();
if (line.length() == 0 || line.startsWith("#")) {
continue;
}
String pieces[] = PApplet.split(line, '\t');
String keyword = pieces[0].trim();
if (pieces.length >= 2) {
//int tab = line.indexOf('\t');
// any line with no tab is ignored
// meaning that a comment is any line without a tab
//if (tab == -1) continue;
keywordOldToken.put(keyword, pieces[1]);
}
String keyword = pieces[0].trim();
//String keyword = line.substring(0, tab).trim();
//String second = line.substring(tab + 1);
//tab = second.indexOf('\t');
//String coloring = second.substring(0, tab).trim();
//String htmlFilename = second.substring(tab + 1).trim();
String coloring = pieces[1].trim();
if (coloring.length() > 0 && Character.isDigit(coloring.charAt(coloring.length() - 1))) {
// text will be KEYWORD or LITERAL
boolean isKey = (coloring.charAt(0) == 'K');
// KEYWORD1 -> 0, KEYWORD2 -> 1, etc
int num = coloring.charAt(coloring.length() - 1) - '1';
byte id = (byte)
((isKey ? Token.KEYWORD1 : Token.LITERAL1) + num);
//System.out.println("got " + (isKey ? "keyword" : "literal") +
// (num+1) + " for " + keyword);
int tokenType = TokenTypes.IDENTIFIER;
// KEYWORD1 Classes, datatypes, and C++ keywords
// KEYWORD2 Methods and functions
// KEYWORD3 setup and loop functions, as well as the Serial keywords
// LITERAL1 Constants
// LITERAL2 Built-in variables (INPUT,OUTPUT,CHANGE,FALLING)
switch (id) {
case Token.KEYWORD1:
tokenType = TokenTypes.VARIABLE;
break;
case Token.KEYWORD2:
tokenType = TokenTypes.FUNCTION;
break;
case Token.KEYWORD3:
tokenType = TokenTypes.RESERVED_WORD;
break;
case Token.LITERAL1:
tokenType = TokenTypes.PREPROCESSOR;
break;
case Token.LITERAL2:
tokenType = TokenTypes.RESERVED_WORD_2;
break;
default:
break;
}
if ("true".equals(keyword) || "false".equals(keyword)) {
tokenType = TokenTypes.LITERAL_BOOLEAN;
}
keywords.put(keyword, tokenType);
}
if (pieces.length >= 3) {
String htmlFilename = pieces[2].trim();
if (htmlFilename.length() > 0) {
keywordToReference.put(keyword, htmlFilename);
}
}
if (pieces.length >= 3) {
parseHTMLReferenceFileName(pieces[2], keyword);
}
if (pieces.length >= 4) {
parseRSyntaxTextAreaTokenType(pieces[3], keyword);
}
}
fillMissingTokenType();
} finally {
if (reader != null) {
reader.close();
}
}
}
public static String getReference(String keyword) {
if (keywordToReference == null) return null;
private void fillMissingTokenType() {
for (Map.Entry<String, String> oldTokenEntry : keywordOldToken.entrySet()) {
String keyword = oldTokenEntry.getKey();
if (!keywordTokenTypeAsString.containsKey(keyword)) {
if ("KEYWORD1".equals(oldTokenEntry.getValue())) {
parseRSyntaxTextAreaTokenType("DATA_TYPE", keyword);
} else {
parseRSyntaxTextAreaTokenType("FUNCTION", keyword);
}
}
}
}
private void parseRSyntaxTextAreaTokenType(String tokenTypeAsString, String keyword) {
if (!ALPHA.matcher(keyword).find()) {
return;
}
if (KNOWN_TOKEN_TYPES.containsKey(tokenTypeAsString)) {
keywordTokenType.put(keyword, KNOWN_TOKEN_TYPES.get(tokenTypeAsString));
keywordTokenTypeAsString.put(keyword, tokenTypeAsString);
} else {
keywordTokenType.put(keyword, TokenTypes.FUNCTION);
keywordTokenTypeAsString.put(keyword, "FUNCTION");
}
}
private void parseHTMLReferenceFileName(String piece, String keyword) {
String htmlFilename = piece.trim();
if (htmlFilename.length() > 0) {
keywordToReference.put(keyword, htmlFilename);
}
}
public String getReference(String keyword) {
return keywordToReference.get(keyword);
}
public String getTokenTypeAsString(String keyword) {
return keywordTokenTypeAsString.get(keyword);
}
public int getTokenType(char[] array, int start, int end) {
return keywordTokenType.get(array, start, end);
}
}

View File

@ -29,66 +29,67 @@
package processing.app.syntax;
import java.awt.AWTKeyStroke;
import java.awt.KeyboardFocusManager;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Logger;
import javax.swing.JPopupMenu;
import javax.swing.KeyStroke;
import javax.swing.event.HyperlinkEvent;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.Segment;
import javax.swing.undo.UndoManager;
import org.fife.ui.rsyntaxtextarea.*;
import org.fife.ui.rsyntaxtextarea.Theme;
import org.fife.ui.rsyntaxtextarea.Token;
import org.fife.ui.rsyntaxtextarea.focusabletip.FocusableTip;
import org.fife.ui.rtextarea.RUndoManager;
import processing.app.*;
import javax.swing.*;
import javax.swing.event.HyperlinkEvent;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.Segment;
import javax.swing.undo.UndoManager;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
/**
* Arduino Sketch code editor based on RSyntaxTextArea (http://fifesoft.com/rsyntaxtextarea)
* @author Ricardo JL Rufino (ricardo@criativasoft.com.br)
*
* @author Ricardo JL Rufino (ricardo@criativasoft.com.br)
* @date 20/04/2015
* @since 1.6.4
*/
public class SketchTextArea extends RSyntaxTextArea {
private final static Logger LOG = Logger.getLogger(SketchTextArea.class.getName());
/** The last docTooltip displayed. */
/**
* The last docTooltip displayed.
*/
private FocusableTip docTooltip;
/**
* The component that tracks the current line number.
*/
protected EditorLineStatus editorLineStatus;
private EditorListener editorListener;
public SketchTextArea() throws IOException {
super();
private final PdeKeywords pdeKeywords;
public SketchTextArea(PdeKeywords pdeKeywords) throws IOException {
this.pdeKeywords = pdeKeywords;
installFeatures();
}
protected void installFeatures() throws IOException {
protected void installFeatures() throws IOException {
setTheme(PreferencesData.get("editor.syntax_theme", "default"));
setLinkGenerator(new DocLinkGenerator());
setLinkGenerator(new DocLinkGenerator(pdeKeywords));
fixControlTab();
installTokenMaker();
setSyntaxEditingStyle(SYNTAX_STYLE_CPLUSPLUS);
}
public void setTheme(String name) throws IOException {
@ -102,93 +103,118 @@ public class SketchTextArea extends RSyntaxTextArea {
defaultXmlInputStream.close();
}
}
setForeground(processing.app.Theme.getColor("editor.fgcolor"));
setBackground(processing.app.Theme.getColor("editor.bgcolor"));
setCurrentLineHighlightColor(processing.app.Theme.getColor("editor.linehighlight.color"));
setCaretColor(processing.app.Theme.getColor("editor.caret.color"));
setSelectedTextColor(null);
setUseSelectedTextColor(false);
setSelectionColor(processing.app.Theme.getColor("editor.selection.color"));
setMatchedBracketBorderColor(processing.app.Theme.getColor("editor.brackethighlight.color"));
setSyntaxTheme(TokenTypes.DATA_TYPE, "data_type");
setSyntaxTheme(TokenTypes.FUNCTION, "function");
setSyntaxTheme(TokenTypes.RESERVED_WORD, "reserved_word");
setSyntaxTheme(TokenTypes.RESERVED_WORD_2, "reserved_word_2");
setSyntaxTheme(TokenTypes.VARIABLE, "variable");
setSyntaxTheme(TokenTypes.OPERATOR, "operator");
setSyntaxTheme(TokenTypes.COMMENT_DOCUMENTATION, "comment1");
setSyntaxTheme(TokenTypes.COMMENT_EOL, "comment1");
setSyntaxTheme(TokenTypes.COMMENT_KEYWORD, "comment1");
setSyntaxTheme(TokenTypes.COMMENT_MARKUP, "comment1");
setSyntaxTheme(TokenTypes.LITERAL_CHAR, "literal_char");
setSyntaxTheme(TokenTypes.LITERAL_STRING_DOUBLE_QUOTE, "literal_string_double_quote");
}
private void setSyntaxTheme(int tokenType, String id) {
Style style = getSyntaxScheme().getStyle(tokenType);
Map<String, Object> styledFont = processing.app.Theme.getStyledFont(id, style.font);
style.foreground = (Color) styledFont.get("color");
style.font = (Font) styledFont.get("font");
getSyntaxScheme().setStyle(tokenType, style);
}
// Removing the default focus traversal keys
// This is because the DefaultKeyboardFocusManager handles the keypress and consumes the event
protected void fixControlTab(){
protected void fixControlTab() {
KeyStroke ctrlTab = KeyStroke.getKeyStroke("ctrl TAB");
KeyStroke ctrlShiftTab = KeyStroke.getKeyStroke("ctrl shift TAB");
// Remove ctrl-tab from normal focus traversal
Set<AWTKeyStroke> forwardKeys = new HashSet<AWTKeyStroke>(this.getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS));
forwardKeys.remove(ctrlTab);
this.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, forwardKeys);
// Remove ctrl-shift-tab from normal focus traversal
Set<AWTKeyStroke> backwardKeys = new HashSet<AWTKeyStroke>(this.getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS));
backwardKeys.remove(ctrlShiftTab);
}
public void setEditorLineStatus(EditorLineStatus editorLineStatus) {
this.editorLineStatus = editorLineStatus;
}
@Override
public void select(int selectionStart, int selectionEnd) {
super.select(selectionStart, selectionEnd);
if(editorLineStatus != null) editorLineStatus.set(selectionStart, selectionEnd);
if (editorLineStatus != null) editorLineStatus.set(selectionStart, selectionEnd);
}
public boolean isSelectionActive() {
return this.getSelectedText() != null;
}
public void setSelectedText(String text){
public void setSelectedText(String text) {
int old = getTextMode();
setTextMode(OVERWRITE_MODE);
replaceSelection(text);
setTextMode(old);
}
protected void installTokenMaker(){
AbstractTokenMakerFactory atmf = (AbstractTokenMakerFactory)TokenMakerFactory.getDefaultInstance();
atmf.putMapping(SYNTAX_STYLE_CPLUSPLUS, "processing.app.syntax.SketchTokenMaker");
setSyntaxEditingStyle(SYNTAX_STYLE_CPLUSPLUS);
}
public void processKeyEvent(KeyEvent evt) {
// this had to be added because the menu key events weren't making it up to the frame.
switch(evt.getID()) {
case KeyEvent.KEY_TYPED:
if (editorListener != null) editorListener.keyTyped(evt);
break;
case KeyEvent.KEY_PRESSED:
if (editorListener != null) editorListener.keyPressed(evt);
break;
case KeyEvent.KEY_RELEASED:
// inputHandler.keyReleased(evt);
break;
switch (evt.getID()) {
case KeyEvent.KEY_TYPED:
if (editorListener != null) editorListener.keyTyped(evt);
break;
case KeyEvent.KEY_PRESSED:
if (editorListener != null) editorListener.keyPressed(evt);
break;
case KeyEvent.KEY_RELEASED:
// inputHandler.keyReleased(evt);
break;
}
if(!evt.isConsumed()){
super.processKeyEvent(evt);
if (!evt.isConsumed()) {
super.processKeyEvent(evt);
}
}
public void switchDocument(Document document, UndoManager newUndo) {
// HACK: Dont discard changes on curret UndoManager.
// BUG: https://github.com/bobbylight/RSyntaxTextArea/issues/84
setUndoManager(null); // bypass reset current undo manager...
super.setDocument(document);
setUndoManager((RUndoManager) newUndo);
// HACK: Complement previous hack (hide code folding on switch) | Drawback: Lose folding state
// if(sketch.getCodeCount() > 1 && textarea.isCodeFoldingEnabled()){
// textarea.setCodeFoldingEnabled(false);
// textarea.setCodeFoldingEnabled(true);
// }
}
@Override
@ -196,12 +222,12 @@ public class SketchTextArea extends RSyntaxTextArea {
JPopupMenu menu = super.createPopupMenu();
return menu;
}
@Override
protected void configurePopupMenu(JPopupMenu popupMenu) {
super.configurePopupMenu(popupMenu);
}
public void getTextLine(int line, Segment segment) {
try {
int offset = getLineStartOffset(line);
@ -210,7 +236,7 @@ public class SketchTextArea extends RSyntaxTextArea {
} catch (BadLocationException e) {
}
}
public String getTextLine(int line) {
try {
int offset = getLineStartOffset(line);
@ -220,48 +246,54 @@ public class SketchTextArea extends RSyntaxTextArea {
return null;
}
}
public void setEditorListener(EditorListener editorListener) {
this.editorListener = editorListener;
}
private static class DocLinkGenerator implements LinkGenerator{
@Override
public LinkGeneratorResult isLinkAtOffset(RSyntaxTextArea textArea, final int offs) {
final Token token = textArea.modelToToken(offs);
final String reference = PdeKeywords.getReference(token.getLexeme());
// LOG.fine("reference: " + reference + ", match: " + (token.getType() == TokenTypes.DATA_TYPE || token.getType() == TokenTypes.VARIABLE || token.getType() == TokenTypes.FUNCTION));
if(token != null && (reference != null || (token.getType() == TokenTypes.DATA_TYPE || token.getType() == TokenTypes.VARIABLE || token.getType() == TokenTypes.FUNCTION) )){
LinkGeneratorResult generatorResult = new LinkGeneratorResult() {
@Override
public int getSourceOffset() {
return offs;
}
@Override
public HyperlinkEvent execute() {
LOG.fine("Open Reference: " + reference);
Base.showReference("Reference/" + reference);
return null;
}
};
return generatorResult;
}
return null;
private static class DocLinkGenerator implements LinkGenerator {
private final PdeKeywords pdeKeywords;
public DocLinkGenerator(PdeKeywords pdeKeywords) {
this.pdeKeywords = pdeKeywords;
}
@Override
public LinkGeneratorResult isLinkAtOffset(RSyntaxTextArea textArea, final int offs) {
final Token token = textArea.modelToToken(offs);
final String reference = pdeKeywords.getReference(token.getLexeme());
// LOG.fine("reference: " + reference + ", match: " + (token.getType() == TokenTypes.DATA_TYPE || token.getType() == TokenTypes.VARIABLE || token.getType() == TokenTypes.FUNCTION));
if (token != null && (reference != null || (token.getType() == TokenTypes.DATA_TYPE || token.getType() == TokenTypes.VARIABLE || token.getType() == TokenTypes.FUNCTION))) {
LinkGeneratorResult generatorResult = new LinkGeneratorResult() {
@Override
public int getSourceOffset() {
return offs;
}
@Override
public HyperlinkEvent execute() {
LOG.fine("Open Reference: " + reference);
Base.showReference("Reference/" + reference);
return null;
}
};
return generatorResult;
}
};
return null;
}
}
}

View File

@ -29,120 +29,33 @@
package processing.app.syntax;
import java.util.HashMap;
import java.util.Set;
import org.fife.ui.rsyntaxtextarea.TokenMap;
import org.fife.ui.rsyntaxtextarea.TokenTypes;
import org.fife.ui.rsyntaxtextarea.modes.CPlusPlusTokenMaker;
import processing.app.Base;
import java.util.Arrays;
/**
* Controls the syntax highlighting of {@link SketchTextArea} based on the {@link PdeKeywords}
*
* @author Ricardo JL Rufino (ricardo@criativasoft.com.br)
* @date 20/04/2015
* @since 1.6.4
* @since 1.6.4
*/
public class SketchTokenMaker extends CPlusPlusTokenMaker {
static TokenMap extraTokens;
public SketchTokenMaker() {
extraTokens = getKeywords();
private final PdeKeywords pdeKeywords;
public SketchTokenMaker(PdeKeywords pdeKeywords) {
this.pdeKeywords = pdeKeywords;
}
@Override
public void addToken(char[] array, int start, int end, int tokenType, int startOffset, boolean hyperlink) {
// This assumes all of your extra tokens would normally be scanned as IDENTIFIER.
if (tokenType == TokenTypes.IDENTIFIER || tokenType == TokenTypes.DATA_TYPE) {
int newType = extraTokens.get(array, start, end);
if (newType>-1) {
tokenType = newType;
}
}
super.addToken(array, start, end, tokenType, startOffset, hyperlink);
}
public static void addKeyword(String keyword, int type) {
extraTokens.put(keyword, type);
}
public void clear() {
extraTokens = new TokenMap();
}
/**
* Handles loading of keywords file.
* <P>
* It is recommended that a # sign be used for comments
* inside keywords.txt.
*/
static public TokenMap getKeywords() {
if (extraTokens == null) {
try {
extraTokens = new TokenMap(false);
extraTokens.put("setup", TokenTypes.RESERVED_WORD);
extraTokens.put("loop", TokenTypes.RESERVED_WORD);
extraTokens.put("HIGH", TokenTypes.RESERVED_WORD_2);
extraTokens.put("LOW", TokenTypes.RESERVED_WORD_2);
extraTokens.put("OUTPUT", TokenTypes.RESERVED_WORD_2);
extraTokens.put("INPUT", TokenTypes.RESERVED_WORD_2);
extraTokens.put("INPUT_PULLUP", TokenTypes.RESERVED_WORD_2);
extraTokens.put("CHANGE", TokenTypes.RESERVED_WORD_2);
extraTokens.put("FALLING", TokenTypes.RESERVED_WORD_2);
extraTokens.put("RISING", TokenTypes.RESERVED_WORD_2);
extraTokens.put("PI", TokenTypes.LITERAL_NUMBER_FLOAT);
extraTokens.put("HALF_PI", TokenTypes.LITERAL_NUMBER_FLOAT);
extraTokens.put("TWO_PI", TokenTypes.LITERAL_NUMBER_FLOAT);
extraTokens.put("DEG_TO_RAD", TokenTypes.LITERAL_NUMBER_FLOAT);
extraTokens.put("RAD_TO_DEG", TokenTypes.LITERAL_NUMBER_FLOAT);
extraTokens.put("EULER", TokenTypes.LITERAL_NUMBER_FLOAT);
// Print.
extraTokens.put("DEC", TokenTypes.RESERVED_WORD_2);
extraTokens.put("HEX", TokenTypes.RESERVED_WORD_2);
extraTokens.put("OCT", TokenTypes.RESERVED_WORD_2);
extraTokens.put("BIN", TokenTypes.RESERVED_WORD_2);
extraTokens.put("true", TokenTypes.LITERAL_BOOLEAN);
extraTokens.put("false", TokenTypes.LITERAL_BOOLEAN);
// Related IO
extraTokens.put("pinMode", TokenTypes.FUNCTION);
extraTokens.put("digitalWrite", TokenTypes.FUNCTION);
extraTokens.put("digitalRead", TokenTypes.FUNCTION);
extraTokens.put("analogRead", TokenTypes.FUNCTION);
extraTokens.put("analogReference", TokenTypes.FUNCTION);
extraTokens.put("analogWrite", TokenTypes.FUNCTION);
// Others.
extraTokens.put("DIGITAL", TokenTypes.RESERVED_WORD_2);
extraTokens.put("ANALOG", TokenTypes.RESERVED_WORD_2);
// force load references.
PdeKeywords.reload();
HashMap<String, Integer> keywords = PdeKeywords.get();
Set<String> keys = keywords.keySet();
for (String key : keys) {
extraTokens.put(key, keywords.get(key));
}
} catch (Exception e) {
Base.showError("Problem loading keywords",
"Could not load keywords.txt,\n" +
"please re-install Arduino.", e);
System.exit(1);
}
// This assumes all of your extra tokens would normally be scanned as IDENTIFIER.
int newType = pdeKeywords.getTokenType(array, start, end);
if (newType > -1) {
tokenType = newType;
}
return extraTokens;
super.addToken(array, start, end, tokenType, startOffset, hyperlink);
}
}