1 21 22 package org.armedbear.j; 23 24 import java.awt.Color ; 25 import java.awt.event.MouseEvent ; 26 import java.util.List ; 27 import javax.swing.JCheckBoxMenuItem ; 28 import javax.swing.JMenuItem ; 29 import javax.swing.JPopupMenu ; 30 31 52 public abstract class AbstractMode implements Constants, Mode 53 { 54 private static final Preferences preferences = Editor.preferences(); 55 56 protected KeyMap keyMap; 57 protected File keyMapFile; 58 protected PropertyList properties; 59 protected Keywords keywords; 60 61 private final int id; 62 private final String displayName; 63 64 protected AbstractMode(int id, String displayName) 65 { 66 this.id = id; 67 this.displayName = displayName; 68 if (Editor.isLispInitialized()) { 69 String hook = 70 displayName.toLowerCase().replace(' ', '-') + "-mode-hook"; 71 Editor.invokeHook(hook); 72 } 73 } 74 75 82 public final int getId() 83 { 84 return id; 85 } 86 87 94 public final String getDisplayName() 95 { 96 return displayName; 97 } 98 99 112 public Buffer createBuffer(File file) 113 { 114 return null; 115 } 116 117 125 public Formatter getFormatter(Buffer buffer) 126 { 127 return new PlainTextFormatter(buffer); 128 } 129 130 135 public final String toString() 136 { 137 return displayName; 138 } 139 140 public synchronized final KeyMap getKeyMap() 142 { 143 if (keyMap == null) { 144 if (!loadKeyMapForMode()) { 145 keyMap = new KeyMap(); 146 setKeyMapDefaults(keyMap); 147 } 148 } 149 return keyMap; 150 } 151 152 private boolean loadKeyMapForMode() 153 { 154 keyMap = null; 155 String filename = preferences.getStringProperty(getFullKey("keyMap")); 156 if (filename != null) { 157 keyMapFile = File.getInstance(filename); 158 if (keyMapFile != null) { 159 keyMap = new KeyMap(); 160 if (keyMap.load(keyMapFile)) 161 return true; 162 } 163 } 164 keyMap = null; 165 keyMapFile = null; 166 return false; 167 } 168 169 protected void setKeyMapDefaults(KeyMap km) 170 { 171 } 173 174 public File getKeyMapFile() 175 { 176 return keyMapFile; 177 } 178 179 public synchronized final void useDefaultKeyMap() 180 { 181 keyMap = new KeyMap(); 182 setKeyMapDefaults(keyMap); 183 } 184 185 public synchronized final void deleteKeyMap() 186 { 187 keyMap = null; 188 } 189 190 public String getMenuName() 191 { 192 return "Default"; 193 } 194 195 public MenuBar createMenuBar(Frame frame) 196 { 197 MenuBar menuBar = new MenuBar("Default"); 198 menuBar.add(new Menu("File", 'F')); 199 menuBar.add(new Menu("Edit", 'E')); 200 menuBar.add(new Menu("View", 'V')); 201 menuBar.add(new Menu("Search", 'S')); 202 menuBar.add(new Menu("Go", 'G')); 203 menuBar.add(new Menu("Mode", 'M')); 204 menuBar.add(new Menu("Lisp", 'L')); 205 menuBar.add(new Menu("Help", 'H')); 206 return menuBar; 207 } 208 209 public void populateMenu(Editor editor, Menu menu) 210 { 211 final String text = menu.getText(); 212 if (text == "File") 213 populateFileMenu(editor, menu); 214 else if (text == "Edit") 215 populateEditMenu(editor, menu); 216 else if (text == "View") 217 populateViewMenu(editor, menu); 218 else if (text == "Search") 219 populateSearchMenu(editor, menu); 220 else if (text == "Go") 221 populateGoMenu(editor, menu); 222 else if (text == "Mode") { 223 populateModeMenu(editor, menu); 224 if (menu.getMenuComponentCount() == 0) 225 menu.add(new JMenuItem ("This menu isn't here yet!")).setEnabled(false); 226 } else if (text == "Lisp") 227 populateLispMenu(editor, menu); 228 else if (text == "Help") 229 populateHelpMenu(editor, menu); 230 } 231 232 private static void populateFileMenu(Editor editor, Menu menu) 233 { 234 final boolean isNotReadOnly = !editor.getBuffer().isReadOnly(); 235 menu.add(editor, "New", 'N', "newBuffer"); 236 menu.add(editor, "Open...", 'O', "openFile"); 237 menu.add(editor, "Recent Files...", 'R', "recentFiles"); 238 menu.addSeparator(); 239 menu.add(editor, "Save", 'S', "save", isNotReadOnly); 240 menu.add(editor, "Save As...", 'E', "saveAs"); 241 menu.add(editor, "Save a Copy...", 'Y', "saveCopy"); 242 menu.add(editor, "Save All", 'A', "saveAll"); 243 menu.add(editor, "Close", 'C', "killBuffer"); 244 menu.add(editor, "Close All", 'L', "closeAll"); 245 menu.add(editor, "Close Others", 'H', "closeOthers"); 246 menu.add(editor, "Revert", 'V', "revertBuffer"); 247 menu.add(editor, "Set Encoding", 'G', "setEncoding"); 248 menu.addSeparator(); 249 menu.add(editor, "Properties", 'I', "properties"); 250 menu.addSeparator(); 251 menu.add(editor, "Next Buffer", 'T', "nextBuffer"); 252 menu.add(editor, "Previous Buffer", 'R', "prevBuffer"); 253 menu.addSeparator(); 254 menu.add(editor, "New Frame", 'M', "newFrame"); 255 menu.add(editor, "Execute Command...", 'D', "executeCommand"); 256 menu.addSeparator(); 257 menu.add(editor, "Print...", 'P', "print"); 258 menu.addSeparator(); 259 menu.add(editor, "Save Session", 'S', "saveSession"); 260 menu.add(editor, "Load Session...", 'L', "loadSession"); 261 menu.addSeparator(); 262 menu.add(editor, "Save All/Exit", '/', "saveAllExit"); 263 menu.add(editor, "Exit", 'X', "quit"); 264 } 265 266 private static void populateEditMenu(Editor editor, Menu menu) 267 { 268 final boolean isNotReadOnly = !editor.getBuffer().isReadOnly(); 269 menu.add(editor, "Undo", 'U', "undo"); 270 menu.add(editor, "Redo", 'O', "redo"); 271 menu.addSeparator(); 272 menu.add(editor, "Cut", 'T', "killRegion", isNotReadOnly); 273 menu.add(editor, "Cut Append", 'D', "killAppend", isNotReadOnly); 274 menu.add(editor, "Copy", 'C', "copyRegion"); 275 menu.add(editor, "Copy Append", 'A', "copyAppend"); 276 menu.add(editor, "Paste", 'P', "paste", isNotReadOnly); 277 menu.add(editor, "Cycle Paste", 'Y', "cyclePaste", isNotReadOnly); 278 menu.addSeparator(); 279 menu.add(editor, "Cycle Tab Width", 'B', "cycleTabWidth"); 280 menu.add(editor, "Cycle Indent Size", 'N', "cycleIndentSize"); 281 menu.add(editor, "Indent", 'I', "indentLineOrRegion", isNotReadOnly); 282 menu.addSeparator(); 283 menu.add(editor, "Upper Case", 'R', "upperCaseRegion", isNotReadOnly); 284 menu.add(editor, "Lower Case", 'L', "lowerCaseRegion", isNotReadOnly); 285 } 286 287 private static void populateViewMenu(Editor editor, Menu menu) 288 { 289 JCheckBoxMenuItem toolbarMenuItem = new JCheckBoxMenuItem ("Toolbar"); 290 toolbarMenuItem.setMnemonic('T'); 291 toolbarMenuItem.setActionCommand("toggleToolbar"); 292 toolbarMenuItem.addActionListener(editor.getDispatcher()); 293 toolbarMenuItem.setSelected(editor.getFrame().getShowToolbar()); 294 menu.add(toolbarMenuItem); 295 JCheckBoxMenuItem sidebarMenuItem = new JCheckBoxMenuItem ("Sidebar"); 296 sidebarMenuItem.setMnemonic('S'); 297 sidebarMenuItem.setActionCommand("toggleSidebar"); 298 sidebarMenuItem.addActionListener(editor.getDispatcher()); 299 sidebarMenuItem.setSelected(editor.getSidebar() != null); 300 menu.add(sidebarMenuItem); 301 menu.addSeparator(); 302 menu.add(editor, "Split Window", 'W', "splitWindow"); 303 menu.add(editor, "Unsplit Window", 'U', "unsplitWindow"); 304 menu.add(editor, "Close Window", 'C', "killWindow"); 305 } 306 307 protected void populateSearchMenu(Editor editor, Menu menu) 308 { 309 final File dir = editor.getCurrentDirectory(); 310 final boolean local = (dir != null && dir.isLocal()); 311 if (Editor.preferences().getBooleanProperty(Property.USE_INCREMENTAL_FIND)) 312 menu.add(editor, "Incremental Find...", 'I', "incrementalFind"); 313 menu.add(editor, "Find...", 'F', "find"); 314 menu.add(editor, "Find Next", 'T', "findNext"); 315 menu.add(editor, "Find Previous", 'R', "findPrev"); 316 menu.add(editor, "Find in Files...", 'S', "findInFiles", local); 317 menu.addSeparator(); 318 menu.add(editor, "List Occurrences of Last Pattern", 'L', "listOccurrences", 319 editor.getLastSearch() != null); 320 menu.add(editor, "List Occurrences of Pattern in Files", 'O', "listFiles", 321 FindInFiles.getFindInFiles() != null); 322 menu.addSeparator(); 323 final boolean isNotReadOnly = !editor.getBuffer().isReadOnly(); 324 if (!(editor.getBuffer() instanceof Directory)) 325 menu.add(editor, "Replace...", 'P', "replace", isNotReadOnly); 326 menu.add(editor, "Replace in Files...", 'E', "replaceInFiles", local); 327 if (!(editor.getBuffer() instanceof Directory)) { 328 menu.addSeparator(); 329 menu.add(editor, "Find Tag...", 'A', "findTag"); 330 } 331 } 332 333 private static void populateGoMenu(Editor editor, Menu menu) 334 { 335 menu.add(editor, "Go to Line...", 'L', "jumpToLine"); 336 menu.add(editor, "Go to Column...", 'C', "jumpToColumn"); 337 menu.add(editor, "Go to Offset...", 'O', "jumpToOffset"); 338 if (editor.getModeId() == HTML_MODE) 339 menu.add(editor, "Go to Matching HTML", 'M', "htmlFindMatch"); 340 else 341 menu.add(editor, "Go to Matching Character", 'M', "findMatchingChar"); 342 menu.add(editor, "Go to Tag", 'A', "findTagAtDot"); 343 menu.add(editor, "Go to Next Occurrence of Word", 'T', "findNextWord"); 344 menu.add(editor, "Go to Previous Occurrence of Word", 'R', "findPrevWord"); 345 if (editor.getBuffer().getBooleanProperty(Property.SHOW_CHANGE_MARKS)) { 346 menu.add(editor, "Go to Next Change", 'H', "nextChange"); 347 menu.add(editor, "Go to Previous Change", 'G', "previousChange"); 348 } 349 menu.addSeparator(); 350 menu.add(editor, "Push Position", 'U', "pushPosition"); 351 menu.add(editor, "Pop Position", 'P', "popPosition"); 352 } 353 354 public void populateModeMenu(Editor editor, Menu menu) 355 { 356 } 357 358 public void populateLispMenu(Editor editor, Menu menu) 359 { 360 menu.add(editor, "Run Lisp as Separate Process", 'L', "lisp"); 361 menu.add(editor, "Run Embedded Lisp", 'E', "jlisp"); 362 } 363 364 private static void populateHelpMenu(Editor editor, Menu menu) 365 { 366 menu.add(editor, "Help", 'P', "help"); 367 menu.add(editor, "Apropos...", 'A', "apropos"); 368 menu.add(editor, "Key Bindings", 'B', "listBindings"); 369 menu.add(editor, "Describe Key...", 'K', "describeKey"); 370 menu.add(editor, "Where is...", 'W', "whereIs"); 371 menu.add(editor, "About J", 'O', "about"); 372 } 373 374 public JPopupMenu getContextMenu(Editor editor) 375 { 376 final JPopupMenu popup = new JPopupMenu (); 377 addDefaultContextMenuItems(editor, popup); 378 popup.pack(); 379 return popup; 380 } 381 382 protected void addDefaultContextMenuItems(Editor editor, JPopupMenu popup) 383 { 384 final Buffer buffer = editor.getBuffer(); 385 final Dispatcher dispatcher = editor.getDispatcher(); 386 387 JMenuItem menuItem; 388 389 if (buffer.supportsUndo()) { 390 menuItem = new JMenuItem (); 391 menuItem.setText("Undo"); 392 menuItem.setActionCommand("undo"); 393 menuItem.addActionListener(dispatcher); 394 if (!buffer.canUndo()) 395 menuItem.setEnabled(false); 396 popup.add(menuItem); 397 398 menuItem = new JMenuItem (); 399 menuItem.setText("Redo"); 400 menuItem.setActionCommand("redo"); 401 menuItem.addActionListener(dispatcher); 402 if (!buffer.canRedo()) 403 menuItem.setEnabled(false); 404 popup.add(menuItem); 405 406 popup.addSeparator(); 407 } 408 409 menuItem = new JMenuItem (); 410 menuItem.setText(editor.getMark() == null ? "Cut line" : "Cut"); 411 menuItem.setActionCommand("killRegion"); 412 menuItem.addActionListener(dispatcher); 413 if (buffer.isReadOnly()) 414 menuItem.setEnabled(false); 415 popup.add(menuItem); 416 417 menuItem = new JMenuItem (); 418 menuItem.setText(editor.getMark() == null ? "Copy line" : "Copy"); 419 menuItem.setActionCommand("copyRegion"); 420 menuItem.addActionListener(dispatcher); 421 if (editor.getMark() == null && editor.getDotLine().isBlank()) 422 menuItem.setEnabled(false); 423 popup.add(menuItem); 424 425 menuItem = new JMenuItem ("Paste"); 426 menuItem.setActionCommand("paste"); 427 menuItem.addActionListener(dispatcher); 428 if (!editor.canPaste()) 429 menuItem.setEnabled(false); 430 popup.add(menuItem); 431 432 menuItem = new JMenuItem (); 434 menuItem.setActionCommand("listOccurrencesOfPatternAtDot"); 435 menuItem.addActionListener(dispatcher); 436 Search search = editor.getSearchAtDot(); 437 if (search != null) { 438 if (editor.getMark() != null) 439 menuItem.setText("List occurrences of selected text"); 440 else 441 menuItem.setText("List occurrences of \"" + search.getPattern() + "\""); 442 } else { 443 menuItem.setText("List occurences of pattern under cursor"); 444 menuItem.setEnabled(false); 445 } 446 popup.addSeparator(); 447 popup.add(menuItem); 448 449 if (buffer.isTaggable()) { 451 menuItem = new JMenuItem (); 452 menuItem.setActionCommand("findTagAtDot"); 453 menuItem.addActionListener(dispatcher); 454 if (editor.getMark() == null) { 455 Expression expr = getExpressionAtDot(editor, false); 456 if (expr != null) 457 menuItem.setText("Find tag \"" + expr.getName() + "\""); 458 } else { 459 menuItem.setText("Find tag under cursor"); 460 menuItem.setEnabled(false); 461 } 462 popup.add(menuItem); 463 } 464 465 popup.addSeparator(); 467 addContextMenuItem("Fold", "fold", popup, dispatcher); 468 addContextMenuItem("Unfold", "unfold", popup, dispatcher); 469 addContextMenuItem("Unfold all", "unfoldAll", popup, dispatcher); 470 471 if (buffer.getFile() != null && !(buffer instanceof Directory)) { 473 popup.addSeparator(); 474 addContextMenuItem("Properties", "properties", popup, dispatcher); 475 } 476 } 477 478 protected JMenuItem addContextMenuItem(String text, String command, 479 JPopupMenu popup, Dispatcher dispatcher) 480 { 481 JMenuItem menuItem = new JMenuItem (text); 482 menuItem.setActionCommand(command); 483 menuItem.addActionListener(dispatcher); 484 popup.add(menuItem); 485 return menuItem; 486 } 487 488 public ToolBar getToolBar(Frame frame) 489 { 490 ToolBar tb = getCustomToolBar(frame); 491 if (tb != null) 492 return tb; 493 return getDefaultToolBar(frame); 494 } 495 496 protected ToolBar getCustomToolBar(Frame frame) 497 { 498 String filename = 499 Editor.preferences().getStringProperty(getFullKey("toolbar")); 500 if (filename != null) { 501 File file = File.getInstance(filename); 502 if (file != null && file.isFile()) { 503 ToolBar tb = ToolBar.createToolBar(frame, file); 504 if (tb != null) 505 return tb; 506 } 507 } 508 return null; 509 } 510 511 protected ToolBar getDefaultToolBar(Frame frame) 512 { 513 return frame.getDefaultToolBar(); 514 } 515 516 public NavigationComponent getSidebarComponent(Editor editor) 517 { 518 if (isTaggable()) 519 return new SidebarTagList(editor.getSidebar(), editor); 520 else 521 return null; 522 } 523 524 531 public Tagger getTagger(SystemBuffer buffer) 532 { 533 return null; 534 } 535 536 542 public boolean isTaggable() 543 { 544 return false; 545 } 546 547 553 public boolean hasQualifiedNames() 554 { 555 return false; 556 } 557 558 566 public boolean isQualifiedName(String s) 567 { 568 return s.indexOf('.') >= 0 || s.indexOf("::") >= 0; 569 } 570 571 577 public boolean canIndent() 578 { 579 return false; 580 } 581 582 588 public boolean canIndentPaste() 589 { 590 return canIndent(); 591 } 592 593 public boolean acceptsLinePaste(Editor editor) 594 { 595 return true; 596 } 597 598 606 public int getCorrectIndentation(Line line, Buffer buffer) 607 { 608 return 0; 609 } 610 611 619 public SyntaxIterator getSyntaxIterator(Position pos) 620 { 621 return new DefaultSyntaxIterator(pos); 622 } 623 624 630 public String getCommentStart() 631 { 632 return null; 633 } 634 635 641 public String getCommentEnd() 642 { 643 return null; 644 } 645 646 public boolean getBooleanProperty(Property property) 647 { 648 String key = property.key(); 649 650 String s = preferences.getStringProperty(getFullKey(key)); 652 653 if (s == null) { 654 if (properties != null) { 658 Object value = properties.getProperty(property); 659 if (value instanceof Boolean ) 660 return ((Boolean ) value).booleanValue(); 661 } 662 663 s = preferences.getStringProperty(key); 666 } 667 668 if (s != null) { 669 s = s.trim(); 670 if (s.equals("true") || s.equals("1")) 671 return true; 672 if (s.equals("false") || s.equals("0")) 673 return false; 674 } 675 676 return ((Boolean )getDefaultValue(property)).booleanValue(); 679 } 680 681 public int getIntegerProperty(Property property) 682 { 683 String key = property.key(); 684 685 String s = preferences.getStringProperty(getFullKey(key)); 687 688 if (s == null) { 689 if (properties != null) { 693 Object value = properties.getProperty(property); 694 if (value instanceof Integer ) 695 return ((Integer ) value).intValue(); 696 } 697 698 s = preferences.getStringProperty(key); 701 } 702 703 if (s != null) { 704 try { 705 return Integer.parseInt(s.trim()); 706 } 707 catch (NumberFormatException e) {} 708 } 709 710 return ((Integer )getDefaultValue(property)).intValue(); 713 } 714 715 public String getStringProperty(Property property) 716 { 717 String key = property.key(); 718 719 String s = preferences.getStringProperty(getFullKey(key)); 721 722 if (s == null) { 723 if (properties != null) { 727 Object value = properties.getProperty(property); 728 if (value instanceof String ) 729 return (String ) value; 730 } 731 732 s = preferences.getStringProperty(key); 735 } 736 737 if (s != null) 738 return s; 739 740 return (String ) getDefaultValue(property); } 744 745 public Color getColorProperty(Property property) 746 { 747 String key = property.key(); 748 749 String value = preferences.getStringProperty(getFullKey(key)); 751 752 if (value == null) { 753 756 value = preferences.getStringProperty(key); 758 } 759 760 if (value != null) 761 return Utilities.getColor(value); 762 else 763 return null; 764 } 765 766 774 public void setProperty(Property property, String value) 775 { 776 if (properties == null) 777 properties = new PropertyList(); 778 properties.setProperty(property, value); 779 } 780 781 789 public void setProperty(Property property, boolean value) 790 { 791 if (properties == null) 792 properties = new PropertyList(); 793 properties.setProperty(property, value); 794 } 795 796 804 public void setProperty(Property property, int value) 805 { 806 if (properties == null) 807 properties = new PropertyList(); 808 properties.setProperty(property, value); 809 } 810 811 817 protected Object getDefaultValue(Property property) 818 { 819 return property.getDefaultValue(); 820 } 821 822 public final boolean accepts(String filename) 823 { 824 return Editor.getModeList().modeAccepts(id, filename); 825 } 826 827 protected String getFullKey(String key) 828 { 829 FastStringBuffer sb = new FastStringBuffer(this.getClass().getName()); 830 sb.append('.'); 831 sb.append(key); 832 final String fullKey = sb.toString().toLowerCase(); 833 if (fullKey.startsWith("org.armedbear.j.mail.")) 834 return fullKey.substring(21); 835 else if (fullKey.startsWith("org.armedbear.j.")) 836 return fullKey.substring(16); 837 else 838 return fullKey; 839 } 840 841 847 public boolean isIdentifierStart(char c) 848 { 849 return Character.isJavaIdentifierStart(c); 850 } 851 852 858 public boolean isIdentifierPart(char c) 859 { 860 return Character.isJavaIdentifierPart(c); 861 } 862 863 873 public boolean isInQuote(Buffer buffer, Position pos) 874 { 875 Line line = pos.getLine(); 879 int offset = pos.getOffset(); 880 boolean inQuote = false; 881 char quoteChar = '\0'; 882 for (int i = 0; i < offset; i++) { 883 char c = line.charAt(i); 884 if (c == '\\') { 885 ++i; 887 } else if (inQuote) { 888 if (c == quoteChar) 889 inQuote = false; 890 } else { 891 if (c == '"' || c == '\'') { 892 inQuote = true; 893 quoteChar = c; 894 } 895 } 896 } 897 return inQuote; 898 } 899 900 908 public boolean isInComment(Buffer buffer, Position pos) 909 { 910 return false; 911 } 912 913 920 public boolean isCommentLine(Line line) 921 { 922 return false; 923 } 924 925 933 public char fixCase(Editor editor, char c) 934 { 935 return c; 936 } 937 938 947 public String getContextString(Editor editor, boolean verbose) 948 { 949 final List tags = editor.getBuffer().getTags(); 950 if (tags != null) { 951 Position pos = editor.getDot(); 952 if (pos != null) { 953 LocalTag tag = null; 954 final int target = pos.lineNumber(); 956 final int limit = tags.size(); 957 for (int i = 0; i < limit; i++) { 958 LocalTag nextTag = (LocalTag) tags.get(i); 959 if (nextTag.lineNumber() > target) 960 break; 961 else 962 tag = nextTag; 963 } 964 if (tag != null) 965 return verbose ? tag.getLongName() : tag.getMethodName(); 966 } 967 } 968 return null; 969 } 970 971 979 public String getMouseMovedContextString(Editor editor, Position pos) 980 { 981 return null; 982 } 983 984 992 public String getToolTipText(Editor editor, MouseEvent e) 993 { 994 return null; 995 } 996 997 1005 public void loadFile(Buffer buffer, File file) 1006 { 1007 } 1008 1009 public boolean confirmClose(Editor editor, Buffer buffer) 1010 { 1011 if (!buffer.isModified()) 1012 return true; 1013 if (buffer.getFile() == null) 1014 return true; 1015 return CloseBufferConfirmationDialog.confirmClose(editor, buffer); 1016 } 1017 1018 public boolean isKeyword(String s) 1019 { 1020 if (keywords != null) 1021 return keywords.isKeyword(s); 1022 return false; 1023 } 1024 1025 public Expression getExpressionAtDot(Editor editor, boolean exact) 1026 { 1027 if (editor.getDot() == null) 1028 return null; 1029 final Position begin; 1030 if (editor.getMark() != null) { 1031 Region r = new Region(editor); 1033 begin = r.getBegin(); 1034 } else 1035 begin = editor.getDot(); 1036 Line line = begin.getLine(); 1037 int offset = begin.getOffset(); 1038 if (offset < line.length() && isIdentifierStart(line.charAt(offset))) { 1039 String identifier = getIdentifier(line, offset); 1040 if (identifier != null) 1041 return new Expression(identifier); 1042 } 1043 while (--offset >= 0) { 1045 char c = line.charAt(offset); 1046 if (isIdentifierStart(c)) { 1047 String identifier = getIdentifier(line, offset); 1048 if (identifier != null) 1049 return new Expression(identifier); 1050 } 1051 } 1052 offset = begin.getOffset(); 1054 while (++offset < line.length()) { 1055 char c = line.charAt(offset); 1056 if (isIdentifierStart(c)) { 1057 String identifier = getIdentifier(line, offset); 1058 if (identifier != null) 1059 return new Expression(identifier); 1060 } 1061 } 1062 return null; 1063 } 1064 1065 public final String getIdentifier(Position pos) 1066 { 1067 return getIdentifier(pos.getLine(), pos.getOffset()); 1068 } 1069 1070 public final String getIdentifier(Line line, int offset) 1071 { 1072 int limit = line.length(); 1073 if (offset < limit) { 1074 char c = line.charAt(offset); 1075 if (isIdentifierPart(c)) { 1076 while (offset > 0) { 1077 --offset; 1078 c = line.charAt(offset); 1079 if (!isIdentifierPart(c)) { 1080 ++offset; 1081 break; 1082 } 1083 } 1084 c = line.charAt(offset); 1086 if (isIdentifierStart(c)) { 1087 FastStringBuffer sb = new FastStringBuffer(c); 1088 while (++offset < limit) { 1089 c = line.charAt(offset); 1090 if (isIdentifierPart(c)) 1091 sb.append(c); 1092 else 1093 break; 1094 } 1095 return sb.toString(); 1096 } 1097 } 1098 } 1099 return null; 1100 } 1101 1102 public Position findIdentifierStart(Line line, int offset) 1103 { 1104 if (!isIdentifierPart(line.charAt(offset))) 1105 return null; 1106 int start = offset; 1107 while (--offset >= 0) { 1108 if (!isIdentifierPart(line.charAt(offset))) 1109 break; 1110 start = offset; 1111 } 1112 return new Position(line, start); 1113 } 1114} 1115 | Popular Tags |