package tools;
import gui.StrTools2;
import java.awt.Color;
import java.util.ArrayList;
import javax.swing.JTextPane;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;
/**
* This class is designed to color polyglot syntax in a text box for easier
* readability.
* @author Jiangcheng Oliver Chu
*/
public class SyntaxColorTools {
private int numOfClosingComments = 0;
private int numOfOpeningComments = 0;
public SyntaxColorTools() {
super();
}
/**
* Adds color styles to a text editor (JTextPane only) so that it can use
* these colors for syntax highlighting. The colors used are show below:
* <br />
* <ul>
* <li>Brown = #define / #enddefine</li>
* <li>Blue = mnemonics</li>
* <li>Light blue = system commands</li>
* <li>Green = comments</li>
* <li>Purple = labels</li>
* </ul>
* @param textPane
*/
public static void addStylesToTextPane(JTextPane textPane) {
Style brownStyle = textPane.addStyle("brown",null);
StyleConstants.setForeground(brownStyle,new Color(0,128,128));
Style blueStyle = textPane.addStyle("blue",null);
StyleConstants.setForeground(blueStyle,new Color(49,109,183));
Style lightBlueStyle = textPane.addStyle("light_blue",null);
StyleConstants.setForeground(lightBlueStyle,new Color(49,109,183));
StyleConstants.setBold(lightBlueStyle, true);
Style greenStyle = textPane.addStyle("green",null);
StyleConstants.setForeground(greenStyle,new Color(21,150,0));
Style purpleStyle = textPane.addStyle("purple",null);
StyleConstants.setBold(purpleStyle, true);
StyleConstants.setForeground(purpleStyle,new Color(137,0,176));
Style grayStyle = textPane.addStyle("gray",null);
StyleConstants.setForeground(grayStyle,new Color(112,128,144));
Style redStyle = textPane.addStyle("red",null);
StyleConstants.setForeground(redStyle, Color.RED);
StyleConstants.setBold(redStyle, true);
textPane.addStyle("empty",null);
}
public void styleJavaCodeInDocument(JTextPane textPane, int beginIndex) {
StyledDocument document = textPane.getStyledDocument();
String text = textPane.getText();
removeStylesFromDocument(textPane,document,beginIndex);
Style blueStyle = textPane.getStyle("blue");
Style lightBlueStyle = textPane.getStyle("light_blue");
Style brownStyle = textPane.getStyle("brown");
Style greenStyle = textPane.getStyle("green");
Style purpleStyle = textPane.getStyle("purple");
Style grayStyle = textPane.getStyle("gray");
Style redStyle = textPane.getStyle("red");
//Color instruction mnemonics blue:
ArrayList<String> allMnemonics;
if (!InstructionTree.getIsTreeLoaded()) {
allMnemonics = JavaResource.getJavaKeywords();
allMnemonics.remove("print");
allMnemonics.addAll(JavaResource.getMnemonicSynonyms());
allMnemonics.addAll(JavaResource.getZeroOperandKeys());
} else {
allMnemonics = new ArrayList<String>();
}
InstructionTree treeObj = new InstructionTree(allMnemonics);
int leafFinderIndex = beginIndex;
String lowerCasedText = text.toLowerCase();
while (true) {
int[] results = treeObj.findNextMnemonicLeafInText(lowerCasedText,
leafFinderIndex);
if (results[0] == -1) {
break;
}
style(document, blueStyle, results[0], results[1]);
leafFinderIndex = results[0] + 1;
}
char ch;
for (ch = '0'; ch < ('9' + 1); ++ch) {
styleExactWording("" + ch, brownStyle,
document, text, beginIndex);
}
//Color the comments green:
styleBlock("//", "\n", greenStyle, document, text, beginIndex);
styleBlock("#", "\n", greenStyle, document, text, beginIndex);
styleExactWording(";", purpleStyle, document, text, beginIndex);
styleExactWording("$", redStyle, document, text, beginIndex);
styleExactWording("$s0", redStyle, document, text, beginIndex);
styleExactWording("$s1", redStyle, document, text, beginIndex);
styleExactWording("$s2", redStyle, document, text, beginIndex);
styleExactWording("$s3", redStyle, document, text, beginIndex);
styleExactWording("$s4", redStyle, document, text, beginIndex);
styleExactWording("$s5", redStyle, document, text, beginIndex);
styleExactWording("$s6", redStyle, document, text, beginIndex);
styleExactWording("$s7", redStyle, document, text, beginIndex);
styleExactWording("$zero", redStyle, document, text, beginIndex);
styleExactWording("$t0", redStyle, document, text, beginIndex);
styleExactWording("$t1", redStyle, document, text, beginIndex);
styleExactWording("$t2", redStyle, document, text, beginIndex);
styleExactWording("$t3", redStyle, document, text, beginIndex);
styleExactWording("$t4", redStyle, document, text, beginIndex);
styleExactWording("$t5", redStyle, document, text, beginIndex);
styleExactWording("$t6", redStyle, document, text, beginIndex);
styleExactWording("$t7", redStyle, document, text, beginIndex);
styleExactWording("<?php", redStyle, document, text, beginIndex);
styleExactWording("?>", redStyle, document, text, beginIndex);
styleBlock("/*", "*/", greenStyle, document, text, beginIndex);
styleBlock("(\"", "\")", grayStyle, document, text, beginIndex);
styleBlock("('", "')", grayStyle, document, text, beginIndex);
styleTextScripts(document, text, lightBlueStyle);
}
private void style(StyledDocument doc,Style style,int begin,int length) {
doc.setCharacterAttributes(begin,length,style,true);
}
void styleJavaCodeInLine(JTextPane textPane,int caretPos) {
StyledDocument document = textPane.getStyledDocument();
String text = textPane.getText();
int lineNum = StrTools.getLineNumber(text,caretPos);
int[] startAndEnd = StrTools.getLineStartAndEnd(text,lineNum);
int start = startAndEnd[0];
int end = startAndEnd[1];
removeStylesFromLine(textPane,document,start,end);
Style blueStyle = textPane.getStyle("blue");
Style lightBlueStyle = textPane.getStyle("light_blue");
Style brownStyle = textPane.getStyle("brown");
Style greenStyle = textPane.getStyle("green");
Style purpleStyle = textPane.getStyle("purple");
//Color instruction mnemonics blue:
ArrayList<String> allMnemonics;
if (!InstructionTree.getIsTreeLoaded()) {
allMnemonics = JavaResource.getJavaKeywords();
allMnemonics.remove("print");
allMnemonics.addAll(JavaResource.getMnemonicSynonyms());
allMnemonics.addAll(JavaResource.getZeroOperandKeys());
} else {
allMnemonics = new ArrayList<String>();
}
InstructionTree treeObj = new InstructionTree(allMnemonics);
int leafFinderIndex = start;
String lowerCasedText = text.toLowerCase();
while (true) {
int[] results = treeObj.findNextMnemonicLeafInTextRange(
lowerCasedText,leafFinderIndex,end);
if (results[0] == -1)
break;
style(document,blueStyle,results[0],results[1]);
leafFinderIndex = results[0] + 1;
}
//Color the comments green:
styleBlockInLine("//", "\n", greenStyle, document, text, start, end);
styleExactWordingInLine(";", purpleStyle, document, text, start, end);
styleBlock("/*","*/",greenStyle,document,text,0);
styleBlockCommentClose(textPane,text,start,end);
styleBlockCommentOpen(textPane,text,start,end);
}
private void styleBlockCommentOpen(JTextPane textPane,String text,
int start,int end) {
String currentLine = StrTools.slice(text,start,end);
int numOfOpeningsInLine =
StrTools.countOccurrences(currentLine,"/*",false);
if (numOfOpeningsInLine < numOfOpeningComments)
undoOpenComment(textPane,text,start,end);
numOfOpeningComments = numOfOpeningsInLine;
}
private void styleBlockCommentClose(JTextPane textPane,String text,
int start,int end) {
String currentLine = StrTools.slice(text,start,end);
int numOfClosingsInLine =
StrTools.countOccurrences(currentLine,"*/",false);
if (numOfClosingsInLine > numOfClosingComments)
closeComment(textPane,text,end);
numOfClosingComments = numOfClosingsInLine;
}
private void undoOpenComment(JTextPane textPane,String text,int startPos,
int endPos) {
String[] givenStrings = {"/*","*/"};
int[] results =
StrTools.searchBackwardsForAnyGiven(text,givenStrings,endPos);
//We have found another opening comment /* right before this erased
//opening comment, so don't do anything.
if (results[1] == 0)
return;
int startUncommentingPos;
if (results[0] != -1 && results[0] > startPos)
startUncommentingPos = results[0];
else
startUncommentingPos = startPos;
styleJavaCodeInDocument(textPane,startUncommentingPos);
}
private void closeComment(JTextPane textPane,String text,int endPos) {
//We need this if statement to prevent searchBackwards()'s .charAt()
//method from crashing the program.
if (endPos >= text.length())
endPos = text.length() - 1;
int closingPos = StrTools.searchBackwards(text,endPos,"*/");
if (closingPos <= 0)
closingPos = 1;
int secondClosingPos =
StrTools.searchBackwards(text,closingPos - 1,"*/");
int openingPos = StrTools.searchBackwards(text,closingPos - 1,"/*");
//If a second closing pos exists after the opening position, then
//it is pointless to restyle the document.
if (secondClosingPos > openingPos)
return;
closingPos += 2;
styleJavaCodeInDocument(textPane,closingPos);
}
static void removeStylesFromDocument(JTextPane textPane,
StyledDocument document,int begin) {
Style emptyStyle = textPane.getStyle("empty");
document.setCharacterAttributes(begin,document.getLength()+1-begin,
emptyStyle,true);
}
private void removeStylesFromLine(JTextPane textPane,
StyledDocument document,
int start,int end) {
Style emptyStyle = textPane.getStyle("empty");
document.setCharacterAttributes(start,end - start,emptyStyle,true);
}
private static void styleExactWording(String wording,Style style,
StyledDocument doc,
String text,int begin) {
int foundPos = begin - 1;
while (true) {
foundPos = StrTools.searchIgnoreCase(text,foundPos+1,wording);
if (foundPos == -1)
break;
doc.setCharacterAttributes(foundPos,wording.length(),style,true);
}
}
private void styleExactWordingInLine(String wording,Style style,
StyledDocument doc,String text,
int start,int end) {
int foundPos = start - 1;
while (true) {
foundPos = StrTools.searchIgnoreCaseInRange(text,foundPos+1,end,
wording);
if (foundPos == -1 || foundPos > end)
break;
doc.setCharacterAttributes(foundPos,wording.length(),style,true);
}
}
private void styleTextScripts(StyledDocument doc, String text,
Style style) {
int curr = -1;
while (true) {
curr = StrTools.searchIgnoreCase(text, curr + 1, "<");
if (curr == -1) {
break;
}
String piece = StrTools2.slice(text, curr + 1, curr + 4);
System.out.println(piece);
boolean isFullyUppercase =
(piece.toUpperCase()).equals(piece);
if (isFullyUppercase) {
doc.setCharacterAttributes(curr, 4, style, true);
}
}
}
private void styleBlock(String blockStart,String blockEnd,
Style style,StyledDocument doc,String text,
int begin) {
int beginPos = begin - 1;
boolean isDone = false;
while (!isDone) {
beginPos = StrTools.searchIgnoreCase(text,
beginPos+1,blockStart);
if (beginPos == -1)
break;
int endPos = StrTools.searchIgnoreCase(text,
beginPos+1,blockEnd);
if (endPos == -1) {
endPos = doc.getLength() - 1;
isDone = true;
}
int styleLength = endPos - beginPos + blockEnd.length();
doc.setCharacterAttributes(beginPos,styleLength,style,true);
}
}
private void styleBlockInLine(String blockStart,String blockEnd,
Style style,StyledDocument doc,
String text,int start,int end) {
int beginPos = start - 1;
boolean isDone = false;
while (!isDone) {
beginPos = StrTools.searchIgnoreCaseInRange(text,
beginPos+1,end,blockStart);
if (beginPos == -1 || beginPos > end)
break;
int endPos = StrTools.searchIgnoreCaseInRange(text,
beginPos+1,end,blockEnd);
if (endPos == -1) {
endPos = end;
isDone = true;
}
int styleLength = endPos - beginPos + blockEnd.length();
doc.setCharacterAttributes(beginPos,styleLength,style,true);
}
}
private static void styleLabels(Style style,StyledDocument doc,
JTextPane currentTextPane,int begin) {
int beginPos = begin - 1;
boolean isDone = false;
String text = currentTextPane.getText();
while (!isDone) {
beginPos = StrTools.search(text,beginPos+1,":");
if (beginPos == -1)
break;
String possibleSegReg = "";
if (beginPos >= 2)
possibleSegReg = StrTools.slice(text,beginPos - 2,beginPos);
if (possibleSegReg.equalsIgnoreCase("ds") ||
possibleSegReg.equalsIgnoreCase("ss")) {
continue;
}
int[] endPositions = new int[6];
//Labels can end with any of these characters!
endPositions[0] = StrTools.search(currentTextPane.getText(),
beginPos+1," ");
endPositions[1] = StrTools.search(currentTextPane.getText(),
beginPos+1,"\n");
endPositions[2] = StrTools.search(currentTextPane.getText(),
beginPos+1,"|");
endPositions[3] = StrTools.search(currentTextPane.getText(),
beginPos+1,"+");
endPositions[4] = StrTools.search(currentTextPane.getText(),
beginPos+1,"-");
endPositions[5] = StrTools.search(currentTextPane.getText(),
beginPos+1,"]");
int endPos = NumberTools.getMinimumPositiveInteger(endPositions);
if (endPos == -1) {
endPos = doc.getLength() - 1;
isDone = true;
}
int styleLength = endPos - beginPos;
if (styleLength < 0)
styleLength = 0;
doc.setCharacterAttributes(beginPos,styleLength,style,true);
}
}
private void styleLabelsInLine(Style style,StyledDocument doc,
JTextPane currentTextPane,int start,int end) {
int beginPos = start - 1;
boolean isDone = false;
String text = currentTextPane.getText();
while (!isDone) {
beginPos = StrTools.searchIgnoreCaseInRange(text,beginPos+1,end,":");
if (beginPos == -1)
break;
String possibleSegReg = "";
if (beginPos >= 2)
possibleSegReg = StrTools.slice(text,beginPos - 2,beginPos);
if (possibleSegReg.equalsIgnoreCase("ds") ||
possibleSegReg.equalsIgnoreCase("ss")) {
continue;
}
int[] endPositions = new int[6];
//Labels can end with any of these characters!
endPositions[0] = StrTools.searchIgnoreCaseInRange(
currentTextPane.getText(),beginPos+1,end," ");
endPositions[1] = StrTools.searchIgnoreCaseInRange(
currentTextPane.getText(),beginPos+1,end,"\n");
endPositions[2] = StrTools.searchIgnoreCaseInRange(
currentTextPane.getText(),beginPos+1,end,"|");
endPositions[3] = StrTools.searchIgnoreCaseInRange(
currentTextPane.getText(),beginPos+1,end,"+");
endPositions[4] = StrTools.searchIgnoreCaseInRange(
currentTextPane.getText(),beginPos+1,end,"-");
endPositions[5] = StrTools.searchIgnoreCaseInRange(
currentTextPane.getText(),beginPos+1,end,"]");
int endPos = NumberTools.getMinimumPositiveInteger(endPositions);
if (endPos == -1) {
endPos = end;
isDone = true;
}
int styleLength = endPos - beginPos;
if (styleLength < 0)
styleLength = 0;
doc.setCharacterAttributes(beginPos,styleLength,style,true);
}
}
}