KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * PythonIndenter.java
3  *
4  * Copyright (C) 2002-2003 Peter Graves
5  * $Id: PythonIndenter.java,v 1.3 2003/10/30 19:25:30 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 PythonIndenter
25 {
26     private static final PythonMode mode = PythonMode.getMode();
27
28     private final Line line;
29     private final Buffer buffer;
30     private final int indentSize;
31
32     public PythonIndenter(Line line, Buffer buffer)
33     {
34         this.line = line;
35         this.buffer = buffer;
36         indentSize = buffer.getIndentSize();
37     }
38
39     public int getCorrectIndentation()
40     {
41         final Line model = findModel(line);
42         if (model == null)
43             return 0;
44         final int modelIndent = buffer.getIndentation(model);
45         // Keep same indentation if model is comment or docstring. Model is
46
// guaranteed not to be blank so charAt(0) is safe.
47
switch (model.getText().trim().charAt(0)) {
48             case '#':
49             case '\'':
50             case '"':
51                 return modelIndent;
52             default:
53                 break;
54         }
55         final String JavaDoc modelText = trimSyntacticWhitespace(model.getText());
56         if (modelText.length() == 0)
57             return 0; // Shouldn't happen.
58
// Indent after '{', '(' or '['.
59
char c = modelText.charAt(modelText.length()-1);
60         if (c == '{' || c == '(' || c == '[')
61             return modelIndent + indentSize;
62         final String JavaDoc modelFirst = getFirstIdentifier(modelText);
63         if (c == ':') {
64             final String JavaDoc[] indentAfter = {
65                 "class", "def", "if", "else", "elif",
66                 "for", "while", "try", "except", "finally"
67             };
68             if (Utilities.isOneOf(modelFirst, indentAfter))
69                 return modelIndent + indentSize;
70         }
71         final String JavaDoc lineText = trimSyntacticWhitespace(line.getText());
72         final String JavaDoc lineFirst = getFirstIdentifier(lineText);
73         if (lineFirst.equals("class"))
74             return 0;
75         if (lineFirst.equals("def"))
76             return indentDef();
77         // Unindent after "break", "continue", "return" and "pass".
78
final String JavaDoc[] unindentAfter = {"break", "continue", "return", "pass"};
79         if (Utilities.isOneOf(modelFirst, unindentAfter))
80             return Math.max(0, modelIndent - indentSize);
81         // Unindent if the current line starts with "else", "elif", "except" or
82
// "finally".
83
final String JavaDoc[] unindent = {"else", "elif", "except", "finally"};
84         if (Utilities.isOneOf(lineFirst, unindent))
85             return Math.max(0, modelIndent - indentSize);
86         return modelIndent;
87     }
88
89     // Scan backwards for line starting with "def" or "class" and indent
90
// accordingly.
91
private int indentDef()
92     {
93         for (Line model = line.previous(); model != null; model = model.previous()) {
94             String JavaDoc modelFirst = getFirstIdentifier(model);
95             if (modelFirst.equals("def"))
96                 return buffer.getIndentation(model);
97             if (modelFirst.equals("class"))
98                 return buffer.getIndentation(model) + buffer.getIndentSize();
99         }
100         return 0;
101     }
102
103     // Return last non-blank line before this one.
104
private static Line findModel(Line line)
105     {
106         for (Line model = line.previous(); model != null; model = model.previous()) {
107             if (!model.isBlank())
108                 return model;
109         }
110         return null;
111     }
112
113     // Replace syntactic whitespace (quotes and comments) with actual space
114
// characters and return trimmed string.
115
private static String JavaDoc trimSyntacticWhitespace(String JavaDoc s)
116     {
117         PythonSyntaxIterator it = new PythonSyntaxIterator(null);
118         return new String JavaDoc(it.hideSyntacticWhitespace(s)).trim();
119     }
120
121     // Never returns null.
122
private static String JavaDoc getFirstIdentifier(Line line)
123     {
124         return getFirstIdentifier(trimSyntacticWhitespace(line.getText()));
125     }
126
127     // Never returns null.
128
private static String JavaDoc getFirstIdentifier(String JavaDoc s)
129     {
130         FastStringBuffer sb = new FastStringBuffer();
131         final int length = s.length();
132         int i = 0;
133         while (i < length && !mode.isIdentifierStart(s.charAt(i)))
134             ++i;
135         char c;
136         while (i < length && mode.isIdentifierPart(c = s.charAt(i))) {
137             sb.append(c);
138             ++i;
139         }
140         return sb.toString();
141     }
142 }
143
Popular Tags