org.gjt.sp.jedit.syntax.XModeHandler Maven / Gradle / Ivy
Go to download
This project aims to build a command line tool that can create
HTML view with syntax highlighted source code.
It uses Jedit syntax highlighting engine and support all languages that are supported in JEdit.
Which are currently: ActionScript, Ada 95, ANTLR, Apache HTTPD, APDL, AppleScript, ASP, Aspect-J, Assembly, AWK, B formal method, Batch, BBj, BCEL, BibTeX, C, C++, C#, CHILL, CIL, COBOL, ColdFusion, CSS, CVS Commit, D, DOxygen, DSSSL, Eiffel, EmbPerl, Erlang, Factor, Fortran, Foxpro, FreeMarker, Fortran, Gettext, Groovy, Haskell, HTML, Icon, IDL, Inform, INI, Inno Setup, Informix 4GL, Interlis, Io, Java, JavaScript, JCL, JHTML, JMK, JSP, Latex, Lilypond, Lisp, LOTOS, Lua, Makefile, Maple, ML, Modula-3, MoinMoin, MQSC, NetRexx, NQC, NSIS2, Objective C, ObjectRexx, Occam, Omnimark, Parrot, Pascal, Patch, Perl, PHP, Pike, PL-SQL, PL/I, Pop11, PostScript, Povray, PowerDynamo, Progress 4GL, Prolog, Properties, PSP, PV-WAVE, Pyrex, Python, REBOL, Redcode, Relax-NG, RelationalView, Rest, Rib, RPM spec, RTF, Ruby, Ruby-HTML, RView, S+, S#, SAS, Scheme, SDL/PL, SGML, Shell Script, SHTML, Smalltalk, SMI MIB, SQR, Squidconf, SVN Commit, Swig, TCL, TeX, Texinfo, TPL, Transact-SQL, UnrealScript, VBScript, Velocity, Verilog, VHDL, XML, XSL, ZPT
The newest version!
/*
* XModeHandler.java - XML handler for mode files
* :tabSize=8:indentSize=8:noTabs=false:
* :folding=explicit:collapseFolds=1:
*
* Copyright (C) 1999 mike dillon
* Portions copyright (C) 2000, 2001 Slava Pestov
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.gjt.sp.jedit.syntax;
//{{{ Imports
import java.util.*;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.helpers.DefaultHandler;
import org.gjt.sp.jedit.Mode;
import org.gjt.sp.util.Log;
import org.gjt.sp.util.XMLUtilities;
//}}}
/**
* XML handler for mode definition files.
* @version $Id: XModeHandler.java 12875 2008-06-22 10:28:48Z kpouer $
*/
public abstract class XModeHandler extends DefaultHandler
{
//{{{ XModeHandler constructor
public XModeHandler (String modeName)
{
this.modeName = modeName;
marker = new TokenMarker();
marker.addRuleSet(new ParserRuleSet(modeName,"MAIN"));
stateStack = new Stack();
} //}}}
//{{{ resolveEntity() method
public InputSource resolveEntity(String publicId, String systemId)
{
return XMLUtilities.findEntity(systemId, "xmode.dtd", XModeHandler.class);
} //}}}
//{{{ characters() method
public void characters(char[] c, int off, int len)
{
peekElement().setText(c, off, len);
} //}}}
//{{{ startElement() method
public void startElement(String uri, String localName,
String qName, Attributes attrs)
{
TagDecl tag = pushElement(qName, attrs);
if (qName.equals("WHITESPACE"))
{
Log.log(Log.WARNING,this,modeName + ": WHITESPACE rule "
+ "no longer needed");
}
else if (qName.equals("KEYWORDS"))
{
keywords = new KeywordMap(rules.getIgnoreCase());
}
else if (qName.equals("RULES"))
{
if(tag.lastSetName == null)
tag.lastSetName = "MAIN";
rules = marker.getRuleSet(tag.lastSetName);
if(rules == null)
{
rules = new ParserRuleSet(modeName,tag.lastSetName);
marker.addRuleSet(rules);
}
rules.setIgnoreCase(tag.lastIgnoreCase);
rules.setHighlightDigits(tag.lastHighlightDigits);
if(tag.lastDigitRE != null)
{
try
{
rules.setDigitRegexp(Pattern.compile(tag.lastDigitRE,
tag.lastIgnoreCase
? Pattern.CASE_INSENSITIVE : 0));
}
catch(PatternSyntaxException e)
{
error("regexp",e);
}
}
if(tag.lastEscape != null)
rules.setEscapeRule(ParserRule.createEscapeRule(tag.lastEscape));
rules.setDefault(tag.lastDefaultID);
rules.setNoWordSep(tag.lastNoWordSep);
}
} //}}}
//{{{ endElement() method
public void endElement(String uri, String localName, String name)
{
TagDecl tag = popElement();
if (name.equals(tag.tagName))
{
if(tag.lastDelegateSet != null
&& ! tag.tagName.equals("IMPORT")
&& ! tag.lastDelegateSet.getModeName().equals(modeName))
{
Mode mode = ModeProvider.instance.getMode(tag.lastDelegateSet.getModeName());
if( ! reloadModes.contains(mode) )
{
reloadModes.add(mode);
}
}
//{{{ PROPERTY
if (tag.tagName.equals("PROPERTY"))
{
props.put(propName,propValue);
} //}}}
//{{{ PROPS
else if (tag.tagName.equals("PROPS"))
{
if(peekElement().tagName.equals("RULES"))
rules.setProperties(props);
else
modeProps = props;
props = new Hashtable();
} //}}}
//{{{ RULES
else if (tag.tagName.equals("RULES"))
{
rules.setKeywords(keywords);
keywords = null;
rules = null;
} //}}}
//{{{ IMPORT
else if (tag.tagName.equals("IMPORT"))
{
// prevent lockups
if (!rules.equals(tag.lastDelegateSet))
{
rules.addRuleSet(tag.lastDelegateSet);
}
} //}}}
//{{{ TERMINATE
else if (tag.tagName.equals("TERMINATE"))
{
rules.setTerminateChar(tag.termChar);
} //}}}
//{{{ SEQ
else if (tag.tagName.equals("SEQ"))
{
if(tag.lastStart == null)
{
error("empty-tag","SEQ");
return;
}
rules.addRule(ParserRule.createSequenceRule(
tag.lastStartPosMatch,tag.lastStart.toString(),
tag.lastDelegateSet,tag.lastTokenID));
} //}}}
//{{{ SEQ_REGEXP
else if (tag.tagName.equals("SEQ_REGEXP"))
{
if(tag.lastStart == null)
{
error("empty-tag","SEQ_REGEXP");
return;
}
try
{
if (null != tag.lastHashChars)
{
rules.addRule(ParserRule.createRegexpSequenceRule(
tag.lastStartPosMatch,tag.lastHashChars.toCharArray(),
tag.lastStart.toString(),tag.lastDelegateSet,
tag.lastTokenID,findParent("RULES").lastIgnoreCase));
}
else
{
rules.addRule(ParserRule.createRegexpSequenceRule(
tag.lastHashChar,tag.lastStartPosMatch,
tag.lastStart.toString(),tag.lastDelegateSet,
tag.lastTokenID,findParent("RULES").lastIgnoreCase));
}
}
catch(PatternSyntaxException re)
{
error("regexp",re);
}
} //}}}
//{{{ SPAN
else if (tag.tagName.equals("SPAN"))
{
if(tag.lastStart == null)
{
error("empty-tag","BEGIN");
return;
}
if(tag.lastEnd == null)
{
error("empty-tag","END");
return;
}
rules.addRule(ParserRule
.createSpanRule(
tag.lastStartPosMatch,tag.lastStart.toString(),
tag.lastEndPosMatch,tag.lastEnd.toString(),
tag.lastDelegateSet,
tag.lastTokenID,tag.lastMatchType,
tag.lastNoLineBreak,
tag.lastNoWordBreak,
tag.lastEscape));
} //}}}
//{{{ SPAN_REGEXP
else if (tag.tagName.equals("SPAN_REGEXP"))
{
if(tag.lastStart == null)
{
error("empty-tag","BEGIN");
return;
}
if(tag.lastEnd == null)
{
error("empty-tag","END");
return;
}
try
{
if (null != tag.lastHashChars)
{
rules.addRule(ParserRule
.createRegexpSpanRule(
tag.lastStartPosMatch,tag.lastHashChars.toCharArray(),
tag.lastStart.toString(),
tag.lastEndPosMatch,tag.lastEnd.toString(),
tag.lastDelegateSet,
tag.lastTokenID,
tag.lastMatchType,
tag.lastNoLineBreak,
tag.lastNoWordBreak,
findParent("RULES").lastIgnoreCase,
tag.lastEscape));
}
else
{
rules.addRule(ParserRule
.createRegexpSpanRule(
tag.lastHashChar,
tag.lastStartPosMatch,tag.lastStart.toString(),
tag.lastEndPosMatch,tag.lastEnd.toString(),
tag.lastDelegateSet,
tag.lastTokenID,
tag.lastMatchType,
tag.lastNoLineBreak,
tag.lastNoWordBreak,
findParent("RULES").lastIgnoreCase,
tag.lastEscape));
}
}
catch(PatternSyntaxException re)
{
error("regexp",re);
}
} //}}}
//{{{ EOL_SPAN
else if (tag.tagName.equals("EOL_SPAN"))
{
if(tag.lastStart == null)
{
error("empty-tag","EOL_SPAN");
return;
}
rules.addRule(ParserRule.createEOLSpanRule(
tag.lastStartPosMatch,tag.lastStart.toString(),
tag.lastDelegateSet,tag.lastTokenID,
tag.lastMatchType));
} //}}}
//{{{ EOL_SPAN_REGEXP
else if (tag.tagName.equals("EOL_SPAN_REGEXP"))
{
if(tag.lastStart == null)
{
error("empty-tag","EOL_SPAN_REGEXP");
return;
}
try
{
if (null != tag.lastHashChars)
{
rules.addRule(ParserRule.createRegexpEOLSpanRule(
tag.lastStartPosMatch,tag.lastHashChars.toCharArray(),
tag.lastStart.toString(),tag.lastDelegateSet,
tag.lastTokenID,tag.lastMatchType,
findParent("RULES").lastIgnoreCase));
}
else
{
rules.addRule(ParserRule.createRegexpEOLSpanRule(
tag.lastHashChar,tag.lastStartPosMatch,
tag.lastStart.toString(),tag.lastDelegateSet,
tag.lastTokenID,tag.lastMatchType,
findParent("RULES").lastIgnoreCase));
}
}
catch(PatternSyntaxException re)
{
error("regexp",re);
}
} //}}}
//{{{ MARK_FOLLOWING
else if (tag.tagName.equals("MARK_FOLLOWING"))
{
if(tag.lastStart == null)
{
error("empty-tag","MARK_FOLLOWING");
return;
}
rules.addRule(ParserRule
.createMarkFollowingRule(
tag.lastStartPosMatch,tag.lastStart.toString(),
tag.lastTokenID,tag.lastMatchType));
} //}}}
//{{{ MARK_PREVIOUS
else if (tag.tagName.equals("MARK_PREVIOUS"))
{
if(tag.lastStart == null)
{
error("empty-tag","MARK_PREVIOUS");
return;
}
rules.addRule(ParserRule
.createMarkPreviousRule(
tag.lastStartPosMatch,tag.lastStart.toString(),
tag.lastTokenID,tag.lastMatchType));
} //}}}
//{{{ Keywords
else if (
!tag.tagName.equals("END")
&& !tag.tagName.equals("BEGIN")
&& !tag.tagName.equals("KEYWORDS")
&& !tag.tagName.equals("MODE")
) {
byte token = Token.stringToToken(tag.tagName);
if(token != -1)
addKeyword(tag.lastKeyword.toString(),token);
} //}}}
}
else
{
// can't happen
throw new InternalError();
}
} //}}}
//{{{ startDocument() method
public void startDocument()
{
props = new Hashtable();
pushElement(null, null);
reloadModes = new Vector();
} //}}}
//{{{ endDocument() method
public void endDocument()
{
ParserRuleSet[] rulesets = marker.getRuleSets();
for(int i = 0; i < rulesets.length; i++)
{
rulesets[i].resolveImports();
}
for(Mode mode : reloadModes)
{
mode.setTokenMarker(null);
mode.loadIfNecessary();
}
} //}}}
//{{{ getTokenMarker() method
/**
* Returns the TokenMarker.
*
* @return a TokenMarker it cannot be null
*/
public TokenMarker getTokenMarker()
{
return marker;
} //}}}
//{{{ getModeProperties() method
public Hashtable getModeProperties()
{
return modeProps;
} //}}}
//{{{ Protected members
//{{{ error() method
/**
* Reports an error.
* You must override this method so that the mode loader can do error
* reporting.
* @param msg The error type
* @param subst A String
or a Throwable
* containing specific information
* @since jEdit 4.2pre1
*/
protected abstract void error(String msg, Object subst);
//}}}
//{{{ getTokenMarker() method
/**
* Returns the token marker for the given mode.
* You must override this method so that the mode loader can resolve
* delegate targets.
* @param mode The mode name
* @since jEdit 4.2pre1
*/
protected abstract TokenMarker getTokenMarker(String mode);
//}}}
//}}}
//{{{ Private members
//{{{ Instance variables
private String modeName;
/** The token marker cannot be null. */
private final TokenMarker marker;
private KeywordMap keywords;
/** this stack can contains null elements. */
private Stack stateStack;
private String propName;
private String propValue;
private Hashtable props;
private Hashtable modeProps;
private ParserRuleSet rules;
/**
* A list of modes to be reloaded at the end, loaded through DELEGATEs
* @see http://sourceforge.net/tracker/index.php?func=detail&aid=1742250&group_id=588&atid=100588
*/
private Vector reloadModes;
//}}}
//{{{ addKeyword() method
private void addKeyword(String k, byte id)
{
if(k == null)
{
error("empty-keyword",null);
return;
}
if (keywords == null) return;
keywords.add(k,id);
} //}}}
//{{{ pushElement() method
private TagDecl pushElement(String name, Attributes attrs)
{
if (name != null)
{
TagDecl tag = new TagDecl(name, attrs);
stateStack.push(tag);
return tag;
}
else
{
stateStack.push(null);
return null;
}
} //}}}
//{{{ peekElement() method
private TagDecl peekElement()
{
return stateStack.peek();
} //}}}
//{{{ popElement() method
private TagDecl popElement()
{
return stateStack.pop();
} //}}}
//{{{ findParent() method
/**
* Finds the first element whose tag matches 'tagName',
* searching backwards in the stack.
*/
private TagDecl findParent(String tagName)
{
for (int idx = stateStack.size() - 1; idx >= 0; idx--)
{
TagDecl tag = stateStack.get(idx);
if (tag.tagName.equals(tagName))
return tag;
}
return null;
} //}}}
//}}}
/**
* Hold info about what tag was read and what attributes were
* set in the XML file, to be kept by the handler in a stack
* (similar to the way tag names were kept in a stack before).
*/
private class TagDecl
{
public TagDecl(String tagName, Attributes attrs)
{
this.tagName = tagName;
String tmp;
propName = attrs.getValue("NAME");
propValue = attrs.getValue("VALUE");
tmp = attrs.getValue("TYPE");
if (tmp != null)
{
lastTokenID = Token.stringToToken(tmp);
if(lastTokenID == -1)
error("token-invalid",tmp);
}
lastMatchType = ParserRule.MATCH_TYPE_RULE;
// check for the deprecated "EXCLUDE_MATCH" and
// warn if found.
tmp = attrs.getValue("EXCLUDE_MATCH");
if (tmp != null)
{
Log.log(Log.WARNING, this, modeName + ": EXCLUDE_MATCH is deprecated");
if ("TRUE".equalsIgnoreCase(tmp))
{
lastMatchType = ParserRule.MATCH_TYPE_CONTEXT;
}
}
// override with the newer MATCH_TYPE if present
tmp = attrs.getValue("MATCH_TYPE");
if (tmp != null)
{
if ("CONTEXT".equals(tmp))
{
lastMatchType = ParserRule.MATCH_TYPE_CONTEXT;
}
else if ("RULE".equals(tmp))
{
lastMatchType = ParserRule.MATCH_TYPE_RULE;
}
else
{
lastMatchType = Token.stringToToken(tmp);
if(lastMatchType == -1)
error("token-invalid",tmp);
}
}
lastAtLineStart = "TRUE".equals(attrs.getValue("AT_LINE_START"));
lastAtWhitespaceEnd = "TRUE".equals(attrs.getValue("AT_WHITESPACE_END"));
lastAtWordStart = "TRUE".equals(attrs.getValue("AT_WORD_START"));
lastNoLineBreak = "TRUE".equals(attrs.getValue("NO_LINE_BREAK"));
lastNoWordBreak = "TRUE".equals(attrs.getValue("NO_WORD_BREAK"));
lastIgnoreCase = (attrs.getValue("IGNORE_CASE") == null ||
"TRUE".equals(attrs.getValue("IGNORE_CASE")));
lastHighlightDigits = "TRUE".equals(attrs.getValue("HIGHLIGHT_DIGITS"));;
lastDigitRE = attrs.getValue("DIGIT_RE");
tmp = attrs.getValue("NO_WORD_SEP");
if (tmp != null)
lastNoWordSep = tmp;
tmp = attrs.getValue("AT_CHAR");
if (tmp != null)
{
try
{
termChar = Integer.parseInt(tmp);
}
catch (NumberFormatException e)
{
error("termchar-invalid",tmp);
termChar = -1;
}
}
lastEscape = attrs.getValue("ESCAPE");
lastSetName = attrs.getValue("SET");
tmp = attrs.getValue("DELEGATE");
if (tmp != null)
{
String delegateMode, delegateSetName;
int index = tmp.indexOf("::");
if(index != -1)
{
delegateMode = tmp.substring(0,index);
delegateSetName = tmp.substring(index + 2);
}
else
{
delegateMode = modeName;
delegateSetName = tmp;
}
TokenMarker delegateMarker = getTokenMarker(delegateMode);
if(delegateMarker == null)
error("delegate-invalid",tmp);
else
{
lastDelegateSet = delegateMarker
.getRuleSet(delegateSetName);
if(delegateMarker == marker
&& lastDelegateSet == null)
{
// stupid hack to handle referencing
// a rule set that is defined later!
lastDelegateSet = new ParserRuleSet(
delegateMode,
delegateSetName);
lastDelegateSet.setDefault(Token.INVALID);
marker.addRuleSet(lastDelegateSet);
}
else if(lastDelegateSet == null)
error("delegate-invalid",tmp);
}
}
tmp = attrs.getValue("DEFAULT");
if (tmp != null)
{
lastDefaultID = Token.stringToToken(tmp);
if(lastDefaultID == -1)
{
error("token-invalid",tmp);
lastDefaultID = Token.NULL;
}
}
lastHashChar = attrs.getValue("HASH_CHAR");
lastHashChars = attrs.getValue("HASH_CHARS");
if ((null != lastHashChar) && (null != lastHashChars))
{
error("hash-char-and-hash-chars-mutually-exclusive",null);
lastHashChars = null;
}
}
public void setText(char[] c, int off, int len)
{
if (tagName.equals("EOL_SPAN") ||
tagName.equals("EOL_SPAN_REGEXP") ||
tagName.equals("MARK_PREVIOUS") ||
tagName.equals("MARK_FOLLOWING") ||
tagName.equals("SEQ") ||
tagName.equals("SEQ_REGEXP") ||
tagName.equals("BEGIN")
)
{
TagDecl target = this;
if (tagName.equals("BEGIN"))
target = stateStack.get(stateStack.size() - 2);
if (target.lastStart == null)
{
target.lastStart = new StringBuffer();
target.lastStart.append(c, off, len);
target.lastStartPosMatch = ((target.lastAtLineStart ? ParserRule.AT_LINE_START : 0)
| (target.lastAtWhitespaceEnd ? ParserRule.AT_WHITESPACE_END : 0)
| (target.lastAtWordStart ? ParserRule.AT_WORD_START : 0));
target.lastAtLineStart = false;
target.lastAtWordStart = false;
target.lastAtWhitespaceEnd = false;
}
else
{
target.lastStart.append(c, off, len);
}
}
else if (tagName.equals("END"))
{
TagDecl target = stateStack.get(stateStack.size() - 2);
if (target.lastEnd == null)
{
target.lastEnd = new StringBuffer();
target.lastEnd.append(c, off, len);
target.lastEndPosMatch = ((this.lastAtLineStart ? ParserRule.AT_LINE_START : 0)
| (this.lastAtWhitespaceEnd ? ParserRule.AT_WHITESPACE_END : 0)
| (this.lastAtWordStart ? ParserRule.AT_WORD_START : 0));
target.lastAtLineStart = false;
target.lastAtWordStart = false;
target.lastAtWhitespaceEnd = false;
}
else
{
target.lastEnd.append(c, off, len);
}
}
else
{
if (lastKeyword == null)
lastKeyword = new StringBuffer();
lastKeyword.append(c, off, len);
}
}
public String tagName;
public StringBuffer lastStart;
public StringBuffer lastEnd;
public StringBuffer lastKeyword;
public String lastSetName;
public String lastEscape;
public ParserRuleSet lastDelegateSet;
public String lastNoWordSep = "_";
public ParserRuleSet rules;
public byte lastDefaultID = Token.NULL;
public byte lastTokenID;
public byte lastMatchType;
public int termChar = -1;
public boolean lastNoLineBreak;
public boolean lastNoWordBreak;
public boolean lastIgnoreCase = true;
public boolean lastHighlightDigits;
public boolean lastAtLineStart;
public boolean lastAtWhitespaceEnd;
public boolean lastAtWordStart;
public int lastStartPosMatch;
public int lastEndPosMatch;
public String lastDigitRE;
public String lastHashChar;
public String lastHashChars;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy