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