1
0
mirror of https://github.com/arduino/Arduino.git synced 2024-12-01 12:24:14 +01: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);
}
}

View File

@ -41,6 +41,8 @@ public abstract class AbstractWithPreferencesTest {
Preferences.init(null);
Theme.init();
BaseNoGui.initPackages();
Base.untitledFolder = Base.createTempFolder("untitled");
DeleteFilesOnShutdown.add(Base.untitledFolder);
}

View File

@ -0,0 +1,30 @@
package processing.app.syntax;
import org.fife.ui.rsyntaxtextarea.TokenTypes;
import org.junit.Test;
import processing.app.AbstractWithPreferencesTest;
import processing.app.BaseNoGui;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class PdeKeywordsTest extends AbstractWithPreferencesTest {
@Test
public void testKeywordsTxtParsing() throws Exception {
PdeKeywords pdeKeywords = new PdeKeywords();
pdeKeywords.reload();
assertEquals("Constants", pdeKeywords.getReference("HIGH"));
assertEquals("IDENTIFIER", pdeKeywords.getTokenTypeAsString("HIGH"));
assertEquals(TokenTypes.IDENTIFIER, pdeKeywords.getTokenType("HIGH".toCharArray(), 0, 3));
assertEquals("IncrementCompound", pdeKeywords.getReference("+="));
assertNull(pdeKeywords.getTokenTypeAsString("+="));
assertNull(pdeKeywords.getReference("Mouse"));
assertEquals("VARIABLE", pdeKeywords.getTokenTypeAsString("Mouse"));
assertEquals(TokenTypes.VARIABLE, pdeKeywords.getTokenType("Mouse".toCharArray(), 0, 4));
}
}

View File

