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