001: /*
002: * JavaScriptMode.java
003: *
004: * Copyright (C) 1998-2003 Peter Graves
005: * $Id: JavaScriptMode.java,v 1.2 2003/06/12 16:35:05 piso Exp $
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: */
021:
022: package org.armedbear.j;
023:
024: import java.awt.event.KeyEvent;
025:
026: public final class JavaScriptMode extends JavaMode implements
027: Constants, Mode {
028: // Since this class is final, we may as well construct the singleton class
029: // instance right away.
030: private static JavaScriptMode mode = new JavaScriptMode();
031:
032: private JavaScriptMode() {
033: super (JAVASCRIPT_MODE, JAVASCRIPT_MODE_NAME);
034: keywords = new Keywords(this );
035: }
036:
037: public static final Mode getMode() {
038: return mode;
039: }
040:
041: public final Formatter getFormatter(Buffer buffer) {
042: return new JavaFormatter(buffer, LANGUAGE_JAVASCRIPT);
043: }
044:
045: protected void setKeyMapDefaults(KeyMap km) {
046: super .setKeyMapDefaults(km);
047: km.mapKey(KeyEvent.VK_ENTER, CTRL_MASK, "newline");
048: }
049:
050: public void populateModeMenu(Editor editor, Menu menu) {
051: // No mode menu yet.
052: }
053:
054: public int getCorrectIndentation(Line line, Buffer buffer) {
055: final int indentSize = buffer.getIndentSize();
056: int indent = 0;
057: String text = line.trim();
058:
059: if (text.startsWith("}")) {
060: Position pos = new Position(line, line.getText().indexOf(
061: '}'));
062: pos = matchClosingBrace(pos);
063: pos = findBeginningOfStatement(pos);
064: indent = buffer.getIndentation(pos.getLine());
065: return indent;
066: }
067:
068: String identifier = getFirstIdentifier(line);
069:
070: if (identifier.equals("case") || identifier.equals("default")) {
071: Line switchLine = findSwitch(line);
072: if (switchLine != null)
073: indent = buffer.getIndentation(switchLine) + indentSize;
074: return indent;
075: }
076:
077: Position paren = findEnclosingParen(new Position(line, 0));
078:
079: if (paren != null) {
080: if (text.startsWith(")"))
081: return buffer.getIndentation(paren.getLine());
082: if (paren.getLine().trim().endsWith("(")
083: || !buffer
084: .getBooleanProperty(Property.LINEUP_ARGLIST)) {
085: indent = buffer.getIndentation(paren.getLine())
086: + indentSize;
087: } else {
088: paren.skip(1);
089: while (paren.getOffset() < paren.getLineLength()
090: && paren.getLine().charAt(paren.getOffset()) <= ' ') {
091: paren.skip(1);
092: }
093: if (paren.getOffset() <= paren.getLineLength())
094: indent = buffer.getCol(paren);
095: }
096: return indent;
097: }
098:
099: // Figure out indentation of previous non-blank line.
100: Line model = findModel(line);
101:
102: if (model == null)
103: return 0;
104:
105: if (line.flags() == STATE_COMMENT) {
106: indent = buffer.getIndentation(model);
107: String s = model.getText().trim();
108: if (s.startsWith("/*") && text.startsWith("*"))
109: return indent + 1;
110: else
111: return indent;
112: }
113:
114: String modelText = trimSyntacticWhitespace(model.getText());
115: final boolean indentBeforeBrace = buffer
116: .getBooleanProperty(Property.INDENT_BEFORE_BRACE);
117: if (modelText.endsWith("}")) {
118: indent = buffer.getIndentation(model);
119: if (indentBeforeBrace)
120: indent -= indentSize;
121: return indent;
122: }
123:
124: Position bos = findBeginningOfStatement(new Position(model, 0));
125: indent = buffer.getIndentation(bos.getLine());
126: final boolean indentAfterBrace = buffer
127: .getBooleanProperty(Property.INDENT_AFTER_BRACE);
128:
129: if (modelText.endsWith(")")) {
130: Position pos = new Position(model, model.length() - 1);
131: while (pos.getChar() != ')')
132: pos.skip(-1);
133: pos = matchClosingParen(pos);
134: indent = buffer.getIndentation(pos.getLine());
135:
136: // Loose JavaScript
137: String s = pos.getLine().trim();
138:
139: if (s.startsWith("}"))
140: s = s.substring(1).trim();
141:
142: String firstToken = getFirstIdentifier(s);
143:
144: if (!firstToken.equals("if") && !firstToken.equals("else")
145: && !firstToken.equals("for")
146: && !firstToken.equals("while")
147: && !firstToken.equals("switch")) {
148: Position begin = findBeginningOfBlock(pos);
149: if (begin != null) {
150: indent = buffer.getIndentation(begin.getLine());
151: if (indentAfterBrace)
152: indent += indentSize;
153: }
154: return indent;
155: }
156:
157: if (indentBeforeBrace || !text.startsWith("{"))
158: indent += indentSize;
159:
160: return indent;
161: }
162:
163: String lastIdentifier = getLastIdentifier(modelText);
164:
165: if (lastIdentifier != null && lastIdentifier.equals("else")) {
166: if (indentBeforeBrace || !text.startsWith("{"))
167: indent += indentSize;
168: return indent;
169: }
170:
171: if (isContinued(modelText)) {
172: // Continuation line.
173: Position pos = findBeginningOfStatement(new Position(model,
174: 0));
175: return buffer.getIndentation(pos.getLine()) + indentSize;
176: }
177:
178: String modelFirstIdentifier = getFirstIdentifier(model);
179:
180: if (modelFirstIdentifier.equals("case")) {
181: if (indentBeforeBrace || !text.startsWith("{"))
182: indent += indentSize;
183: } else if (modelFirstIdentifier.equals("default")) {
184: if (indentBeforeBrace || !text.startsWith("{"))
185: indent += indentSize;
186: } else if (modelText.endsWith("{")) {
187: if (indentAfterBrace)
188: indent += indentSize;
189: } else {
190: // Match indentation of beginning of statement.
191: Position pos = findBeginningOfStatement(new Position(model,
192: 0));
193: indent = buffer.getIndentation(pos.getLine());
194: }
195:
196: return indent;
197: }
198:
199: private boolean isContinued(String text) {
200: if (text.length() == 0)
201: return false;
202: return isContinued(text, text.charAt(text.length() - 1));
203: }
204:
205: private static Position findBeginningOfBlock(Position pos) {
206: JavaSyntaxIterator iter = new JavaSyntaxIterator(pos);
207:
208: int count = 1;
209:
210: while (true) {
211: char c = iter.prevChar();
212:
213: if (c == JavaSyntaxIterator.DONE)
214: return null;
215:
216: if (c == '}')
217: ++count;
218: else if (c == '{')
219: --count;
220:
221: if (count == 0)
222: return iter.getPosition();
223: }
224: }
225: }
|