KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * PerlMode.java
3  *
4  * Copyright (C) 1998-2003 Peter Graves
5  * $Id: PerlMode.java,v 1.2 2003/12/04 12:51:03 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 import gnu.regexp.RE;
25 import gnu.regexp.UncheckedRE;
26 import java.awt.event.KeyEvent JavaDoc;
27
28 public final class PerlMode extends AbstractMode implements Constants, Mode
29 {
30     private static final PerlMode mode = new PerlMode();
31
32     private PerlMode()
33     {
34         super(PERL_MODE, PERL_MODE_NAME);
35         keywords = new Keywords(this);
36     }
37
38     public static final PerlMode getMode()
39     {
40         return mode;
41     }
42
43     public final boolean canIndent()
44     {
45         return true;
46     }
47
48     public final String JavaDoc getCommentStart()
49     {
50         return "# ";
51     }
52
53     public final SyntaxIterator getSyntaxIterator(Position pos)
54     {
55         return new PerlSyntaxIterator(pos);
56     }
57
58     public final Formatter getFormatter(Buffer buffer)
59     {
60         return new PerlFormatter(buffer);
61     }
62
63     protected void setKeyMapDefaults(KeyMap km)
64     {
65         km.mapKey('{', "electricOpenBrace");
66         km.mapKey('}', "electricCloseBrace");
67         km.mapKey(';', "electricSemi");
68         km.mapKey(KeyEvent.VK_TAB, 0, "tab");
69         km.mapKey(KeyEvent.VK_ENTER, 0, "newlineAndIndent");
70         km.mapKey(KeyEvent.VK_T, CTRL_MASK, "findTag");
71         km.mapKey(KeyEvent.VK_PERIOD, ALT_MASK, "findTagAtDot");
72         km.mapKey(KeyEvent.VK_L, CTRL_MASK | SHIFT_MASK, "listTags");
73         km.mapKey(')', "closeParen");
74         km.mapKey(KeyEvent.VK_I, ALT_MASK, "cycleIndentSize");
75
76         km.mapKey(KeyEvent.VK_OPEN_BRACKET, CTRL_MASK | SHIFT_MASK, "insertBraces");
77         // Duplicate mapping for 1.4.
78
km.mapKey(KeyEvent.VK_BRACELEFT, CTRL_MASK | SHIFT_MASK, "insertBraces");
79
80         km.mapKey(KeyEvent.VK_9, CTRL_MASK | SHIFT_MASK, "insertParentheses");
81
82         km.mapKey(KeyEvent.VK_F12, 0, "wrapComment");
83
84         if (Platform.isPlatformLinux()) {
85             // Blackdown 1.1.7v3, 1.2pre2, IBM 1.1.8.
86
// Duplicate mappings needed for VK_9, VK_0 and VK_OPEN_BRACKET.
87
km.mapKey(0xbb, CTRL_MASK | SHIFT_MASK, "insertBraces");
88
89             // Duplicate mapping to support IBM 1.3 for Linux.
90
km.mapKey(0xffc9, 0, "wrapComment"); // F12
91
}
92
93         km.mapKey(KeyEvent.VK_OPEN_BRACKET, CTRL_MASK, "fold");
94         km.mapKey(KeyEvent.VK_CLOSE_BRACKET, CTRL_MASK, "unfold");
95     }
96
97     public Tagger getTagger(SystemBuffer buffer)
98     {
99         return new PerlTagger(buffer);
100     }
101
102     public boolean isTaggable()
103     {
104         return true;
105     }
106
107     public boolean hasQualifiedNames()
108     {
109         return true;
110     }
111
112     public boolean isQualifiedName(String JavaDoc s)
113     {
114         return s.indexOf("::") >= 0;
115     }
116
117     public int getCorrectIndentation(Line line, Buffer buffer)
118     {
119         String JavaDoc trim = line.trim();
120         if (trim.length() > 0) {
121             Position pos = null;
122             char c = trim.charAt(0);
123             if (c == '}') {
124                 pos = matchClosingBrace(new Position(line,
125                     line.getText().indexOf('}')));
126                 if (pos == null)
127                     return 0;
128                 if (!pos.getLine().trim().startsWith("{"))
129                     pos = findBeginningOfStatement(pos);
130             } else if (c == ')') {
131                 pos = findEnclosingParen(new Position(line,
132                     line.getText().indexOf(')')));
133                 if (pos == null)
134                     return 0;
135                 if (!pos.getLine().trim().startsWith("("))
136                     pos = findBeginningOfStatement(pos);
137             }
138             if (pos != null)
139                 return buffer.getIndentation(pos.getLine());
140
141             // Labels are a special case.
142
if (isLabel(line))
143                 return 0;
144         }
145         final Line modelLine = findModel(line);
146         if (modelLine == null)
147             return 0;
148         final int indentSize = buffer.getIndentSize();
149         int modelIndent = 0;
150         final String JavaDoc modelText = trimSyntacticWhitespace(modelLine.getText());
151         if (modelText.equals("{")) {
152             modelIndent = buffer.getIndentation(modelLine);
153             if (buffer.getBooleanProperty(Property.INDENT_AFTER_BRACE))
154                 return modelIndent + indentSize;
155             else
156                 return modelIndent;
157         }
158         Position pos = findBeginningOfStatement(new Position(modelLine, 0));
159         if (pos != null)
160             modelIndent = buffer.getIndentation(pos.getLine());
161         if (modelText.endsWith("{")) {
162             if (buffer.getBooleanProperty(Property.INDENT_AFTER_BRACE))
163                 return modelIndent + indentSize;
164             else
165                 return modelIndent;
166         }
167         if (modelText.endsWith("}"))
168             return modelIndent;
169         if (modelText.endsWith(";"))
170             return modelIndent;
171         pos = findEnclosingParen(new Position(line, 0) );
172         if (pos != null) {
173             if (pos.getLine().trim().endsWith("(") ||
174                 !buffer.getBooleanProperty(Property.LINEUP_ARGLIST)) {
175                 return buffer.getIndentation(pos.getLine()) + indentSize;
176             } else {
177                 // Advance past '('.
178
pos.skip(1);
179                 // Advance to first non-whitespace char.
180
pos.skipWhitespaceOnCurrentLine();
181                 return buffer.getCol(pos);
182             }
183         }
184         if (modelText.endsWith(","))
185             return buffer.getIndentation(modelLine);
186
187         // Continuation line.
188
pos = findBeginningOfStatement(new Position(line, 0));
189
190         if (pos != null) {
191             if (line.getText().trim().startsWith("{")) {
192                 if (buffer.getBooleanProperty(Property.INDENT_BEFORE_BRACE))
193                     return buffer.getIndentation(pos.getLine()) + indentSize;
194                 else
195                     return buffer.getIndentation(pos.getLine());
196             } else
197                 return buffer.getIndentation(pos.getLine()) + indentSize;
198         }
199         return modelIndent;
200     }
201
202     private static Line findModel(Line line)
203     {
204         for (Line modelLine = line.previous(); modelLine != null;
205             modelLine = modelLine.previous()) {
206             if (modelLine.isBlank())
207                 continue;
208             else if (modelLine.trim().startsWith("#"))
209                 continue;
210             else if (isLabel(modelLine))
211                 continue;
212             else
213                 return modelLine;
214         }
215         return null;
216     }
217
218     private static RE labelRE = new UncheckedRE("^\\s*[A-Za-z0-9_]+:\\s*$");
219
220     private static boolean isLabel(Line line)
221     {
222         return labelRE.getMatch(line.getText()) != null;
223     }
224
225     // Scan backwards from starting position, looking for unmatched opening
226
// parenthesis.
227
private static Position findEnclosingParen(Position start)
228     {
229         PerlSyntaxIterator it = new PerlSyntaxIterator(start);
230         int count = 0;
231         char c;
232         while ((c = it.prevChar()) != SyntaxIterator.DONE) {
233             if (c == '}')
234                 return null;
235             if (c == ')') {
236                 ++count;
237             } else if (c == '(') {
238                 if (count == 0)
239                     return it.getPosition(); // Found unmatched '('.
240
else
241                     --count;
242             }
243         }
244         return null;
245     }
246
247     static Position findBeginningOfStatement(Position start)
248     {
249         Position pos = new Position(start);
250         if (pos.getLine().trim().startsWith("}")) {
251             Position posMatch =
252                 matchClosingBrace(new Position(pos.getLine(), 0));
253             if (posMatch != null)
254                 pos = posMatch;
255         } else {
256             Position posParen = findEnclosingParen(pos);
257             if (posParen != null)
258                 pos = posParen;
259         }
260         while (pos.getLine() != null) {
261             pos.setLine(pos.getLine().previous());
262             if (pos.getLine() == null)
263                 break;
264             pos.setOffset(pos.getLineLength());
265             String JavaDoc s = trimSyntacticWhitespace(pos.getLine().getText());
266             if (s.length() > 0) {
267                 char c = s.charAt(s.length() - 1);
268                 if (c == ';' || c == '{' || c == '}' || c == ':')
269                     break;
270             }
271         }
272         if (pos.getLine() == null) {
273             pos.moveTo(start.getLine(), 0);
274         } else {
275             // Skip syntactic whitespace.
276
PerlSyntaxIterator it = new PerlSyntaxIterator(pos);
277             while (true) {
278                 char c = it.nextChar();
279                 if (c == SyntaxIterator.DONE)
280                     break;
281                 if (c > ' ')
282                     break;
283             }
284             pos = it.getPosition();
285         }
286         return pos;
287     }
288
289     private static Position matchClosingBrace(Position start)
290     {
291         int count = 1;
292         PerlSyntaxIterator it = new PerlSyntaxIterator(start);
293         char c;
294         while ((c = it.prevChar()) != SyntaxIterator.DONE) {
295             if (c == '}')
296                 ++count;
297             else if (c == '{')
298                 --count;
299             if (count == 0) // Found it!
300
return it.getPosition();
301         }
302         return null;
303     }
304
305     // Replace syntactic whitespace (quotes and comments) with actual space
306
// characters and return trimmed string.
307
protected static String JavaDoc trimSyntacticWhitespace(String JavaDoc s)
308     {
309         PerlSyntaxIterator it = new PerlSyntaxIterator(null);
310         return (new String JavaDoc(it.hideSyntacticWhitespace(s))).trim();
311     }
312
313     private static final String JavaDoc validChars =
314         "$@%ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_0123456789";
315
316     static final boolean isIdentifierChar(char c)
317     {
318         return (validChars.indexOf(c) >= 0);
319     }
320
321     public boolean isIdentifierStart(char c)
322     {
323         return isIdentifierChar(c);
324     }
325
326     public boolean isIdentifierPart(char c)
327     {
328         return isIdentifierChar(c);
329     }
330
331     public boolean isCommentLine(Line line)
332     {
333         return line.trim().startsWith("#");
334     }
335 }
336
Popular Tags