001: package net.xoetrope.builder.editor.syntaxhighlight;
002:
003: /*
004: * ShellScriptTokenMarker.java - Shell script token marker
005: * Copyright (C) 1998, 1999 Slava Pestov
006: *
007: * You may use and modify this package for any purpose. Redistribution is
008: * permitted, in both source and binary form, provided that this notice
009: * remains intact in all source distributions of this package.
010: */
011:
012: import javax.swing.text.Segment;
013:
014: /**
015: * Shell script token marker.
016: *
017: * @author Slava Pestov
018: * @version $Id: ShellScriptTokenMarker.java,v 1.22 2005/01/05 17:20:49 luano Exp $
019: */
020: public class ShellScriptTokenMarker extends TokenMarker {
021: // public members
022: public static final byte LVARIABLE = Token.INTERNAL_FIRST;
023:
024: public byte markTokensImpl(byte token, Segment line, int lineIndex) {
025: char[] array = line.array;
026: byte cmdState = 0; // 0 = space before command, 1 = inside
027: // command, 2 = after command
028: int offset = line.offset;
029: int lastOffset = offset;
030: int length = line.count + offset;
031:
032: if (token == Token.LITERAL1 && lineIndex != 0
033: && lineInfo[lineIndex - 1].obj != null) {
034: String str = (String) lineInfo[lineIndex - 1].obj;
035: if (str != null
036: && str.length() == line.count
037: && SyntaxUtilities.regionMatches(false, line,
038: offset, str)) {
039: addToken(line.count, Token.LITERAL1);
040: return Token.NULL;
041: } else {
042: addToken(line.count, Token.LITERAL1);
043: lineInfo[lineIndex].obj = str;
044: return Token.LITERAL1;
045: }
046: }
047:
048: boolean backslash = false;
049: loop: for (int i = offset; i < length; i++) {
050: int i1 = (i + 1);
051:
052: char c = array[i];
053:
054: if (c == '\\') {
055: backslash = !backslash;
056: continue;
057: }
058:
059: switch (token) {
060: case Token.NULL:
061: switch (c) {
062: case ' ':
063: case '\t':
064: case '(':
065: case ')':
066: backslash = false;
067: if (cmdState == 1/*insideCmd*/) {
068: addToken(i - lastOffset, Token.KEYWORD1);
069: lastOffset = i;
070: cmdState = 2; /*afterCmd*/
071: }
072: break;
073: case '=':
074: backslash = false;
075: if (cmdState == 1/*insideCmd*/) {
076: addToken(i - lastOffset, token);
077: lastOffset = i;
078: cmdState = 2; /*afterCmd*/
079: }
080: break;
081: case '&':
082: case '|':
083: case ';':
084: if (backslash)
085: backslash = false;
086: else
087: cmdState = 0; /*beforeCmd*/
088: break;
089: case '#':
090: if (backslash)
091: backslash = false;
092: else {
093: addToken(i - lastOffset, token);
094: addToken(length - i, Token.COMMENT1);
095: lastOffset = length;
096: break loop;
097: }
098: break;
099: case '$':
100: if (backslash)
101: backslash = false;
102: else {
103: addToken(i - lastOffset, token);
104: cmdState = 2; /*afterCmd*/
105: lastOffset = i;
106: if (length - i >= 2) {
107: switch (array[i1]) {
108: case '(':
109: continue;
110: case '{':
111: token = LVARIABLE;
112: break;
113: default:
114: token = Token.KEYWORD2;
115: break;
116: }
117: } else
118: token = Token.KEYWORD2;
119: }
120: break;
121: case '"':
122: if (backslash)
123: backslash = false;
124: else {
125: addToken(i - lastOffset, token);
126: token = Token.LITERAL1;
127: lineInfo[lineIndex].obj = null;
128: cmdState = 2; /*afterCmd*/
129: lastOffset = i;
130: }
131: break;
132: case '\'':
133: if (backslash)
134: backslash = false;
135: else {
136: addToken(i - lastOffset, token);
137: token = Token.LITERAL2;
138: cmdState = 2; /*afterCmd*/
139: lastOffset = i;
140: }
141: break;
142: case '<':
143: if (backslash)
144: backslash = false;
145: else {
146: if (length - i > 1 && array[i1] == '<') {
147: addToken(i - lastOffset, token);
148: token = Token.LITERAL1;
149: lastOffset = i;
150: lineInfo[lineIndex].obj = new String(array,
151: i + 2, length - (i + 2));
152: }
153: }
154: break;
155: default:
156: backslash = false;
157: if (Character.isLetter(c)) {
158: if (cmdState == 0 /*beforeCmd*/) {
159: addToken(i - lastOffset, token);
160: lastOffset = i;
161: cmdState++; /*insideCmd*/
162: }
163: }
164: break;
165: }
166: break;
167: case Token.KEYWORD2:
168: backslash = false;
169: if (!Character.isLetterOrDigit(c) && c != '_') {
170: if (i != offset && array[i - 1] == '$') {
171: addToken(i1 - lastOffset, token);
172: lastOffset = i1;
173: token = Token.NULL;
174: continue;
175: } else {
176: addToken(i - lastOffset, token);
177: lastOffset = i;
178: token = Token.NULL;
179: }
180: }
181: break;
182: case Token.LITERAL1:
183: if (backslash)
184: backslash = false;
185: else if (c == '"') {
186: addToken(i1 - lastOffset, token);
187: cmdState = 2; /*afterCmd*/
188: lastOffset = i1;
189: token = Token.NULL;
190: } else
191: backslash = false;
192: break;
193: case Token.LITERAL2:
194: if (backslash)
195: backslash = false;
196: else if (c == '\'') {
197: addToken(i1 - lastOffset, Token.LITERAL1);
198: cmdState = 2; /*afterCmd*/
199: lastOffset = i1;
200: token = Token.NULL;
201: } else
202: backslash = false;
203: break;
204: case LVARIABLE:
205: backslash = false;
206: if (c == '}') {
207: addToken(i1 - lastOffset, Token.KEYWORD2);
208: lastOffset = i1;
209: token = Token.NULL;
210: }
211: break;
212: default:
213: throw new InternalError("Invalid state: " + token);
214: }
215: }
216:
217: switch (token) {
218: case Token.NULL:
219: if (cmdState == 1)
220: addToken(length - lastOffset, Token.KEYWORD1);
221: else
222: addToken(length - lastOffset, token);
223: break;
224: case Token.LITERAL2:
225: addToken(length - lastOffset, Token.LITERAL1);
226: break;
227: case Token.KEYWORD2:
228: addToken(length - lastOffset, token);
229: token = Token.NULL;
230: break;
231: case LVARIABLE:
232: addToken(length - lastOffset, Token.INVALID);
233: token = Token.NULL;
234: break;
235: default:
236: addToken(length - lastOffset, token);
237: break;
238: }
239: return token;
240: }
241: }
|