KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > armedbear > j > CSSFormatter


1 /*
2  * CSSFormatter.java
3  *
4  * Copyright (C) 2002 Peter Graves
5  * $Id: CSSFormatter.java,v 1.1.1.1 2002/09/24 16:08:12 piso Exp $
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */

21
22 package org.armedbear.j;
23
24 public final class CSSFormatter extends Formatter implements Constants
25 {
26     // States (used in line flags).
27
private static final int CSS_STATE_QUOTE = 0x0001;
28     private static final int CSS_STATE_SINGLEQUOTE = 0x0002;
29     private static final int CSS_STATE_COMMENT = 0x0004;
30     private static final int CSS_STATE_BRACE = 0x0008;
31     private static final int CSS_STATE_IN_BLOCK = 0x0010;
32     private static final int CSS_STATE_NUMBER = 0x0020;
33     private static final int CSS_STATE_PROPERTY = 0x0040;
34     private static final int CSS_STATE_VALUE = 0x0080;
35     private static final int CSS_STATE_SELECTOR = 0x0100;
36
37     // Formats.
38
private static final int CSS_FORMAT_TEXT = 0;
39     private static final int CSS_FORMAT_COMMENT = 1;
40     private static final int CSS_FORMAT_STRING = 2;
41     private static final int CSS_FORMAT_PROPERTY = 3;
42     private static final int CSS_FORMAT_BRACE = 4;
43     private static final int CSS_FORMAT_NUMBER = 5;
44     private static final int CSS_FORMAT_SELECTOR = 6;
45
46     private static final CSSMode mode = CSSMode.getMode();
47
48     public CSSFormatter(Buffer buffer)
49     {
50         this.buffer = buffer;
51     }
52
53     private int tokenBegin = 0;
54
55     private void endToken(String JavaDoc text, int tokenEnd, int state)
56     {
57         if (tokenEnd - tokenBegin > 0) {
58             int format = CSS_FORMAT_TEXT;
59             if ((state & (CSS_STATE_QUOTE | CSS_STATE_SINGLEQUOTE)) != 0)
60                 format = CSS_FORMAT_STRING;
61             else if ((state & CSS_STATE_COMMENT) != 0)
62                 format = CSS_FORMAT_COMMENT;
63             else if ((state & CSS_STATE_BRACE) != 0)
64                 format = CSS_FORMAT_BRACE;
65             else if ((state & CSS_STATE_NUMBER) != 0)
66                 format = CSS_FORMAT_NUMBER;
67             else if ((state & CSS_STATE_PROPERTY) != 0)
68                 format = CSS_FORMAT_PROPERTY;
69             else if ((state & CSS_STATE_VALUE) != 0)
70                 format = CSS_FORMAT_TEXT;
71             else if ((state & CSS_STATE_SELECTOR) != 0)
72                 format = CSS_FORMAT_SELECTOR;
73             addSegment(text, tokenBegin, tokenEnd, format);
74             tokenBegin = tokenEnd;
75         }
76     }
77
78     private void parseLine(Line line)
79     {
80         final String JavaDoc text;
81         if (Editor.tabsAreVisible())
82             text = Utilities.makeTabsVisible(line.getText(), buffer.getTabWidth());
83         else
84             text = Utilities.detab(line.getText(), buffer.getTabWidth());
85         tokenBegin = 0;
86         int state = line.flags();
87         int i = 0;
88         final int limit = text.length();
89         // Skip whitespace at start of line.
90
while (i < limit) {
91             if (Character.isWhitespace(text.charAt(i)))
92                 ++i;
93             else {
94                 endToken(text, i, state);
95                 break;
96             }
97         }
98         while (i < limit) {
99             final char c = text.charAt(i);
100             if (c == '\\' && i < limit-1) {
101                 // Escape character.
102
i += 2;
103                 continue;
104             }
105             if ((state & CSS_STATE_COMMENT) != 0) {
106                 if (i < limit-1 && c == '*' && text.charAt(i+1) == '/') {
107                     endToken(text, i+2, state);
108                     state &= ~CSS_STATE_COMMENT;
109                     i += 2;
110                 } else
111                     ++i;
112                 continue;
113             }
114             if ((state & CSS_STATE_QUOTE) != 0) {
115                 if (c == '"') {
116                     endToken(text, i+1, state);
117                     state &= ~CSS_STATE_QUOTE;
118                 }
119                 ++i;
120                 continue;
121             }
122             if ((state & CSS_STATE_SINGLEQUOTE) != 0) {
123                 if (c == '"') {
124                     endToken(text, i+1, state);
125                     state &= ~CSS_STATE_SINGLEQUOTE;
126                 }
127                 ++i;
128                 continue;
129             }
130             // Reaching here, we're not in a comment or a quoted string.
131
if (c == '"') {
132                 endToken(text, i, state);
133                 state |= CSS_STATE_QUOTE;
134                 ++i;
135                 continue;
136             }
137             if (c == '\'') {
138                 endToken(text, i, state);
139                 state |= CSS_STATE_SINGLEQUOTE;
140                 ++i;
141                 continue;
142             }
143             if (c == '/') {
144                 if (i < limit-1) {
145                     if (text.charAt(i+1) == '*') {
146                         endToken(text, i, state);
147                         state |= CSS_STATE_COMMENT;
148                         i += 2;
149                     } else
150                         ++i;
151                 } else
152                     ++i;
153                 continue;
154             }
155             if (c == '{') {
156                 endToken(text, i, state);
157                 endToken(text, ++i, CSS_STATE_BRACE);
158                 state |= CSS_STATE_IN_BLOCK;
159                 continue;
160             }
161             if (c == '}') {
162                 endToken(text, i, state);
163                 endToken(text, ++i, CSS_STATE_BRACE);
164                 state &= ~CSS_STATE_IN_BLOCK;
165                 continue;
166             }
167             if ((state & CSS_STATE_IN_BLOCK) != 0) {
168                 if ((state & CSS_STATE_NUMBER) != 0) {
169                     boolean isNumeric;
170                     if ("0123456789".indexOf(c) >= 0) {
171                         // Definitely a number.
172
isNumeric = true;
173                     } else if ("abcdefABCDEF".indexOf(c) >= 0) {
174                         if (c == 'e' && i < limit-1 && text.charAt(i+1) == 'm') {
175                             // Not a number ("em").
176
isNumeric = false;
177                         } else {
178                             // Hex digit.
179
isNumeric = true;
180                         }
181                     } else
182                         isNumeric = false;
183                     if (!isNumeric) {
184                         // Not a number.
185
endToken(text, i, state);
186                         state &= ~CSS_STATE_NUMBER;
187                     }
188                     ++i;
189                     continue;
190                 }
191                 if ((state & CSS_STATE_VALUE) != 0) {
192                     if (c == '#' || Character.isDigit(c)) {
193                         endToken(text, i, state);
194                         state |= CSS_STATE_NUMBER;
195                         ++i;
196                         continue;
197                     }
198                     if (c == '-' && i < limit-1 && Character.isDigit(text.charAt(i+1))) {
199                         endToken(text, i, state);
200                         state |= CSS_STATE_NUMBER;
201                         i += 2;
202                         continue;
203                     }
204                     if (c == ';') {
205                         // End of value.
206
endToken(text, i, state);
207                         state &= ~CSS_STATE_VALUE;
208                         ++i;
209                         continue;
210                     }
211                     ++i;
212                     continue;
213                 }
214                 if (c == ':') {
215                     endToken(text, i, CSS_STATE_PROPERTY);
216                     state |= CSS_STATE_VALUE;
217                     ++i;
218                     continue;
219                 }
220             }
221             if ((state & CSS_STATE_SELECTOR) != 0) {
222                 if (!mode.isIdentifierPart(c)) {
223                     endToken(text, i, state);
224                     state &= ~CSS_STATE_SELECTOR;
225                 }
226                 ++i;
227                 continue;
228             }
229             if (state == 0) {
230                 if (mode.isIdentifierStart(c)) {
231                     endToken(text, i, state);
232                     state |= CSS_STATE_SELECTOR;
233                 }
234             }
235             ++i;
236         }
237         // Reached end of line.
238
endToken(text, i, state);
239     }
240
241     public LineSegmentList formatLine(Line line)
242     {
243         clearSegmentList();
244         if (line == null) {
245             addSegment("", CSS_FORMAT_TEXT);
246             return segmentList;
247         }
248         parseLine(line);
249         return segmentList;
250     }
251
252     public boolean parseBuffer()
253     {
254         int state = 0;
255         Line line = buffer.getFirstLine();
256         boolean changed = false;
257         while (line != null) {
258             int oldflags = line.flags();
259             // Quoted strings can't span lines. (Can they?)
260
state &= ~(CSS_STATE_QUOTE | CSS_STATE_SINGLEQUOTE);
261             if (state != oldflags) {
262                 line.setFlags(state);
263                 changed = true;
264             }
265             final int limit = line.length();
266             for (int i = 0; i < limit; i++) {
267                 char c = line.charAt(i);
268                 if (c == '\\' && i < limit-1) {
269                     // Escape.
270
++i;
271                     continue;
272                 }
273                 if ((state & CSS_STATE_COMMENT) != 0) {
274                     if (c == '*' && i < limit-1) {
275                         c = line.charAt(i+1);
276                         if (c == '/') {
277                             ++i;
278                             state &= ~CSS_STATE_COMMENT;
279                         }
280                     }
281                     continue;
282                 }
283                 if ((state & CSS_STATE_QUOTE) != 0) {
284                     if (c == '"')
285                         state &= ~CSS_STATE_QUOTE;
286                     continue;
287                 }
288                 if ((state & CSS_STATE_SINGLEQUOTE) != 0) {
289                     if (c == '"')
290                         state &= ~CSS_STATE_SINGLEQUOTE;
291                     continue;
292                 }
293                 // Not in comment or quoted string.
294
if (c == '{') {
295                     state |= CSS_STATE_IN_BLOCK;
296                     continue;
297                 }
298                 if (c == '}') {
299                     state &= ~CSS_STATE_IN_BLOCK;
300                     continue;
301                 }
302                 if (c == '/' && i < limit-1) {
303                     c = line.charAt(++i);
304                     if (c == '*')
305                         state |= CSS_STATE_COMMENT;
306                 } else if (c == '"') {
307                     state |= CSS_STATE_QUOTE;
308                 } else if (c == '\'') {
309                     state |= CSS_STATE_SINGLEQUOTE;
310                 }
311             }
312             line = line.next();
313         }
314         buffer.setNeedsParsing(false);
315         return changed;
316     }
317
318     public FormatTable getFormatTable()
319     {
320         if (formatTable == null) {
321             formatTable = new FormatTable("CSSMode");
322             formatTable.addEntryFromPrefs(CSS_FORMAT_TEXT, "text");
323             formatTable.addEntryFromPrefs(CSS_FORMAT_COMMENT, "comment");
324             formatTable.addEntryFromPrefs(CSS_FORMAT_STRING, "string");
325             formatTable.addEntryFromPrefs(CSS_FORMAT_PROPERTY, "property", "keyword");
326             formatTable.addEntryFromPrefs(CSS_FORMAT_BRACE, "brace");
327             formatTable.addEntryFromPrefs(CSS_FORMAT_NUMBER, "number");
328             formatTable.addEntryFromPrefs(CSS_FORMAT_SELECTOR, "selector", "function");
329         }
330         return formatTable;
331     }
332 }
333
Popular Tags