View Javadoc

1   /*
2    * ShellScriptTokenMarker.java - Shell script token marker
3    * Copyright (C) 1998, 1999 Slava Pestov
4    *
5    * You may use and modify this package for any purpose. Redistribution is
6    * permitted, in both source and binary form, provided that this notice
7    * remains intact in all source distributions of this package.
8    */
9   
10  package org.syntax.jedit.tokenmarker;
11  
12  import javax.swing.text.Segment;
13  
14  import org.syntax.jedit.SyntaxUtilities;
15  
16  /***
17   * Shell script token marker.
18   * 
19   * @author Slava Pestov
20   * @version $Id: ShellScriptTokenMarker.java,v 1.18 1999/12/13 03:40:30 sp Exp $
21   */
22  public class ShellScriptTokenMarker extends TokenMarker
23  {
24  	// public members
25  	public static final byte LVARIABLE = Token.INTERNAL_FIRST;
26  
27  	public byte markTokensImpl( byte token, Segment line, int lineIndex )
28  	{
29  		char[] array = line.array;
30  		byte cmdState = 0; // 0 = space before command, 1 = inside
31  		// command, 2 = after command
32  		int offset = line.offset;
33  		int lastOffset = offset;
34  		int length = line.count + offset;
35  
36  		if( token == Token.LITERAL1 && lineIndex != 0 && lineInfo[lineIndex - 1].obj != null )
37  		{
38  			String str = ( String )lineInfo[lineIndex - 1].obj;
39  			if( str != null && str.length() == line.count && SyntaxUtilities.regionMatches( false, line, offset, str ) )
40  			{
41  				addToken( line.count, Token.LITERAL1 );
42  				return Token.NULL;
43  			}
44  			else
45  			{
46  				addToken( line.count, Token.LITERAL1 );
47  				lineInfo[lineIndex].obj = str;
48  				return Token.LITERAL1;
49  			}
50  		}
51  
52  		boolean backslash = false;
53  		loop : for( int i = offset; i < length; i++ )
54  		{
55  			int i1 = ( i + 1 );
56  
57  			char c = array[i];
58  
59  			if( c == '//' )
60  			{
61  				backslash = !backslash;
62  				continue;
63  			}
64  
65  			switch( token )
66  			{
67  			case Token.NULL :
68  				switch( c )
69  				{
70  				case ' ' :
71  				case '\t' :
72  				case '(' :
73  				case ')' :
74  					backslash = false;
75  					if( cmdState == 1/* insideCmd */)
76  					{
77  						addToken( i - lastOffset, Token.KEYWORD1 );
78  						lastOffset = i;
79  						cmdState = 2; /* afterCmd */
80  					}
81  					break;
82  				case '=' :
83  					backslash = false;
84  					if( cmdState == 1/* insideCmd */)
85  					{
86  						addToken( i - lastOffset, token );
87  						lastOffset = i;
88  						cmdState = 2; /* afterCmd */
89  					}
90  					break;
91  				case '&' :
92  				case '|' :
93  				case ';' :
94  					if( backslash )
95  						backslash = false;
96  					else
97  						cmdState = 0; /* beforeCmd */
98  					break;
99  				case '#' :
100 					if( backslash )
101 						backslash = false;
102 					else
103 					{
104 						addToken( i - lastOffset, token );
105 						addToken( length - i, Token.COMMENT1 );
106 						lastOffset = length;
107 						break loop;
108 					}
109 					break;
110 				case '$' :
111 					if( backslash )
112 						backslash = false;
113 					else
114 					{
115 						addToken( i - lastOffset, token );
116 						cmdState = 2; /* afterCmd */
117 						lastOffset = i;
118 						if( length - i >= 2 )
119 						{
120 							switch( array[i1] )
121 							{
122 							case '(' :
123 								continue;
124 							case '{' :
125 								token = LVARIABLE;
126 								break;
127 							default :
128 								token = Token.KEYWORD2;
129 								break;
130 							}
131 						}
132 						else
133 							token = Token.KEYWORD2;
134 					}
135 					break;
136 				case '"' :
137 					if( backslash )
138 						backslash = false;
139 					else
140 					{
141 						addToken( i - lastOffset, token );
142 						token = Token.LITERAL1;
143 						lineInfo[lineIndex].obj = null;
144 						cmdState = 2; /* afterCmd */
145 						lastOffset = i;
146 					}
147 					break;
148 				case '\'' :
149 					if( backslash )
150 						backslash = false;
151 					else
152 					{
153 						addToken( i - lastOffset, token );
154 						token = Token.LITERAL2;
155 						cmdState = 2; /* afterCmd */
156 						lastOffset = i;
157 					}
158 					break;
159 				case '<' :
160 					if( backslash )
161 						backslash = false;
162 					else
163 					{
164 						if( length - i > 1 && array[i1] == '<' )
165 						{
166 							addToken( i - lastOffset, token );
167 							token = Token.LITERAL1;
168 							lastOffset = i;
169 							lineInfo[lineIndex].obj = new String( array, i + 2, length - ( i + 2 ) );
170 						}
171 					}
172 					break;
173 				default :
174 					backslash = false;
175 					if( Character.isLetter( c ) )
176 					{
177 						if( cmdState == 0 /* beforeCmd */)
178 						{
179 							addToken( i - lastOffset, token );
180 							lastOffset = i;
181 							cmdState++ ; /* insideCmd */
182 						}
183 					}
184 					break;
185 				}
186 				break;
187 			case Token.KEYWORD2 :
188 				backslash = false;
189 				if( !Character.isLetterOrDigit( c ) && c != '_' )
190 				{
191 					if( i != offset && array[i - 1] == '$' )
192 					{
193 						addToken( i1 - lastOffset, token );
194 						lastOffset = i1;
195 						token = Token.NULL;
196 						continue;
197 					}
198 					else
199 					{
200 						addToken( i - lastOffset, token );
201 						lastOffset = i;
202 						token = Token.NULL;
203 					}
204 				}
205 				break;
206 			case Token.LITERAL1 :
207 				if( backslash )
208 					backslash = false;
209 				else if( c == '"' )
210 				{
211 					addToken( i1 - lastOffset, token );
212 					cmdState = 2; /* afterCmd */
213 					lastOffset = i1;
214 					token = Token.NULL;
215 				}
216 				else
217 					backslash = false;
218 				break;
219 			case Token.LITERAL2 :
220 				if( backslash )
221 					backslash = false;
222 				else if( c == '\'' )
223 				{
224 					addToken( i1 - lastOffset, Token.LITERAL1 );
225 					cmdState = 2; /* afterCmd */
226 					lastOffset = i1;
227 					token = Token.NULL;
228 				}
229 				else
230 					backslash = false;
231 				break;
232 			case LVARIABLE :
233 				backslash = false;
234 				if( c == '}' )
235 				{
236 					addToken( i1 - lastOffset, Token.KEYWORD2 );
237 					lastOffset = i1;
238 					token = Token.NULL;
239 				}
240 				break;
241 			default :
242 				throw new InternalError( "Invalid state: " + token );
243 			}
244 		}
245 
246 		switch( token )
247 		{
248 		case Token.NULL :
249 			if( cmdState == 1 )
250 				addToken( length - lastOffset, Token.KEYWORD1 );
251 			else
252 				addToken( length - lastOffset, token );
253 			break;
254 		case Token.LITERAL2 :
255 			addToken( length - lastOffset, Token.LITERAL1 );
256 			break;
257 		case Token.KEYWORD2 :
258 			addToken( length - lastOffset, token );
259 			token = Token.NULL;
260 			break;
261 		case LVARIABLE :
262 			addToken( length - lastOffset, Token.INVALID );
263 			token = Token.NULL;
264 			break;
265 		default :
266 			addToken( length - lastOffset, token );
267 			break;
268 		}
269 		return token;
270 	}
271 }