📄 tokenmarker.java
字号:
/* * TokenMarker.java - Tokenizes lines of text * Copyright (C) 1998, 1999, 2000, 2001 Slava Pestov * Copyright (C) 1999, 2000 mike dillon * * 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;import javax.swing.text.*;import java.util.*;import org.gjt.sp.jedit.*;import org.gjt.sp.util.Log;/** * A token marker splits lines of text into tokens. Each token carries * a length field and an identification tag that can be mapped to a color * or font style for painting that token. * * @author Slava Pestov, mike dillon * @version $Id: TokenMarker.java,v 1.1.1.1 2001/09/02 05:38:02 spestov Exp $ * * @see org.gjt.sp.jedit.syntax.Token */public class TokenMarker{ // major actions (total: 8) public static final int MAJOR_ACTIONS = 0x000000FF; public static final int WHITESPACE = 1 << 0; public static final int SPAN = 1 << 1; public static final int MARK_PREVIOUS = 1 << 2; public static final int MARK_FOLLOWING = 1 << 3; public static final int EOL_SPAN = 1 << 4;// public static final int MAJOR_ACTION_5 = 1 << 5;// public static final int MAJOR_ACTION_6 = 1 << 6;// public static final int MAJOR_ACTION_7 = 1 << 7; // action hints (total: 8) public static final int ACTION_HINTS = 0x0000FF00; public static final int EXCLUDE_MATCH = 1 << 8; public static final int AT_LINE_START = 1 << 9; public static final int NO_LINE_BREAK = 1 << 10; public static final int NO_WORD_BREAK = 1 << 11; public static final int IS_ESCAPE = 1 << 12; public static final int DELEGATE = 1 << 13;// public static final int ACTION_HINT_14 = 1 << 14;// public static final int ACTION_HINT_15 = 1 << 15; public TokenMarker() { ruleSets = new Hashtable(64); } public void addRuleSet(String setName, ParserRuleSet rules) { if (rules == null) return; if (setName == null) setName = "MAIN"; ruleSets.put(rulePfx.concat(setName), rules); } public ParserRuleSet getMainRuleSet() { return getRuleSet(rulePfx + "MAIN"); } public ParserRuleSet getRuleSet(String setName) { ParserRuleSet rules; rules = (ParserRuleSet) ruleSets.get(setName); if (rules == null && !setName.startsWith(rulePfx)) { int delim = setName.indexOf("::"); String modeName = setName.substring(0, delim); Mode mode = jEdit.getMode(modeName); if(mode == null) { Log.log(Log.ERROR,TokenMarker.class, "Unknown edit mode: " + modeName); rules = null; } else { TokenMarker marker = mode.getTokenMarker(); rules = marker.getRuleSet(setName); } // store external ParserRuleSet in the local hashtable for // faster lookups later ruleSets.put(setName, rules); } if (rules == null) { Log.log(Log.ERROR,this,"Unresolved delegate target: " + setName); } return rules; } public String getName() { return name; } public void setName(String name) { if (name == null) throw new NullPointerException(); this.name = name; rulePfx = name.concat("::"); } /** * Do not call this method directly; call Buffer.markTokens() instead. */ public void markTokens(Buffer.LineInfo prevInfo, Buffer.LineInfo info, Segment line) { LineContext lastContext = (prevInfo == null ? null : prevInfo.context); if(lastContext == null) { lastContext = new LineContext(null, getRuleSet(rulePfx.concat("MAIN"))); } context = info.context; context.parent = (lastContext.parent == null ? null : (LineContext)lastContext.parent.clone()); context.inRule = lastContext.inRule; context.rules = lastContext.rules; lastOffset = lastKeyword = line.offset; lineLength = line.count + line.offset; int terminateChar = context.rules.getTerminateChar(); int searchLimit = (terminateChar >= 0 && terminateChar < line.count) ? line.offset + terminateChar : lineLength; escaped = false; boolean b; boolean tempEscaped; Segment tempPattern; ParserRule rule; LineContext tempContext; for(pos = line.offset; pos < searchLimit; pos++) { // if we are not in the top level context, we are delegated if (context.parent != null) { tempContext = context; context = context.parent; pattern.array = context.inRule.searchChars; pattern.count = context.inRule.sequenceLengths[1]; pattern.offset = context.inRule.sequenceLengths[0]; b = handleRule(info, line, context.inRule); context = tempContext; if (!b) { if (escaped) { escaped = false; } else { if (pos != lastOffset) { if (context.inRule == null) { markKeyword(info,line,lastKeyword,pos); info.addToken(pos - lastOffset, context.rules.getDefault()); } else if ((context.inRule.action & (NO_LINE_BREAK | NO_WORD_BREAK)) == 0) { info.addToken(pos - lastOffset, context.inRule.token); } else { info.addToken(pos - lastOffset, Token.INVALID); } } context = (LineContext) context.parent; if ((context.inRule.action & EXCLUDE_MATCH) == EXCLUDE_MATCH) { info.addToken(pattern.count, context.rules.getDefault()); } else { info.addToken(pattern.count,context.inRule.token); } context.inRule = null; lastKeyword = lastOffset = pos + pattern.count; } pos += (pattern.count - 1); // move pos to last character of match sequence continue; } } // check the escape rule for the current context, if there is one if ((rule = context.rules.getEscapeRule()) != null) { // assign tempPattern to mutable "buffer" pattern tempPattern = pattern; // swap in the escape pattern pattern = context.rules.getEscapePattern(); tempEscaped = escaped; b = handleRule(info, line, rule); // swap back the buffer pattern pattern = tempPattern; if (!b) { if (tempEscaped) escaped = false; continue; } } // if we are inside a span, check for its end sequence rule = context.inRule; if(rule != null && (rule.action & SPAN) == SPAN) { pattern.array = rule.searchChars; pattern.count = rule.sequenceLengths[1]; pattern.offset = rule.sequenceLengths[0]; // if we match the end of the span, or if this is a "hard" span, // we continue to the next character; otherwise, we check all // applicable rules below if (!handleRule(info,line,rule) || (rule.action & SOFT_SPAN) == 0) { escaped = false; continue; } } // now check every rule rule = context.rules.getRules(line.array[pos]); while(rule != null) { pattern.array = rule.searchChars; if (context.inRule == rule && (rule.action & SPAN) == SPAN) { pattern.count = rule.sequenceLengths[1]; pattern.offset = rule.sequenceLengths[0]; } else { pattern.count = rule.sequenceLengths[0]; pattern.offset = 0; } // stop checking rules if there was a match and go to next pos if (!handleRule(info,line,rule)) break; rule = rule.next; } escaped = false; } // check for keywords at the line's end if(context.inRule == null) markKeyword(info, line, lastKeyword, lineLength); // mark all remaining characters if(lastOffset != lineLength) { if (context.inRule == null) { info.addToken(lineLength - lastOffset, context.rules.getDefault()); } else if ( (context.inRule.action & SPAN) == SPAN && (context.inRule.action & (NO_LINE_BREAK | NO_WORD_BREAK)) != 0 ) { info.addToken(lineLength - lastOffset,Token.INVALID); context.inRule = null; } else { info.addToken(lineLength - lastOffset,context.inRule.token); if((context.inRule.action & MARK_FOLLOWING) == MARK_FOLLOWING) { context.inRule = null; } } } info.context = context; } // private members private static final int SOFT_SPAN = MARK_FOLLOWING | NO_WORD_BREAK; private String name; private String rulePfx; private Hashtable ruleSets; private LineContext context; private Segment pattern = new Segment(new char[0],0,0); private int lastOffset; private int lastKeyword; private int lineLength; private int pos; private boolean escaped; /** * Checks if the rule matches the line at the current position * and handles the rule if it does match * @param line Segment to check rule against * @param checkRule ParserRule to check against line * @return true, keep checking other rules * <br>false, stop checking other rules */ private boolean handleRule(Buffer.LineInfo info, Segment line, ParserRule checkRule) { if (pattern.count == 0) return true; if (lineLength - pos < pattern.count) return true; char a, b; for (int k = 0; k < pattern.count; k++) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -