001: /*
002: * CMode.java
003: *
004: * Copyright (C) 1998-2003 Peter Graves
005: * $Id: CMode.java,v 1.3 2003/12/30 19:28:31 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: import java.util.HashSet;
026:
027: public class CMode extends JavaMode implements Constants, Mode {
028: private static final String[] cConditionals = { "if", "else", "do",
029: "while", "for", "switch" };
030:
031: private static CMode mode;
032:
033: private CMode() {
034: super (C_MODE, C_MODE_NAME);
035: keywords = new Keywords(this );
036: conditionals = cConditionals;
037: }
038:
039: protected CMode(int id, String displayName) {
040: super (id, displayName);
041: }
042:
043: // Don't construct the singleton class instance until we actually need it,
044: // to avoid unnecessary overhead for CppMode which is derived from this
045: // class.
046: public static Mode getMode() {
047: if (mode == null)
048: mode = new CMode();
049: return mode;
050: }
051:
052: public String getCommentStart() {
053: return "/*";
054: }
055:
056: public String getCommentEnd() {
057: return "*/";
058: }
059:
060: public Formatter getFormatter(Buffer buffer) {
061: return new CFormatter(buffer, LANGUAGE_C);
062: }
063:
064: protected void setKeyMapDefaults(KeyMap km) {
065: super .setKeyMapDefaults(km);
066: km.mapKey('#', "electricPound");
067: km.mapKey(KeyEvent.VK_M, CTRL_MASK, "cppFindMatch");
068: km.mapKey(KeyEvent.VK_F6, CTRL_MASK, "iList");
069: }
070:
071: public void populateModeMenu(Editor editor, Menu menu) {
072: menu.add(editor, "Compile...", 'C', "compile");
073: menu.add(editor, "Recompile", 'R', "recompile");
074: boolean enabled = CompilationCommands.getCompilationBuffer() != null;
075: menu.addSeparator();
076: menu.add(editor, "Next Error", 'N', "nextError", enabled);
077: menu.add(editor, "Previous Error", 'P', "previousError",
078: enabled);
079: menu.add(editor, "Show Error Message", 'M', "showMessage",
080: enabled);
081: }
082:
083: public Tagger getTagger(SystemBuffer buffer) {
084: return new CTagger(buffer);
085: }
086:
087: public boolean hasQualifiedNames() {
088: return false;
089: }
090:
091: public boolean isQualifiedName(String s) {
092: return false;
093: }
094:
095: public int getCorrectIndentation(Line line, Buffer buffer) {
096: if (line.trim().startsWith("#"))
097: return 0; // Preprocessor directive.
098:
099: return super .getCorrectIndentation(line, buffer);
100: }
101:
102: protected static String getPreprocessorToken(Line line) {
103: String s = line.trim();
104: if (s.length() == 0 || s.charAt(0) != '#')
105: return null;
106: final int limit = s.length();
107: int i;
108: for (i = 1; i < limit; i++) {
109: char c = s.charAt(i);
110: if (c != ' ' && c != '\t')
111: break;
112: }
113: FastStringBuffer sb = new FastStringBuffer();
114: for (; i < limit; i++) {
115: char c = s.charAt(i);
116: if (c >= 'a' && c <= 'z')
117: sb.append(c);
118: else
119: break;
120: }
121: return sb.toString();
122: }
123:
124: // Used only by findMatchPreprocessor. This needs to persist between calls
125: // so we can handle #else/#elif correctly in successive calls.
126: private static boolean matchBackwards = false;
127:
128: public static Line findMatchPreprocessor(Line startLine) {
129: final String patternIf = "if";
130: final String patternElse = "el";
131: final String patternEndif = "endif";
132: String token = null;
133: String match = null;
134: boolean searchBackwards = false;
135: String s = getPreprocessorToken(startLine);
136: if (s == null)
137: return null;
138: if (s.startsWith(patternIf)) {
139: token = patternIf;
140: match = patternEndif;
141: matchBackwards = false;
142: } else if (s.startsWith(patternEndif)) {
143: token = patternEndif;
144: match = patternIf;
145: matchBackwards = true;
146: } else if (s.startsWith(patternElse)) {
147: if (matchBackwards) {
148: token = patternEndif;
149: match = patternIf;
150: } else {
151: token = patternIf;
152: match = patternEndif;
153: }
154: } else
155: return null;
156: int count = 1;
157: Line line = startLine;
158: while (true) {
159: if (matchBackwards)
160: line = line.previous();
161: else
162: line = line.next();
163: if (line == null)
164: break;
165: s = getPreprocessorToken(line);
166: if (s != null) {
167: if (count == 1 && s.startsWith(patternElse))
168: return line;
169: if (s.startsWith(token))
170: ++count;
171: else if (s.startsWith(match))
172: --count;
173: if (count == 0)
174: return line;
175: }
176: }
177: return null;
178: }
179:
180: public boolean isIdentifierStart(char c) {
181: if (c >= 'a' && c <= 'z')
182: return true;
183: if (c >= 'A' && c <= 'Z')
184: return true;
185: if (c == '_')
186: return true;
187: return false;
188: }
189:
190: public boolean isIdentifierPart(char c) {
191: if (c >= 'a' && c <= 'z')
192: return true;
193: if (c >= 'A' && c <= 'Z')
194: return true;
195: if (c >= '0' && c <= '9')
196: return true;
197: if (c == '_')
198: return true;
199: return false;
200: }
201: }
|