@ -5,57 +5,57 @@
# LITERAL2 specifies constants
HIGH LITERAL2 Constants
LOW LITERAL2 Constants
INPUT LITERAL2 Constants
INPUT_PULLUP LITERAL2 Constants
OUTPUT LITERAL2 Constants
DEC LITERAL2 Serial_Print
BIN LITERAL2 Serial_Print
HEX LITERAL2 Serial_Print
OCT LITERAL2 Serial_Print
PI LITERAL2
HALF_PI LITERAL2
TWO_PI LITERAL2
LSBFIRST LITERAL2 ShiftOut
MSBFIRST LITERAL2 ShiftOut
CHANGE LITERAL2 AttachInterrupt
FALLING LITERAL2 AttachInterrupt
RISING LITERAL2 AttachInterrupt
DEFAULT LITERAL2 AnalogReference
EXTERNAL LITERAL2 AnalogReference
INTERNAL LITERAL2 AnalogReference
INTERNAL1V1 LITERAL2 AnalogReference
INTERNAL2V56 LITERAL2 AnalogReference
HIGH LITERAL2 Constants RESERVED_WORD_2
LOW LITERAL2 Constants RESERVED_WORD_2
INPUT LITERAL2 Constants RESERVED_WORD_2
INPUT_PULLUP LITERAL2 Constants RESERVED_WORD_2
OUTPUT LITERAL2 Constants RESERVED_WORD_2
DEC LITERAL2 Serial_Print RESERVED_WORD_2
BIN LITERAL2 Serial_Print RESERVED_WORD_2
HEX LITERAL2 Serial_Print RESERVED_WORD_2
OCT LITERAL2 Serial_Print RESERVED_WORD_2
PI LITERAL2 RESERVED_WORD_2
HALF_PI LITERAL2 RESERVED_WORD_2
TWO_PI LITERAL2 RESERVED_WORD_2
LSBFIRST LITERAL2 ShiftOut RESERVED_WORD_2
MSBFIRST LITERAL2 ShiftOut RESERVED_WORD_2
CHANGE LITERAL2 AttachInterrupt RESERVED_WORD_2
FALLING LITERAL2 AttachInterrupt RESERVED_WORD_2
RISING LITERAL2 AttachInterrupt RESERVED_WORD_2
DEFAULT LITERAL2 AnalogReference RESERVED_WORD_2
EXTERNAL LITERAL2 AnalogReference RESERVED_WORD_2
INTERNAL LITERAL2 AnalogReference RESERVED_WORD_2
INTERNAL1V1 LITERAL2 AnalogReference RESERVED_WORD_2
INTERNAL2V56 LITERAL2 AnalogReference RESERVED_WORD_2
boolean LITERAL2 BooleanVariables
byte LITERAL2 Byte
char LITERAL2 Char
const LITERAL2 Const
false LITERAL2 Constants
float LITERAL2 Float
null LITERAL2
int LITERAL2 Int
long LITERAL2 Long
new LITERAL2
private LITERAL2
protected LITERAL2
public LITERAL2
short LITERAL2
signed LITERAL2
static LITERAL2 Static
String LITERAL2 String
void LITERAL2 Void
true LITERAL2
unsigned LITERAL2
boolean LITERAL2 BooleanVariables RESERVED_WORD_2
byte LITERAL2 Byte RESERVED_WORD_2
char LITERAL2 Char RESERVED_WORD_2
const LITERAL2 Const RESERVED_WORD_2
false LITERAL2 Constants LITERAL_BOOLEAN
float LITERAL2 Float RESERVED_WORD_2
null LITERAL2 RESERVED_WORD_2
int LITERAL2 Int RESERVED_WORD_2
long LITERAL2 Long RESERVED_WORD_2
new LITERAL2 RESERVED_WORD_2
private LITERAL2 RESERVED_WORD_2
protected LITERAL2 RESERVED_WORD_2
public LITERAL2 RESERVED_WORD_2
short LITERAL2 RESERVED_WORD_2
signed LITERAL2 RESERVED_WORD_2
static LITERAL2 Static RESERVED_WORD_2
String LITERAL2 String RESERVED_WORD_2
void LITERAL2 Void RESERVED_WORD_2
true LITERAL2 LITERAL_BOOLEAN
unsigned LITERAL2 RESERVED_WORD_2
boolean LITERAL2 boolean_
byte LITERAL2 byte_
char LITERAL2 char_
float LITERAL2 float_
int LITERAL2 int_
long LITERAL2 long_
word LITERAL2 word_
boolean LITERAL2 boolean_ RESERVED_WORD_2
byte LITERAL2 byte_ RESERVED_WORD_2
char LITERAL2 char_ RESERVED_WORD_2
float LITERAL2 float_ RESERVED_WORD_2
int LITERAL2 int_ RESERVED_WORD_2
long LITERAL2 long_ RESERVED_WORD_2
word LITERAL2 word_ RESERVED_WORD_2
# KEYWORD2 specifies methods and functions
@ -113,11 +113,11 @@ shiftOut KEYWORD2 ShiftOut
tone KEYWORD2 Tone
yield KEYWORD2 Yield
Serial KEYWORD1 Serial
Serial1 KEYWORD1 Serial
Serial2 KEYWORD1 Serial
Serial3 KEYWORD1 Serial
SerialUSB KEYWORD1 Serial
Serial KEYWORD1 Serial DATA_TYPE
Serial1 KEYWORD1 Serial DATA_TYPE
Serial2 KEYWORD1 Serial DATA_TYPE
Serial3 KEYWORD1 Serial DATA_TYPE
SerialUSB KEYWORD1 Serial DATA_TYPE
begin KEYWORD2 Serial_Begin
end KEYWORD2 Serial_End
peek KEYWORD2 Serial_Peek
@ -156,8 +156,8 @@ substring KEYWORD2
toCharArray KEYWORD2
toInt KEYWORD2
Keyboard KEYWORD1
Mouse KEYWORD1
Keyboard KEYWORD1 DATA_TYPE
Mouse KEYWORD1 DATA_TYPE
press KEYWORD2
release KEYWORD2
releaseAll KEYWORD2
@ -168,28 +168,28 @@ isPressed KEYWORD2
# KEYWORD3 specifies structures
break KEYWORD3 Break
case KEYWORD3 SwitchCase
class KEYWORD3
continue KEYWORD3 Continue
default KEYWORD3 SwitchCase
do KEYWORD3 DoWhile
double KEYWORD3 Double
else KEYWORD3 Else
for KEYWORD3 For
if KEYWORD3 If
register KEYWORD3
return KEYWORD3 Return
break KEYWORD3 Break RESERVED_WORD
case KEYWORD3 SwitchCase RESERVED_WORD
class KEYWORD3 RESERVED_WORD
continue KEYWORD3 Continue RESERVED_WORD
default KEYWORD3 SwitchCase RESERVED_WORD
do KEYWORD3 DoWhile RESERVED_WORD
double KEYWORD3 Double RESERVED_WORD
else KEYWORD3 Else RESERVED_WORD
for KEYWORD3 For RESERVED_WORD
if KEYWORD3 If RESERVED_WORD
register KEYWORD3 RESERVED_WORD
return KEYWORD3 Return RESERVED_WORD
switch KEYWORD3 SwitchCase
this KEYWORD3
throw KEYWORD3
try KEYWORD3
while KEYWORD3 While
word KEYWORD3 Word
switch KEYWORD3 SwitchCase RESERVED_WORD
this KEYWORD3 RESERVED_WORD
throw KEYWORD3 RESERVED_WORD
try KEYWORD3 RESERVED_WORD
while KEYWORD3 While RESERVED_WORD
word KEYWORD3 Word RESERVED_WORD
setup KEYWORD3 Setup
loop KEYWORD3 Loop
setup KEYWORD3 Setup RESERVED_WORD
loop KEYWORD3 Loop RESERVED_WORD
# operators aren't highlighted, but may have documentation
@ -199,15 +199,15 @@ loop KEYWORD3 Loop
= assign
& BitwiseAnd
| BitwiseAnd
,
,
// Comments
?:
?:
{} Braces
-- Increment
/ Arithmetic
/* Comments
. dot
==
==
< greaterthan
<= greaterthanorequalto
++ Increment

View File

@ -18,7 +18,7 @@
<marginLine fg="b0b4b9"/>
<markAllHighlight color="ffc800"/>
<markOccurrencesHighlight color="d4d4d4" border="false"/>
<matchedBracket fg="000080" bg="eaeaff" highlightBoth="false" animate="true"/>
<matchedBracket fg="000080" bg="ffffff" highlightBoth="false" animate="true"/>
<hyperlinks fg="0000ff"/>
<secondaryLanguages>
<language index="1" bg="fff0cc"/>
@ -40,7 +40,7 @@
<style token="VARIABLE" fg="cc6600" bold="true"/>
<style token="RESERVED_WORD" fg="024f8b" bold="true"/>
<style token="RESERVED_WORD_2" fg="008080" bold="false"/>
<style token="PREPROCESSOR" fg="024f8b" bold="false"/>
<style token="PREPROCESSOR" fg="000000" bold="false"/>
<style token="ANNOTATION" fg="808080"/>
<style token="COMMENT_DOCUMENTATION" fg="7e7e7e"/>
@ -48,13 +48,13 @@
<style token="COMMENT_MULTILINE" fg="7e7e7e"/>
<style token="COMMENT_KEYWORD" fg="7F9FBF" bold="true"/>
<style token="COMMENT_MARKUP" fg="7f7f9f"/>
<style token="LITERAL_BOOLEAN" fg="ff0000" bold="false"/>
<style token="LITERAL_NUMBER_DECIMAL_INT" fg="ff0000"/>
<style token="LITERAL_NUMBER_FLOAT" fg="ff0000"/>
<style token="LITERAL_NUMBER_HEXADECIMAL" fg="ff0000"/>
<style token="LITERAL_BOOLEAN" fg="000000" bold="false"/>
<style token="LITERAL_NUMBER_DECIMAL_INT" fg="000000"/>
<style token="LITERAL_NUMBER_FLOAT" fg="000000"/>
<style token="LITERAL_NUMBER_HEXADECIMAL" fg="000000"/>
<style token="LITERAL_STRING_DOUBLE_QUOTE" fg="006699"/>
<style token="LITERAL_CHAR" fg="DC009C"/>
<style token="LITERAL_BACKQUOTE" fg="DC009C"/>
<style token="LITERAL_CHAR" fg="006699"/>
<style token="LITERAL_BACKQUOTE" fg="000000"/>
<style token="OPERATOR" fg="804040"/>
<style token="REGEX" fg="008040"/>

View File

@ -77,12 +77,15 @@ editor.brackethighlight.color = #006699
# FUNCTIONS
editor.keyword1.style = #d35400,bold
editor.data_type.style = #d35400,bold
# METHODS
editor.keyword2.style = #D35400,plain
editor.function.style = #d35400,plain
# STRUCTURES
editor.keyword3.style = #5E6D03,plain
editor.reserved_word.style = #5E6D03,plain
# TEXT - LITERALS
@ -92,6 +95,10 @@ editor.literal1.style = #006699,plain
# p5 built in variables: e.g. mouseX, width, pixels
editor.literal2.style = #00979C,plain
editor.variable.style = #00979C,plain
editor.reserved_word_2.style = #00979C,plain
editor.literal_char.style = #00979C,plain
editor.literal_string_double_quote.style = #00979C,plain
# http://arduino.cc/
editor.url.style = #0000ff,underlined