Source Code Cross Referenced for JavaMode.java in  » IDE » J » org » armedbear » j » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE » J » org.armedbear.j 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * JavaMode.java
0003:         *
0004:         * Copyright (C) 1998-2004 Peter Graves
0005:         * $Id: JavaMode.java,v 1.16 2004/09/08 00:48:28 piso Exp $
0006:         *
0007:         * This program is free software; you can redistribute it and/or
0008:         * modify it under the terms of the GNU General Public License
0009:         * as published by the Free Software Foundation; either version 2
0010:         * of the License, or (at your option) any later version.
0011:         *
0012:         * This program is distributed in the hope that it will be useful,
0013:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0015:         * GNU General Public License for more details.
0016:         *
0017:         * You should have received a copy of the GNU General Public License
0018:         * along with this program; if not, write to the Free Software
0019:         * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
0020:         */
0021:
0022:        package org.armedbear.j;
0023:
0024:        import gnu.regexp.RE;
0025:        import gnu.regexp.REMatch;
0026:        import gnu.regexp.UncheckedRE;
0027:        import java.awt.event.KeyEvent;
0028:        import java.awt.event.MouseEvent;
0029:        import javax.swing.JMenuItem;
0030:        import javax.swing.JPopupMenu;
0031:        import javax.swing.undo.CompoundEdit;
0032:
0033:        public class JavaMode extends AbstractMode implements  Constants, Mode {
0034:            private static final String[] javaConditionals = { "if", "else",
0035:                    "do", "while", "for", "switch", "try", "catch", "finally",
0036:                    "synchronized" };
0037:
0038:            private static Mode mode;
0039:            private static Object jdb;
0040:
0041:            protected String[] conditionals;
0042:
0043:            private JavaMode() {
0044:                super (JAVA_MODE, JAVA_MODE_NAME);
0045:                keywords = new Keywords(this );
0046:                conditionals = javaConditionals;
0047:            }
0048:
0049:            protected JavaMode(int id, String displayName) {
0050:                super (id, displayName);
0051:            }
0052:
0053:            // Don't construct the singleton class instance until we actually need it,
0054:            // to avoid unnecessary overhead for the derived classes.
0055:            public static Mode getMode() {
0056:                if (mode == null)
0057:                    mode = new JavaMode();
0058:                return mode;
0059:            }
0060:
0061:            public static final Object getJdb() {
0062:                return jdb;
0063:            }
0064:
0065:            public static final void setJdb(Object obj) {
0066:                jdb = obj;
0067:            }
0068:
0069:            public boolean canIndent() {
0070:                return true;
0071:            }
0072:
0073:            public SyntaxIterator getSyntaxIterator(Position pos) {
0074:                return new JavaSyntaxIterator(pos);
0075:            }
0076:
0077:            public String getCommentStart() {
0078:                return "// ";
0079:            }
0080:
0081:            public Formatter getFormatter(Buffer buffer) {
0082:                return new JavaFormatter(buffer);
0083:            }
0084:
0085:            protected void setKeyMapDefaults(KeyMap km) {
0086:                km.mapKey('{', "electricOpenBrace");
0087:                km.mapKey('}', "electricCloseBrace");
0088:                km.mapKey(KeyEvent.VK_TAB, CTRL_MASK, "insertTab");
0089:                km.mapKey(KeyEvent.VK_TAB, 0, "tab");
0090:                km.mapKey(KeyEvent.VK_ENTER, 0, "newlineAndIndent");
0091:                km.mapKey(';', "electricSemi");
0092:                km.mapKey(':', "electricColon");
0093:                km.mapKey('*', "electricStar");
0094:                km.mapKey(KeyEvent.VK_T, CTRL_MASK, "findTag");
0095:                km.mapKey(KeyEvent.VK_PERIOD, ALT_MASK, "findTagAtDot");
0096:                km.mapKey(KeyEvent.VK_COMMA, ALT_MASK, "listMatchingTagsAtDot");
0097:                km.mapKey(KeyEvent.VK_PERIOD, CTRL_MASK | ALT_MASK,
0098:                        "findTagAtDotOtherWindow");
0099:                km.mapKey(')', "closeParen");
0100:                km.mapKey(KeyEvent.VK_I, ALT_MASK, "cycleIndentSize");
0101:
0102:                km.mapKey(KeyEvent.VK_9, CTRL_MASK | SHIFT_MASK,
0103:                        "insertParentheses");
0104:                km.mapKey(KeyEvent.VK_0, CTRL_MASK | SHIFT_MASK,
0105:                        "movePastCloseAndReindent");
0106:
0107:                km.mapKey(KeyEvent.VK_OPEN_BRACKET, CTRL_MASK | SHIFT_MASK,
0108:                        "insertBraces");
0109:                // Duplicate mapping for 1.4.
0110:                km.mapKey(KeyEvent.VK_BRACELEFT, CTRL_MASK | SHIFT_MASK,
0111:                        "insertBraces");
0112:
0113:                km.mapKey(KeyEvent.VK_F12, 0, "wrapComment");
0114:
0115:                // Duplicate mapping to support IBM 1.3 for Linux.
0116:                km.mapKey(0xffc9, 0, "wrapComment"); // F12
0117:
0118:                km.mapKey(KeyEvent.VK_OPEN_BRACKET, CTRL_MASK, "fold");
0119:                km.mapKey(KeyEvent.VK_CLOSE_BRACKET, CTRL_MASK, "unfold");
0120:
0121:                km.mapKey(KeyEvent.VK_F9, 0, "compile");
0122:                km.mapKey(KeyEvent.VK_F9, CTRL_MASK, "recompile");
0123:                km.mapKey(KeyEvent.VK_F1, ALT_MASK, "jdkHelp");
0124:                km.mapKey(KeyEvent.VK_F1, CTRL_MASK, "source");
0125:
0126:                // This is the "normal" mapping.
0127:                km.mapKey(KeyEvent.VK_COMMA, CTRL_MASK | SHIFT_MASK,
0128:                        "htmlInsertTag");
0129:                // The "normal" mapping doesn't work for Linux, but this does.
0130:                km.mapKey(0x7c, CTRL_MASK | SHIFT_MASK, "htmlInsertTag");
0131:
0132:                if (Editor.checkExperimental()) {
0133:                    km.mapKey(KeyEvent.VK_SEMICOLON, ALT_MASK,
0134:                            "JavaMode.insertComment");
0135:                    km.mapKey(KeyEvent.VK_ENTER, ALT_MASK,
0136:                            "JavaMode.newlineAndIndentForComment");
0137:                }
0138:
0139:                if (Platform.isPlatformLinux()) {
0140:                    // Blackdown 1.1.7v3, 1.2pre2, IBM 1.1.8.
0141:                    // Duplicate mappings needed for VK_9, VK_0 and VK_OPEN_BRACKET.
0142:                    km
0143:                            .mapKey(0x68, CTRL_MASK | SHIFT_MASK,
0144:                                    "insertParentheses");
0145:                    km.mapKey(0x69, CTRL_MASK | SHIFT_MASK,
0146:                            "movePastCloseAndReindent");
0147:                    km.mapKey(0xbb, CTRL_MASK | SHIFT_MASK, "insertBraces");
0148:                }
0149:            }
0150:
0151:            public void populateModeMenu(Editor editor, Menu menu) {
0152:                menu.add(editor, "Compile...", 'C', "compile");
0153:                menu.add(editor, "Recompile", 'R', "recompile");
0154:                boolean enabled = CompilationCommands.getCompilationBuffer() != null;
0155:                menu.addSeparator();
0156:                menu.add(editor, "Next Error", 'N', "nextError", enabled);
0157:                menu.add(editor, "Previous Error", 'P', "previousError",
0158:                        enabled);
0159:                menu.add(editor, "Show Error Message", 'M', "showMessage",
0160:                        enabled);
0161:                menu.addSeparator();
0162:                MenuItem jdbMenuItem = menu.add(editor, "Debug...", 'D', "jdb");
0163:                if (jdb != null)
0164:                    jdbMenuItem.setEnabled(false);
0165:                else {
0166:                    try {
0167:                        Class.forName("com.sun.jdi.Bootstrap");
0168:                    } catch (ClassNotFoundException e) {
0169:                        jdbMenuItem.setEnabled(false);
0170:                    }
0171:                }
0172:            }
0173:
0174:            public JPopupMenu getContextMenu(Editor editor) {
0175:                final JPopupMenu popup = new JPopupMenu();
0176:                if (jdb != null) {
0177:                    final Line line = editor.getDotLine();
0178:                    if (line != null) {
0179:                        final Dispatcher dispatcher = editor.getDispatcher();
0180:                        JMenuItem menuItem = addContextMenuItem(
0181:                                "Set breakpoint", "jdbSetBreakpoint", popup,
0182:                                dispatcher);
0183:                        if (line.isBlank() || line.getAnnotation() != null)
0184:                            menuItem.setEnabled(false);
0185:                        menuItem = addContextMenuItem("Delete breakpoint",
0186:                                "jdbDeleteBreakpoint", popup, dispatcher);
0187:                        if (line.getAnnotation() == null)
0188:                            menuItem.setEnabled(false);
0189:                        menuItem = addContextMenuItem("Run to current line",
0190:                                "jdbRunToCurrentLine", popup, dispatcher);
0191:                        if (line.isBlank())
0192:                            menuItem.setEnabled(false);
0193:                        popup.addSeparator();
0194:                    }
0195:                }
0196:                addDefaultContextMenuItems(editor, popup);
0197:                popup.pack();
0198:                return popup;
0199:            }
0200:
0201:            public NavigationComponent getSidebarComponent(Editor editor) {
0202:                if (getId() == JAVA_MODE) {
0203:                    View view = editor.getCurrentView();
0204:                    if (view == null)
0205:                        return null; // Shouldn't happen.
0206:                    if (view.getSidebarComponent() == null)
0207:                        view.setSidebarComponent(new JavaTree(editor));
0208:                    return view.getSidebarComponent();
0209:                }
0210:                // For subclasses...
0211:                return super .getSidebarComponent(editor);
0212:            }
0213:
0214:            public Tagger getTagger(SystemBuffer buffer) {
0215:                return new JavaTagger(buffer);
0216:            }
0217:
0218:            public boolean isTaggable() {
0219:                return true;
0220:            }
0221:
0222:            public boolean hasQualifiedNames() {
0223:                return true;
0224:            }
0225:
0226:            public boolean isQualifiedName(String s) {
0227:                return s.indexOf('.') >= 0;
0228:            }
0229:
0230:            public int getCorrectIndentation(final Line line,
0231:                    final Buffer buffer) {
0232:                if (line.flags() == STATE_COMMENT)
0233:                    return indentComment(line, buffer);
0234:                final String text = line.trim();
0235:                final char textFirstChar = text.length() > 0 ? text.charAt(0)
0236:                        : 0;
0237:                if (textFirstChar == '}')
0238:                    return indentClosingBrace(line, buffer);
0239:
0240:                if (textFirstChar == 'c' || textFirstChar == 'd') {
0241:                    // Does line begin with "case" or "default"?
0242:                    final String firstIdentifier = getFirstIdentifier(text);
0243:                    if (firstIdentifier.equals("case")
0244:                            || firstIdentifier.equals("default"))
0245:                        return indentSwitchLabel(line, buffer);
0246:                    // Otherwise fall through...
0247:                } else if (textFirstChar == 'e') {
0248:                    // Does line begin with "else" or "elseif"?
0249:                    final String firstIdentifier = getFirstIdentifier(text);
0250:                    if (firstIdentifier.equals("else")
0251:                            || firstIdentifier.equals("elseif")) {
0252:                        Position match = matchElse(new Position(line, 0));
0253:                        if (match != null)
0254:                            return buffer.getIndentation(match.getLine());
0255:                    }
0256:                    // Otherwise fall through...
0257:                }
0258:
0259:                Position paren = findEnclosingParen(new Position(line, 0));
0260:                if (paren != null)
0261:                    return indentInParen(paren, buffer);
0262:
0263:                final Line model = findModel(line);
0264:                if (model == null)
0265:                    return 0;
0266:
0267:                final int indentSize = buffer.getIndentSize();
0268:
0269:                final String firstIdentifier = getFirstIdentifier(text);
0270:                if (firstIdentifier.equals("throws")
0271:                        || firstIdentifier.equals("implements")) {
0272:                    Position pos = findBeginningOfStatement(new Position(model,
0273:                            0));
0274:                    return buffer.getIndentation(pos.getLine()) + indentSize;
0275:                }
0276:
0277:                final String modelText = trimSyntacticWhitespace(model
0278:                        .getText());
0279:
0280:                // Model line can't be blank, so this is safe.
0281:                final char modelLastChar = modelText
0282:                        .charAt(modelText.length() - 1);
0283:
0284:                if (modelLastChar == '{')
0285:                    return indentAfterOpeningBrace(model, modelText, buffer);
0286:
0287:                if (modelLastChar == ')')
0288:                    return indentAfterCloseParen(model, text, textFirstChar,
0289:                            buffer);
0290:
0291:                final String lastIdentifier = getLastIdentifier(modelText);
0292:                if (lastIdentifier != null && lastIdentifier.equals("else"))
0293:                    return indentAfterElse(model, text, textFirstChar, buffer);
0294:
0295:                final char modelFirstChar = modelText.charAt(0);
0296:                if (modelFirstChar == 'c' || modelFirstChar == 'd') {
0297:                    final String modelFirstIdentifier = getFirstIdentifier(modelText);
0298:                    if (modelFirstIdentifier.equals("case")
0299:                            || modelFirstIdentifier.equals("default"))
0300:                        return indentAfterSwitchLabel(model, text,
0301:                                textFirstChar, buffer);
0302:                    // Otherwise fall through...
0303:                }
0304:
0305:                final int indent = getIndentationOfEnclosingScope(line, buffer);
0306:
0307:                if (textFirstChar == '{') {
0308:                    if (buffer.getBooleanProperty(Property.INDENT_BEFORE_BRACE)) {
0309:                        // Never indent before the opening brace of a class or method.
0310:                        if (!isOpeningBraceOfClassOrMethod(line))
0311:                            return indent + indentSize;
0312:                    }
0313:                    return indent;
0314:                }
0315:
0316:                if (modelLastChar == ',') {
0317:                    if (buffer.getModeId() == CPP_MODE && modelFirstChar == ':') {
0318:                        // Model line is start of member initialization list, current
0319:                        // line is continuation.
0320:                        return indent + 2;
0321:                    }
0322:                    if (isInArrayInitializer(line))
0323:                        return indent;
0324:                    // Otherwise it's a continuation line.
0325:                    return indent + indentSize;
0326:                }
0327:
0328:                // Check for continuation line.
0329:                if (isContinued(modelText, modelLastChar))
0330:                    return indent + indentSize;
0331:
0332:                return indent;
0333:            }
0334:
0335:            private final int indentComment(Line line, Buffer buffer) {
0336:                final Line model = findModel(line);
0337:                if (model == null)
0338:                    return 0;
0339:                int indent = buffer.getIndentation(model);
0340:                if (model.trim().startsWith("/*"))
0341:                    if (line.trim().startsWith("*"))
0342:                        return indent + 1;
0343:                return indent;
0344:            }
0345:
0346:            private final int indentClosingBrace(Line line, Buffer buffer) {
0347:                Position pos = matchClosingBrace(new Position(line, 0));
0348:                if (isOpeningBraceOfClassOrMethod(pos.getLine()))
0349:                    pos = findBeginningOfStatement(pos);
0350:                else if (!pos.getLine().trim().startsWith("{"))
0351:                    pos = findPreviousConditional(pos);
0352:                return buffer.getIndentation(pos.getLine());
0353:            }
0354:
0355:            private final int indentSwitchLabel(Line line, Buffer buffer) {
0356:                Line switchLine = findSwitch(line);
0357:                if (switchLine != null)
0358:                    return buffer.getIndentation(switchLine)
0359:                            + buffer.getIndentSize();
0360:                return 0;
0361:            }
0362:
0363:            private final int indentInParen(Position posParen, Buffer buffer) {
0364:                final Line line = posParen.getLine();
0365:                if (line.trim().endsWith("(")
0366:                        || !buffer.getBooleanProperty(Property.LINEUP_ARGLIST))
0367:                    return buffer.getIndentation(line) + buffer.getIndentSize();
0368:                final int limit = line.length();
0369:                int offset = posParen.getOffset();
0370:                do {
0371:                    ++offset;
0372:                } while (offset < limit && line.charAt(offset) <= ' ');
0373:                if (offset <= limit)
0374:                    return buffer.getCol(line, offset);
0375:                return 0;
0376:            }
0377:
0378:            private final int indentAfterOpeningBrace(Line model,
0379:                    String modelText, Buffer buffer) {
0380:                final int indentSize = buffer.getIndentSize();
0381:                if (isOpeningBraceOfClassOrMethod(model)) {
0382:                    Position pos = findBeginningOfStatement(new Position(model,
0383:                            0));
0384:                    int indent = buffer.getIndentation(pos.getLine());
0385:                    if (buffer
0386:                            .getBooleanProperty(Property.INDENT_AFTER_OPENING_BRACE))
0387:                        indent += indentSize;
0388:                    return indent;
0389:                }
0390:                Position pos = new Position(model, model.length() - 1);
0391:                if (modelText.charAt(0) != '{')
0392:                    pos = findPreviousConditional(pos);
0393:                int indent = buffer.getIndentation(pos.getLine());
0394:                if (buffer.getBooleanProperty(Property.INDENT_AFTER_BRACE))
0395:                    indent += indentSize;
0396:                final boolean indentBeforeBrace = buffer
0397:                        .getBooleanProperty(Property.INDENT_BEFORE_BRACE);
0398:                if (indentBeforeBrace && pos.getLine() != model)
0399:                    indent += indentSize;
0400:                return indent;
0401:            }
0402:
0403:            private final int indentAfterElse(Line model, String text,
0404:                    char textFirstChar, Buffer buffer) {
0405:                int indent = buffer.getIndentation(model);
0406:                final boolean indentBeforeBrace = buffer
0407:                        .getBooleanProperty(Property.INDENT_BEFORE_BRACE);
0408:                if (indentBeforeBrace || textFirstChar != '{')
0409:                    return indent + buffer.getIndentSize();
0410:                else
0411:                    return indent;
0412:            }
0413:
0414:            private final int indentAfterSwitchLabel(Line model, String text,
0415:                    char textFirstChar, Buffer buffer) {
0416:                int indent = buffer.getIndentation(model);
0417:                final boolean indentBeforeBrace = buffer
0418:                        .getBooleanProperty(Property.INDENT_BEFORE_BRACE);
0419:                if (indentBeforeBrace || textFirstChar != '{')
0420:                    return indent + buffer.getIndentSize();
0421:                else
0422:                    return indent;
0423:            }
0424:
0425:            private final int indentAfterCloseParen(Line model, String text,
0426:                    char textFirstChar, Buffer buffer) {
0427:                // Find matching '('.
0428:                SyntaxIterator it = getSyntaxIterator(new Position(model, model
0429:                        .length()));
0430:                char c;
0431:                do {
0432:                    c = it.prevChar();
0433:                } while (c != SyntaxIterator.DONE && c != ')');
0434:                Position pos = it.getPosition();
0435:                pos = matchClosingParen(pos);
0436:                boolean indent = false;
0437:                final String s = getIdentifierBefore(pos);
0438:                final String[] indentAfter = { "if", "while", "for", "switch",
0439:                        "catch" };
0440:                if (Utilities.isOneOf(s, indentAfter)) {
0441:                    indent = true;
0442:                } else if (buffer.getModeId() == JAVA_MODE) {
0443:                    if (s.equals("synchronized"))
0444:                        indent = true;
0445:                } else if (buffer.getModeId() == PHP_MODE) {
0446:                    if (s.equals("elseif") || s.equals("foreach"))
0447:                        indent = true;
0448:                }
0449:                if (indent) {
0450:                    int modelIndent = buffer.getIndentation(pos.getLine());
0451:                    if (textFirstChar != '{'
0452:                            || buffer
0453:                                    .getBooleanProperty(Property.INDENT_BEFORE_BRACE))
0454:                        return modelIndent + buffer.getIndentSize();
0455:                    else
0456:                        return modelIndent;
0457:                }
0458:                if (buffer.getModeId() == JAVA_MODE) {
0459:                    RE re = new UncheckedRE("\\s+new\\s+");
0460:                    if (re.getMatch(pos.getLine().getText().substring(0,
0461:                            pos.getOffset())) != null)
0462:                        indent = true;
0463:                }
0464:                int modelIndent = buffer
0465:                        .getIndentation(findBeginningOfStatement(pos).getLine());
0466:                if (indent
0467:                        && (textFirstChar != '{' || buffer
0468:                                .getBooleanProperty(Property.INDENT_BEFORE_BRACE)))
0469:                    return modelIndent + buffer.getIndentSize();
0470:                else
0471:                    return modelIndent;
0472:            }
0473:
0474:            private final int getIndentationOfEnclosingScope(Line line,
0475:                    Buffer buffer) {
0476:                SyntaxIterator it = getSyntaxIterator(new Position(line, 0));
0477:                loop: while (true) {
0478:                    switch (it.prevChar()) {
0479:                    case ')': {
0480:                        Position pos = matchClosingParen(it.getPosition());
0481:                        it = getSyntaxIterator(pos);
0482:                        break;
0483:                    }
0484:                    case '}': {
0485:                        Position pos = matchClosingBrace(it.getPosition());
0486:                        pos = findBeginningOfStatement(pos);
0487:                        return buffer.getIndentation(pos.getLine());
0488:                    }
0489:                    case '{': {
0490:                        Line model = it.getLine();
0491:                        String modelText = trimSyntacticWhitespace(model
0492:                                .getText());
0493:                        if (modelText.equals("{"))
0494:                            return buffer.getIndentation(model)
0495:                                    + buffer.getIndentSize();
0496:                        return indentAfterOpeningBrace(model, modelText, buffer);
0497:                    }
0498:                    case ':': {
0499:                        String firstIdentifier = getFirstIdentifier(it
0500:                                .getLine());
0501:                        if (firstIdentifier.equals("case")
0502:                                || firstIdentifier.equals("default"))
0503:                            return buffer.getIndentation(it.getLine())
0504:                                    + buffer.getIndentSize();
0505:                        break;
0506:                    }
0507:                    case SyntaxIterator.DONE:
0508:                        return 0;
0509:                    }
0510:                }
0511:            }
0512:
0513:            private boolean isInArrayInitializer(Line line) {
0514:                // Find matching opening brace.
0515:                Position match = matchClosingBrace(new Position(line, 0));
0516:                SyntaxIterator it = getSyntaxIterator(match);
0517:                char c;
0518:                do {
0519:                    c = it.prevChar();
0520:                } while (c != SyntaxIterator.DONE && Character.isWhitespace(c));
0521:                if (c == '=' || c == ']')
0522:                    return true;
0523:                return false;
0524:            }
0525:
0526:            protected static Line findModel(Line line) {
0527:                Line model = line.previous();
0528:                if (line.flags() == STATE_COMMENT) {
0529:                    // Any non-blank line is an acceptable model.
0530:                    while (model != null && model.isBlank())
0531:                        model = model.previous();
0532:                } else {
0533:                    while (model != null) {
0534:                        if (isAcceptableModel(model))
0535:                            break; // Found an acceptable model.
0536:                        else
0537:                            model = model.previous();
0538:                    }
0539:                }
0540:                return model;
0541:            }
0542:
0543:            private static final boolean isAcceptableModel(Line line) {
0544:                int flags = line.flags();
0545:                if (flags == STATE_COMMENT || flags == STATE_QUOTE)
0546:                    return false;
0547:                if (line.isBlank())
0548:                    return false;
0549:                String trim = line.trim();
0550:                char firstChar = trim.charAt(0);
0551:                if (firstChar == '/') {
0552:                    if (trim.length() > 1 && trim.charAt(1) == '/')
0553:                        return false;
0554:                } else if (firstChar == '#')
0555:                    return false;
0556:                String s = trimSyntacticWhitespace(line.getText());
0557:                if (s.length() == 0)
0558:                    return false;
0559:                return true;
0560:            }
0561:
0562:            // Returns true if line contains opening brace of class or method.
0563:            private boolean isOpeningBraceOfClassOrMethod(Line line) {
0564:                if (line.length() == 0)
0565:                    return false;
0566:                String text = trimSyntacticWhitespace(line.getText());
0567:                if (!text.endsWith("{"))
0568:                    return false;
0569:                if (text.equals("{")) {
0570:                    Line modelLine = findModel(line);
0571:                    if (modelLine == null)
0572:                        return true;
0573:                    Position beginningOfStatement = findBeginningOfStatement(new Position(
0574:                            modelLine, 0));
0575:                    text = beginningOfStatement.getLine().trim();
0576:                } else
0577:                    text = text.substring(0, text.length() - 1).trim();
0578:                if (text.indexOf('=') >= 0)
0579:                    return false;
0580:                final String firstIdentifier = getFirstIdentifier(text);
0581:                if (Utilities.isOneOf(firstIdentifier, conditionals))
0582:                    return false;
0583:                if (firstIdentifier.equals("case")
0584:                        || firstIdentifier.equals("default"))
0585:                    return false;
0586:                return true;
0587:            }
0588:
0589:            protected String getFirstIdentifier(String s) {
0590:                return Utilities.getFirstIdentifier(s, this );
0591:            }
0592:
0593:            protected final String getFirstIdentifier(Line line) {
0594:                return getFirstIdentifier(line.trim());
0595:            }
0596:
0597:            protected final String getLastIdentifier(String s) {
0598:                int i = s.length() - 1;
0599:                while (i >= 0) {
0600:                    if (isIdentifierPart(s.charAt(i))) {
0601:                        if (i > 0)
0602:                            --i;
0603:                        else
0604:                            break;
0605:                    } else {
0606:                        ++i;
0607:                        break;
0608:                    }
0609:                }
0610:                if (i >= 0 && i < s.length())
0611:                    return s.substring(i);
0612:                return null;
0613:            }
0614:
0615:            private final String getIdentifierBefore(Position pos) {
0616:                while (pos.prev())
0617:                    if (!Character.isWhitespace(pos.getChar()))
0618:                        break;
0619:                while (isIdentifierPart(pos.getChar()) && pos.prev())
0620:                    ;
0621:                while (!isIdentifierStart(pos.getChar()) && pos.next())
0622:                    ;
0623:                return pos.getIdentifier(this );
0624:            }
0625:
0626:            protected final Position matchClosingBrace(Position start) {
0627:                SyntaxIterator it = getSyntaxIterator(start);
0628:                int count = 1;
0629:                while (true) {
0630:                    switch (it.prevChar()) {
0631:                    case '}':
0632:                        ++count;
0633:                        break;
0634:                    case '{':
0635:                        --count;
0636:                        if (count == 0)
0637:                            return it.getPosition();
0638:                        break;
0639:                    case SyntaxIterator.DONE:
0640:                        return it.getPosition();
0641:                    default:
0642:                        break;
0643:                    }
0644:                }
0645:            }
0646:
0647:            protected final Position matchClosingParen(Position start) {
0648:                SyntaxIterator it = getSyntaxIterator(start);
0649:                int count = 1;
0650:                while (true) {
0651:                    switch (it.prevChar()) {
0652:                    case ')':
0653:                        ++count;
0654:                        break;
0655:                    case '(':
0656:                        --count;
0657:                        if (count == 0)
0658:                            return it.getPosition();
0659:                        break;
0660:                    case SyntaxIterator.DONE:
0661:                        return it.getPosition();
0662:                    default:
0663:                        break;
0664:                    }
0665:                }
0666:            }
0667:
0668:            // Scan backwards from starting position, looking for unmatched opening
0669:            // parenthesis.
0670:            protected Position findEnclosingParen(Position start) {
0671:                SyntaxIterator it = getSyntaxIterator(start);
0672:                int parenCount = 0;
0673:                int braceCount = 0;
0674:                boolean seenBrace = false;
0675:                while (true) {
0676:                    switch (it.prevChar()) {
0677:                    case '{':
0678:                        if (braceCount == 0)
0679:                            return null; // Found unmatched '{'.
0680:                        --braceCount;
0681:                        seenBrace = true;
0682:                        break;
0683:                    case '}':
0684:                        ++braceCount;
0685:                        seenBrace = true;
0686:                        break;
0687:                    case ';':
0688:                        if (seenBrace)
0689:                            return null;
0690:                        break;
0691:                    case ')':
0692:                        ++parenCount;
0693:                        break;
0694:                    case '(':
0695:                        if (parenCount == 0)
0696:                            return it.getPosition(); // Found unmatched '('.
0697:                        --parenCount;
0698:                        break;
0699:                    case SyntaxIterator.DONE:
0700:                        return null;
0701:                    default:
0702:                        break;
0703:                    }
0704:                }
0705:            }
0706:
0707:            private final Position findEnclosingBrace(Position start) {
0708:                SyntaxIterator it = getSyntaxIterator(start);
0709:                int count = 0;
0710:                while (true) {
0711:                    switch (it.prevChar()) {
0712:                    case '}':
0713:                        ++count;
0714:                        break;
0715:                    case '{':
0716:                        if (count == 0)
0717:                            return it.getPosition(); // Found unmatched '{'.
0718:                        --count;
0719:                        break;
0720:                    case SyntaxIterator.DONE:
0721:                        return null;
0722:                    default:
0723:                        break;
0724:                    }
0725:                }
0726:            }
0727:
0728:            // Scan backwards from line, looking for the start of a switch statement.
0729:            protected final Line findSwitch(Line line) {
0730:                Position pos = findEnclosingBrace(new Position(line, 0));
0731:                if (pos != null) {
0732:                    line = pos.getLine();
0733:                    do {
0734:                        String s = getFirstIdentifier(line);
0735:                        if (s.equals("switch"))
0736:                            return line;
0737:                    } while ((line = line.previous()) != null);
0738:                }
0739:                return null;
0740:            }
0741:
0742:            private Position matchElse(Position start) {
0743:                SyntaxIterator it = getSyntaxIterator(start);
0744:                int count = 1;
0745:                char c;
0746:                while ((c = it.prevChar()) != SyntaxIterator.DONE) {
0747:                    if (c == '}') {
0748:                        Position match = matchClosingBrace(it.getPosition());
0749:                        it = getSyntaxIterator(match);
0750:                        continue;
0751:                    }
0752:                    if (c == 'e') {
0753:                        Position pos = it.getPosition();
0754:                        if (pos.getIdentifier(this ).equals("else")) {
0755:                            ++count;
0756:                            continue;
0757:                        }
0758:                    }
0759:                    if (c == 'i') {
0760:                        Position pos = it.getPosition();
0761:                        if (pos.getIdentifier(this ).equals("if")) {
0762:                            --count;
0763:                            if (count == 0)
0764:                                return pos;
0765:                            continue;
0766:                        }
0767:                    }
0768:                }
0769:                return null;
0770:            }
0771:
0772:            public Position findBeginningOfStatement(Position start) {
0773:                Position pos = new Position(start);
0774:
0775:                final Position posParen = findEnclosingParen(pos);
0776:
0777:                if (posParen != null)
0778:                    pos = posParen;
0779:
0780:                final String trim = trimSyntacticWhitespace(pos.getLine()
0781:                        .getText());
0782:                final String lastIdentifier = getLastIdentifier(trim);
0783:                if (lastIdentifier != null && lastIdentifier.equals("else"))
0784:                    return new Position(pos.getLine(), 0); // BUG!! This is clearly wrong!
0785:                final String firstIdentifier = getFirstIdentifier(trim);
0786:                if (firstIdentifier != null
0787:                        && (firstIdentifier.equals("case") || firstIdentifier
0788:                                .equals("default")))
0789:                    return new Position(pos.getLine(), 0);
0790:
0791:                while (pos.getLine().trim().startsWith("}")
0792:                        && pos.getPreviousLine() != null) {
0793:                    pos.moveTo(pos.getPreviousLine(), pos.getPreviousLine()
0794:                            .length());
0795:                    pos = matchClosingBrace(pos);
0796:                }
0797:
0798:                SyntaxIterator it = getSyntaxIterator(pos);
0799:                boolean inParen = false;
0800:                int count = 0;
0801:                while (true) {
0802:                    char c = it.prevChar();
0803:                    if (c == SyntaxIterator.DONE)
0804:                        return it.getPosition();
0805:                    if (inParen) {
0806:                        if (c == ')')
0807:                            ++count;
0808:                        else if (c == '(') {
0809:                            --count;
0810:                            if (count == 0) // Found it!
0811:                                inParen = false;
0812:                        }
0813:                        continue;
0814:                    }
0815:                    if (c == ')') {
0816:                        inParen = true;
0817:                        count = 1;
0818:                        continue;
0819:                    }
0820:                    if (c == '{') {
0821:                        // If previous non-whitespace char is '=' then this is an array
0822:                        // initializer.
0823:                        pos = it.getPosition(); // Save position.
0824:                        char ch;
0825:                        do {
0826:                            ch = it.prevChar();
0827:                        } while (ch != SyntaxIterator.DONE
0828:                                && Character.isWhitespace(ch));
0829:                        if (ch == '=' || ch == ']') {
0830:                            // It is an array initializer.
0831:                            pos = it.getPosition();
0832:                            pos.moveTo(pos.getLine(), 0);
0833:                            return pos;
0834:                        }
0835:                        // Not an array initializer.
0836:                        it = getSyntaxIterator(pos); // Restore position.
0837:                        // Fall through...
0838:                    }
0839:                    if (";{}:".indexOf(c) >= 0) {
0840:                        do {
0841:                            c = it.nextChar();
0842:                        } while (c != SyntaxIterator.DONE
0843:                                && Character.isWhitespace(c));
0844:                        pos = it.getPosition();
0845:                        pos.setOffset(0);
0846:                        return pos;
0847:                    }
0848:                }
0849:            }
0850:
0851:            public Position findPreviousConditional(Position start) {
0852:                Position pos = start.copy();
0853:                Position posParen = findEnclosingParen(pos);
0854:                if (posParen != null)
0855:                    pos = posParen;
0856:                while (pos.getLine().trim().startsWith("}")
0857:                        && pos.getPreviousLine() != null) {
0858:                    pos.moveTo(pos.getPreviousLine(), pos.getPreviousLine()
0859:                            .length());
0860:                    pos = matchClosingBrace(pos);
0861:                }
0862:                while (true) {
0863:                    if (pos.getLine().flags() != STATE_COMMENT) {
0864:                        String text = pos.getLine().trim();
0865:                        // Handle "} else".
0866:                        if (text.startsWith("}"))
0867:                            text = text.substring(1).trim();
0868:                        String firstIdentifier = getFirstIdentifier(text);
0869:                        if (Utilities.isOneOf(firstIdentifier, conditionals)) {
0870:                            pos.setOffset(pos.getLine().getText().indexOf(
0871:                                    firstIdentifier));
0872:                            return pos;
0873:                        }
0874:                    }
0875:                    Line previousLine = pos.getPreviousLine();
0876:                    if (previousLine == null)
0877:                        return new Position(pos.getLine(), 0);
0878:                    pos.moveTo(previousLine, previousLine.length());
0879:                    if (pos.getLine().flags() == STATE_COMMENT)
0880:                        continue;
0881:                    posParen = findEnclosingParen(pos);
0882:                    if (posParen != null) {
0883:                        pos = posParen;
0884:                        continue;
0885:                    }
0886:                    String s = trimSyntacticWhitespace(pos.getLine().getText());
0887:                    if (s.length() > 0) {
0888:                        if (s.charAt(0) == '#') // C preprocessor.
0889:                            break;
0890:                        char lastChar = s.charAt(s.length() - 1);
0891:                        if (lastChar == ';' || lastChar == '{'
0892:                                || lastChar == '}' || lastChar == ':')
0893:                            break;
0894:                    }
0895:                }
0896:                // No conditional found.
0897:                return start;
0898:            }
0899:
0900:            protected final boolean isContinued(String text, char lastChar) {
0901:                switch (lastChar) {
0902:                case '+':
0903:                    return !text.endsWith("++");
0904:                case '/':
0905:                    return !text.endsWith("//");
0906:                case '=':
0907:                    return (!text.endsWith("==") && !text.endsWith("!="));
0908:                case ',':
0909:                    return true;
0910:                case '.':
0911:                    return true;
0912:                case '|':
0913:                    return text.endsWith("||");
0914:                case '&':
0915:                    return text.endsWith("&&");
0916:                default:
0917:                    return false;
0918:                }
0919:            }
0920:
0921:            // Replaces syntactic whitespace (quotes and comments) with actual space
0922:            // characters, then returns trimmed string.
0923:            protected static String trimSyntacticWhitespace(String s) {
0924:                JavaSyntaxIterator it = new JavaSyntaxIterator(null);
0925:                return new String(it.hideSyntacticWhitespace(s)).trim();
0926:            }
0927:
0928:            public boolean isIdentifierStart(char c) {
0929:                return Character.isJavaIdentifierStart(c);
0930:            }
0931:
0932:            public boolean isIdentifierPart(char c) {
0933:                return Character.isJavaIdentifierPart(c);
0934:            }
0935:
0936:            public boolean isInComment(Buffer buffer, Position pos) {
0937:                if (buffer == null || pos == null) {
0938:                    Debug.bug();
0939:                    return false;
0940:                }
0941:                final Line line = pos.getLine();
0942:                final String text = line.getText();
0943:                if (text == null)
0944:                    return false;
0945:                final char[] chars = text.toCharArray();
0946:                final int offset = pos.getOffset();
0947:                if (buffer.needsParsing())
0948:                    buffer.getFormatter().parseBuffer();
0949:                int state = line.flags();
0950:                final int length = chars.length;
0951:                for (int i = 0; i < length; i++) {
0952:                    if (i == offset)
0953:                        return state == STATE_COMMENT;
0954:                    char c = chars[i];
0955:                    if (c == '\\' && i < length - 1) {
0956:                        // Escape character.
0957:                        continue;
0958:                    }
0959:                    if (state == STATE_QUOTE) {
0960:                        if (c == '"')
0961:                            state = STATE_NEUTRAL;
0962:                        continue;
0963:                    }
0964:                    if (state == STATE_SINGLEQUOTE) {
0965:                        if (c == '\'')
0966:                            state = STATE_NEUTRAL;
0967:                        continue;
0968:                    }
0969:                    if (state == STATE_COMMENT) {
0970:                        if (c == '*' && i < length - 1 && chars[i + 1] == '/') {
0971:                            // /* */ comment ending
0972:                            state = STATE_NEUTRAL;
0973:                        }
0974:                        continue;
0975:                    }
0976:                    // Reaching here, STATE_NEUTRAL...
0977:                    if (c == '"') {
0978:                        state = STATE_QUOTE;
0979:                        continue;
0980:                    }
0981:                    if (c == '\'') {
0982:                        state = STATE_SINGLEQUOTE;
0983:                        continue;
0984:                    }
0985:                    if (c == '/') {
0986:                        if (i < length - 1) {
0987:                            if (chars[i + 1] == '*') {
0988:                                // /* */ comment starting
0989:                                state = STATE_COMMENT;
0990:                                continue;
0991:                            }
0992:                            if (chars[i + 1] == '/') {
0993:                                // "//" comment starting
0994:                                return true;
0995:                            }
0996:                        }
0997:                    }
0998:                }
0999:                return state == STATE_COMMENT;
1000:            }
1001:
1002:            public boolean isCommentLine(Line line) {
1003:                return line.trim().startsWith("//");
1004:            }
1005:
1006:            public static void insertComment() {
1007:                if (!Editor.checkExperimental())
1008:                    return;
1009:                final Editor editor = Editor.currentEditor();
1010:                String toBeInserted = Editor.preferences().getStringProperty(
1011:                        Property.JAVA_MODE_INSERT_COMMENT_TEXT);
1012:                if (toBeInserted == null)
1013:                    toBeInserted = "/**\\n * |\\n */";
1014:                Position caretPos = null;
1015:                CompoundEdit compoundEdit = editor.beginCompoundEdit();
1016:                final int limit = toBeInserted.length();
1017:                for (int i = 0; i < limit; i++) {
1018:                    char c = toBeInserted.charAt(i);
1019:                    if (c == '|') {
1020:                        caretPos = new Position(editor.getDot());
1021:                        continue;
1022:                    }
1023:                    if (c == '\\' && i < limit - 1) {
1024:                        c = toBeInserted.charAt(++i);
1025:                        if (c == 'n') {
1026:                            editor.newlineAndIndent();
1027:                            continue;
1028:                        }
1029:                        // Otherwise fall through...
1030:                    }
1031:                    editor.insertChar(c);
1032:                }
1033:                if (caretPos != null)
1034:                    editor.moveDotTo(caretPos);
1035:                editor.moveCaretToDotCol();
1036:                editor.endCompoundEdit(compoundEdit);
1037:                editor.getFormatter().parseBuffer();
1038:            }
1039:
1040:            public static void newlineAndIndentForComment() {
1041:                final Editor editor = Editor.currentEditor();
1042:                if (!editor.checkReadOnly())
1043:                    return;
1044:                final Buffer buffer = editor.getBuffer();
1045:                final Display display = editor.getDisplay();
1046:                String commentPrefix = null;
1047:                String s = editor.getDotLine().getText().trim();
1048:                int flags = editor.getDotLine().flags();
1049:                if (flags == STATE_COMMENT) {
1050:                    if (s.startsWith("*") && !s.endsWith("*/"))
1051:                        commentPrefix = "* ";
1052:                } else {
1053:                    // Look for start of comment on current line.
1054:                    if (s.startsWith("/*") && !s.endsWith("*/"))
1055:                        commentPrefix = "* ";
1056:                    else if (s.startsWith("//"))
1057:                        commentPrefix = "// ";
1058:                }
1059:                if (commentPrefix == null) {
1060:                    // No special handling necessary.
1061:                    editor.newlineAndIndent();
1062:                    return;
1063:                }
1064:                CompoundEdit compoundEdit = buffer.beginCompoundEdit();
1065:                if (editor.getMark() != null)
1066:                    editor.deleteRegion();
1067:                editor.addUndo(SimpleEdit.INSERT_LINE_SEP);
1068:                editor.insertLineSeparator();
1069:                // Trim leading whitespace. (This code actually trims trailing
1070:                // whitespace too.)
1071:                editor.addUndo(SimpleEdit.LINE_EDIT);
1072:                editor.getDotLine().setText(
1073:                        editor.getDotLine().getText().trim());
1074:                // Insert the comment prefix at the start of the new line.
1075:                editor.addUndo(SimpleEdit.INSERT_STRING);
1076:                editor.insertStringInternal(commentPrefix);
1077:                // Make the indentation code think we're still in a multi-line
1078:                // comment, if we were in one before.
1079:                editor.getDotLine().setFlags(flags);
1080:                editor.indentLine();
1081:                // We want dot to end up right after the comment prefix.
1082:                editor.moveDotToIndentation();
1083:                editor.getDot().skip(commentPrefix.length());
1084:                display.moveCaretToDotCol();
1085:                buffer.endCompoundEdit(compoundEdit);
1086:            }
1087:
1088:            public String getToolTipText(Editor editor, MouseEvent e) {
1089:                if (editor.getModeId() == JAVA_MODE) {
1090:                    if (editor.getBuffer().getBooleanProperty(
1091:                            Property.ENABLE_TOOL_TIPS)) {
1092:                        Position pos = editor.getDisplay().positionFromPoint(
1093:                                e.getPoint());
1094:                        if (pos != null) {
1095:                            final String name = getQualifiedName(pos);
1096:                            if (name != null) {
1097:                                JavaContext context = new JavaContext(editor);
1098:                                context.parseContext(pos);
1099:                                JavaVariable var = context
1100:                                        .findDeclaration(name);
1101:                                if (var != null)
1102:                                    return var.toString();
1103:                            }
1104:                        }
1105:                    }
1106:                }
1107:                return null;
1108:            }
1109:
1110:            private String getQualifiedName(Position pos) {
1111:                Line line = pos.getLine();
1112:                int offset = pos.getOffset();
1113:                final int limit = line.length();
1114:                if (offset < limit) {
1115:                    char c = line.charAt(offset);
1116:                    if (isIdentifierPart(c)) {
1117:                        while (offset > 0) {
1118:                            --offset;
1119:                            c = line.charAt(offset);
1120:                            if (!isIdentifierPart(c) && c != '.') {
1121:                                ++offset;
1122:                                break;
1123:                            }
1124:                        }
1125:                        // Now we're looking at the first character of the identifier.
1126:                        c = line.charAt(offset);
1127:                        if (isIdentifierStart(c)) {
1128:                            FastStringBuffer sb = new FastStringBuffer();
1129:                            sb.append(c);
1130:                            while (++offset < limit) {
1131:                                c = line.charAt(offset);
1132:                                if (isIdentifierPart(c)) {
1133:                                    sb.append(c);
1134:                                } else if (c == '.' && offset < pos.getOffset()) {
1135:                                    // We don't want to go beyond the end of the
1136:                                    // simple name at pos.
1137:                                    sb.append(c);
1138:                                } else
1139:                                    break;
1140:                            }
1141:                            return sb.toString();
1142:                        }
1143:                    }
1144:                }
1145:                return null;
1146:            }
1147:
1148:            public Expression getExpressionAtDot(final Editor editor,
1149:                    final boolean exact) {
1150:                if (editor.getModeId() == OBJC_MODE)
1151:                    return super .getExpressionAtDot(editor, exact);
1152:                if (editor.getDot() == null)
1153:                    return null;
1154:                Position begin;
1155:                if (editor.getMark() != null) {
1156:                    // Start at beginning of marked block.
1157:                    Region r = new Region(editor);
1158:                    begin = r.getBegin();
1159:                } else
1160:                    begin = editor.getDot();
1161:                final Line line = begin.getLine();
1162:                final int offset = begin.getOffset();
1163:                Position posExpr = null;
1164:                if (exact) {
1165:                    if (offset < line.length()
1166:                            && isIdentifierPart(line.charAt(offset)))
1167:                        posExpr = findIdentifierStart(line, offset);
1168:                    if (posExpr == null)
1169:                        return null;
1170:                }
1171:                if (posExpr == null) {
1172:                    // Not exact, or no identifier there.  Try to be smart.
1173:                    RE re = new UncheckedRE(
1174:                            "([A-Za-z_$]+[A-Za-z_$0-9]*)\\s*\\(");
1175:                    final String text = editor.getDotLine().getText();
1176:                    int index = 0;
1177:                    REMatch match;
1178:                    while ((match = re.getMatch(text, index)) != null) {
1179:                        String identifier = match.toString(1);
1180:                        if (!isKeyword(identifier)) {
1181:                            posExpr = new Position(line, match.getStartIndex());
1182:                            // If we've found a match to the right of dot, we're done.
1183:                            if (match.getEndIndex() > offset)
1184:                                break;
1185:                        }
1186:                        index = match.getEndIndex();
1187:                    }
1188:                }
1189:                if (posExpr == null) {
1190:                    // Smart didn't help.  Go back to exact.
1191:                    if (offset < line.length()
1192:                            && isIdentifierStart(line.charAt(offset)))
1193:                        posExpr = findIdentifierStart(line, offset);
1194:                }
1195:                if (posExpr == null)
1196:                    return null;
1197:                Position pos = posExpr.copy();
1198:                // Gather up method name.
1199:                FastStringBuffer sb = new FastStringBuffer();
1200:                while (true) {
1201:                    char c = pos.getChar();
1202:                    if (!isIdentifierPart(c))
1203:                        break;
1204:                    sb.append(c);
1205:                    if (!pos.next())
1206:                        break;
1207:                }
1208:                String name = sb.toString().trim();
1209:                // Skip whitespace (if any) between identifier and '('.
1210:                while (true) {
1211:                    char c = pos.getChar();
1212:                    if (!Character.isWhitespace(c))
1213:                        break;
1214:                    if (!pos.next())
1215:                        break;
1216:                }
1217:                final int arity;
1218:                if (editor.getModeId() == JAVASCRIPT_MODE)
1219:                    arity = -1; // Can't trust arity in JavaScript.
1220:                else
1221:                    arity = getArity(editor, pos);
1222:                if (arity >= 0)
1223:                    return new JavaExpression(name, arity);
1224:                else
1225:                    return new JavaExpression(name, arity, TAG_UNKNOWN);
1226:            }
1227:
1228:            private int getArity(Editor editor, Position pos) {
1229:                if (pos.getChar() != '(')
1230:                    return -1;
1231:                if (!pos.next())
1232:                    return -1;
1233:                final Position start = pos.copy();
1234:                int parenCount = 0;
1235:                int arity = 0;
1236:                char quoteChar = '\0';
1237:                boolean inQuote = false;
1238:                while (!pos.atEnd()) {
1239:                    char c = pos.getChar();
1240:                    if (inQuote) {
1241:                        if (c == quoteChar)
1242:                            inQuote = false;
1243:                        pos.next();
1244:                        continue;
1245:                    }
1246:                    // Not in a quoted string.
1247:                    if (c == '"' || c == '\'') {
1248:                        inQuote = true;
1249:                        quoteChar = c;
1250:                        pos.next();
1251:                        continue;
1252:                    }
1253:                    if (c == ',') {
1254:                        if (parenCount == 0) // Top level.
1255:                            ++arity;
1256:                        pos.next();
1257:                        continue;
1258:                    }
1259:                    if (c == '(') {
1260:                        ++parenCount;
1261:                        pos.next();
1262:                        continue;
1263:                    }
1264:                    if (c == ')') {
1265:                        --parenCount;
1266:                        if (parenCount < 0) {
1267:                            // Closing paren, done.
1268:                            if (arity == 0) {
1269:                                // We haven't seen a comma.
1270:                                Region r = new Region(editor.getBuffer(),
1271:                                        start, pos);
1272:                                if (r.toString().trim().length() > 0)
1273:                                    arity = 1;
1274:                            } else
1275:                                ++arity;
1276:                            return arity;
1277:                        }
1278:                        pos.next();
1279:                        continue;
1280:                    }
1281:                    pos.next();
1282:                }
1283:                return -1;
1284:            }
1285:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.