1 19 20 package org.netbeans.editor.ext; 21 22 import java.util.HashMap ; 23 import javax.swing.text.Document ; 24 import javax.swing.text.Position ; 25 import org.netbeans.editor.BaseDocument; 26 import org.netbeans.editor.Syntax; 27 import org.netbeans.editor.TokenID; 28 import org.netbeans.editor.TokenContextPath; 29 import org.netbeans.editor.TokenItem; 30 import org.netbeans.editor.Analyzer; 31 32 43 44 public class FormatSupport { 45 46 47 private FormatWriter formatWriter; 48 49 public FormatSupport(FormatWriter formatWriter) { 50 this.formatWriter = formatWriter; 51 } 52 53 54 public FormatWriter getFormatWriter() { 55 return formatWriter; 56 } 57 58 public int getTabSize() { 59 Document doc = formatWriter.getDocument(); 60 return (doc instanceof BaseDocument) 61 ? ((BaseDocument)doc).getTabSize() 62 : formatWriter.getFormatter().getTabSize(); 63 } 64 65 public int getShiftWidth() { 66 Document doc = formatWriter.getDocument(); 67 return (doc instanceof BaseDocument) 68 ? ((BaseDocument)doc).getShiftWidth() 69 : formatWriter.getFormatter().getShiftWidth(); 70 } 71 72 public boolean expandTabs() { 73 return formatWriter.getFormatter().expandTabs(); 74 } 75 76 public int getSpacesPerTab() { 77 return formatWriter.getFormatter().getSpacesPerTab(); 78 } 79 80 public Object getSettingValue(String settingName) { 81 return formatWriter.getFormatter().getSettingValue(settingName); 82 } 83 84 public Object getSettingValue(String settingName, Object defaultValue) { 85 Object value = getSettingValue(settingName); 86 return (value != null) ? value : defaultValue; 87 } 88 89 public boolean getSettingBoolean(String settingName, Boolean defaultValue) { 90 return ((Boolean )getSettingValue(settingName, defaultValue)).booleanValue(); 91 } 92 93 public boolean getSettingBoolean(String settingName, boolean defaultValue) { 94 return ((Boolean )getSettingValue(settingName, 95 (defaultValue ? Boolean.TRUE : Boolean.FALSE))).booleanValue(); 96 } 97 98 public int getSettingInteger(String settingName, Integer defaultValue) { 99 return ((Integer )getSettingValue(settingName, defaultValue)).intValue(); 100 } 101 102 public int getSettingInteger(String settingName, int defaultValue) { 103 Object value = getSettingValue(settingName); 104 return (value instanceof Integer ) ? ((Integer )value).intValue() : defaultValue; 105 } 106 107 108 public final boolean isIndentOnly() { 109 return formatWriter.isIndentOnly(); 110 } 111 112 113 public FormatTokenPosition getFormatStartPosition() { 114 return formatWriter.getFormatStartPosition(); 115 } 116 117 public FormatTokenPosition getTextStartPosition() { 118 return formatWriter.getTextStartPosition(); 119 } 120 121 122 public TokenItem findFirstToken(TokenItem token) { 123 return formatWriter.findFirstToken(token); 124 } 125 126 127 public TokenItem getLastToken() { 128 return formatWriter.getLastToken(); 129 } 130 131 public FormatTokenPosition getLastPosition() { 132 TokenItem lt = findNonEmptyToken(getLastToken(), true); 133 return (lt == null) ? null : getPosition(lt, lt.getImage().length() - 1); 134 } 135 136 137 public boolean canInsertToken(TokenItem beforeToken) { 138 return formatWriter.canInsertToken(beforeToken); 139 } 140 141 142 public TokenItem insertToken(TokenItem beforeToken, 143 TokenID tokenID, TokenContextPath tokenContextPath, String tokenImage) { 144 return formatWriter.insertToken(beforeToken, 145 tokenID, tokenContextPath, tokenImage); 146 } 147 148 public void insertSpaces(TokenItem beforeToken, int spaceCount) { 149 TokenID whitespaceTokenID = getWhitespaceTokenID(); 150 if (whitespaceTokenID == null) { 151 throw new IllegalStateException ("Valid whitespace token-id required."); } 153 154 insertToken(beforeToken, whitespaceTokenID, null, 155 new String (Analyzer.getSpacesBuffer(spaceCount), 0, spaceCount)); 156 } 157 158 162 public boolean canRemoveToken(TokenItem token) { 163 return formatWriter.canRemoveToken(token); 164 } 165 166 171 public void removeToken(TokenItem token) { 172 formatWriter.removeToken(token); 173 } 174 175 176 public void removeTokenChain(TokenItem startToken, TokenItem endToken) { 177 while (startToken != null && startToken != endToken) { 178 TokenItem t = startToken.getNext(); 179 removeToken(startToken); 180 startToken = t; 181 } 182 } 183 184 public TokenItem splitStart(TokenItem token, int startLength, 185 TokenID newTokenID, TokenContextPath newTokenContextPath) { 186 return formatWriter.splitStart(token, startLength, newTokenID, newTokenContextPath); 187 } 188 189 public TokenItem splitEnd(TokenItem token, int endLength, 190 TokenID newTokenID, TokenContextPath newTokenContextPath) { 191 return formatWriter.splitEnd(token, endLength, newTokenID, newTokenContextPath); 192 } 193 194 public void insertString(TokenItem token, int offset, String text) { 195 formatWriter.insertString(token, offset, text); 196 } 197 198 public void insertString(FormatTokenPosition pos, String text) { 199 TokenItem token = pos.getToken(); 200 int offset = pos.getOffset(); 201 202 if (token == null) { token = getLastToken(); 204 if (token == null) { 205 throw new IllegalStateException ("Cannot insert string. No tokens."); } 207 offset = token.getImage().length(); 208 } 209 210 insertString(token, offset, text); 211 } 212 213 public void remove(TokenItem token, int offset, int length) { 214 formatWriter.remove(token, offset, length); 215 } 216 217 public void remove(FormatTokenPosition pos, int length) { 218 remove(pos.getToken(), pos.getOffset(), length); 219 } 220 221 226 public TokenItem findNonEmptyToken(TokenItem token, boolean backward) { 227 return formatWriter.findNonEmptyToken(token, backward); 228 } 229 230 234 public FormatTokenPosition getPosition(TokenItem token, int offset) { 235 return getPosition(token, offset, Position.Bias.Forward); 236 } 237 238 public FormatTokenPosition getPosition(TokenItem token, int offset, Position.Bias bias) { 239 return formatWriter.getPosition(token, offset, bias); 240 } 241 242 247 public FormatTokenPosition getNextPosition(TokenItem token, int offset, 248 Position.Bias bias) { 249 if (token == null) { return null; 251 252 } else { offset++; 254 255 if (offset >= token.getImage().length()) { 256 token = token.getNext(); 257 offset = 0; 258 } 259 260 return getPosition(token, offset, bias); 261 } 262 } 263 264 269 public FormatTokenPosition getPreviousPosition(TokenItem token, int offset, 270 Position.Bias bias) { 271 FormatTokenPosition ret = null; 272 if (token == null) { TokenItem lastToken = findNonEmptyToken(getLastToken(), true); 274 if (lastToken != null) { ret = getPosition(lastToken, lastToken.getImage().length() - 1, 276 Position.Bias.Forward); 277 } 278 279 } else { offset--; 281 282 if (offset < 0) { 283 token = token.getPrevious(); 284 if (token != null) { ret = getPosition(token, token.getImage().length() - 1, 286 Position.Bias.Forward); 287 } 288 289 } else { ret = getPosition(token, offset, 291 Position.Bias.Forward); 292 } 293 } 294 295 return ret; 296 } 297 298 301 public FormatTokenPosition getPreviousPosition(FormatTokenPosition pos) { 302 return getPreviousPosition(pos.getToken(), 303 pos.getOffset(), pos.getBias()); 304 } 305 306 309 public FormatTokenPosition getPreviousPosition(FormatTokenPosition pos, Position.Bias bias) { 310 return getPreviousPosition(pos.getToken(), pos.getOffset(), bias); 311 } 312 313 public FormatTokenPosition getPreviousPosition(TokenItem token, int offset) { 314 return getPreviousPosition(token, offset, Position.Bias.Forward); 315 } 316 317 320 public FormatTokenPosition getNextPosition(FormatTokenPosition pos) { 321 return getNextPosition(pos.getToken(), 322 pos.getOffset(), pos.getBias()); 323 } 324 325 328 public FormatTokenPosition getNextPosition(FormatTokenPosition pos, Position.Bias bias) { 329 return getNextPosition(pos.getToken(), pos.getOffset(), bias); 330 } 331 332 public FormatTokenPosition getNextPosition(TokenItem token, int offset) { 333 return getNextPosition(token, offset, Position.Bias.Forward); 334 } 335 336 public boolean isAfter(TokenItem testedToken, TokenItem afterToken) { 337 return formatWriter.isAfter(testedToken, afterToken); 338 } 339 340 public boolean isAfter(FormatTokenPosition testedPosition, 341 FormatTokenPosition afterPosition) { 342 return formatWriter.isAfter(testedPosition, afterPosition); 343 } 344 345 public boolean isChainStartPosition(FormatTokenPosition pos) { 346 return formatWriter.isChainStartPosition(pos); 347 } 348 349 352 public boolean canReplaceToken(TokenItem token) { 353 return canRemoveToken(token); 354 } 355 356 362 public void replaceToken(TokenItem originalToken, 363 TokenID tokenID, TokenContextPath tokenContextPath, String tokenImage) { 364 if (!canReplaceToken(originalToken)) { 365 throw new IllegalStateException ("Cannot insert token into chain"); } 367 368 TokenItem next = originalToken.getNext(); 369 removeToken(originalToken); 370 insertToken(next, tokenID, tokenContextPath, tokenImage); 371 } 372 373 374 public boolean isRestartFormat() { 375 return formatWriter.isRestartFormat(); 376 } 377 378 379 public void setRestartFormat(boolean restartFormat) { 380 formatWriter.setRestartFormat(restartFormat); 381 } 382 383 384 public int getIndentShift() { 385 return formatWriter.getIndentShift(); 386 } 387 388 389 public void setIndentShift(int indentShift) { 390 formatWriter.setIndentShift(indentShift); 391 } 392 393 399 public boolean tokenEquals(TokenItem compareToken, TokenID withTokenID) { 400 return tokenEquals(compareToken, withTokenID, null, null); 401 } 402 403 411 public boolean tokenEquals(TokenItem compareToken, TokenID withTokenID, 412 TokenContextPath withTokenContextPath) { 413 return tokenEquals(compareToken, withTokenID, withTokenContextPath, null); 414 } 415 416 428 public boolean tokenEquals(TokenItem compareToken, TokenID withTokenID, 429 TokenContextPath withTokenContextPath, String withTokenImage) { 430 return (withTokenID == null || compareToken.getTokenID() == withTokenID) 431 && (withTokenContextPath == null 432 || compareToken.getTokenContextPath() == withTokenContextPath) 433 && (withTokenImage == null || compareToken.getImage().equals(withTokenImage)); 434 } 435 436 439 public boolean isWhitespace(TokenItem token, int offset) { 440 return Character.isWhitespace(token.getImage().charAt(offset)); 441 } 442 443 public boolean isWhitespace(FormatTokenPosition pos) { 444 return isWhitespace(pos.getToken(), pos.getOffset()); 445 } 446 447 454 public FormatTokenPosition findLineStart(FormatTokenPosition pos) { 455 if (isChainStartPosition(pos)) { return pos; 457 } 458 459 pos = getPreviousPosition(pos); 461 462 TokenItem token = pos.getToken(); 463 int offset = pos.getOffset(); 464 465 while (true) { 466 String text = token.getImage(); 467 while (offset >= 0) { 468 if (text.charAt(offset) == '\n') { 469 return getNextPosition(token, offset); 470 } 471 472 offset--; 473 } 474 475 if (token.getPrevious() == null) { 476 return getPosition(token, 0); 478 } 479 token = token.getPrevious(); 480 offset = token.getImage().length() - 1; 481 } 482 } 483 484 490 public FormatTokenPosition findLineEnd(FormatTokenPosition pos) { 491 TokenItem token = pos.getToken(); 492 int offset = pos.getOffset(); 493 494 if (token == null) { return pos; 496 } 497 498 while (true) { 499 String text = token.getImage(); 500 int textLen = text.length(); 501 while (offset < textLen) { 502 if (text.charAt(offset) == '\n') { 503 return getPosition(token, offset); 504 } 505 506 offset++; 507 } 508 509 if (token.getNext() == null) { 510 return getPosition(null, 0); 512 } 513 514 token = token.getNext(); 515 offset = 0; 516 } 517 } 518 519 522 public FormatTokenPosition findLineFirstNonWhitespace(FormatTokenPosition pos) { 523 pos = findLineStart(pos); 524 TokenItem token = pos.getToken(); 525 int offset = pos.getOffset(); 526 527 if (token == null) { return null; 529 } 530 531 while (true) { 532 String text = token.getImage(); 533 int textLen = text.length(); 534 while (offset < textLen) { 535 if (text.charAt(offset) == '\n') { 536 return null; 537 } 538 539 if (!isWhitespace(token, offset)) { 540 return getPosition(token, offset); 541 } 542 543 offset++; 544 } 545 546 if (token.getNext() == null) { 547 return null; 548 } 549 550 token = token.getNext(); 551 offset = 0; 552 } 553 } 554 555 558 public FormatTokenPosition findLineEndWhitespace(FormatTokenPosition pos) { 559 pos = findLineEnd(pos); 560 if (isChainStartPosition(pos)) { return pos; 562 563 } else { 564 pos = getPreviousPosition(pos); 565 } 566 567 568 TokenItem token = pos.getToken(); 569 int offset = pos.getOffset(); 570 while (true) { 571 String text = token.getImage(); 572 int textLen = text.length(); 573 while (offset >= 0) { 574 if (offset < textLen 575 && ((text.charAt(offset) == '\n') || !isWhitespace(token, offset)) 576 ) { 577 return getNextPosition(token, offset); 578 } 579 580 581 offset--; 582 } 583 584 if (token.getPrevious() == null) { 585 return getPosition(token, 0); 587 } 588 589 token = token.getPrevious(); 590 offset = token.getImage().length() - 1; 591 } 592 } 593 594 599 public FormatTokenPosition findPreviousEOL(FormatTokenPosition pos) { 600 pos = getPreviousPosition(pos); 601 if (pos == null) { return null; 603 } 604 605 TokenItem token = pos.getToken(); 606 int offset = pos.getOffset(); 607 608 while (true) { 609 String text = token.getImage(); 610 while (offset >= 0) { 611 if (text.charAt(offset) == '\n') { 612 return getPosition(token, offset); 613 } 614 615 offset--; 616 } 617 618 if (token.getPrevious() == null) { 619 return null; 620 } 621 622 token = token.getPrevious(); 623 offset = token.getImage().length() - 1; 624 } 625 } 626 627 633 public FormatTokenPosition findNextEOL(FormatTokenPosition pos) { 634 pos = getNextPosition(pos); 635 if (pos == null) { 636 return null; 637 } 638 639 TokenItem token = pos.getToken(); 640 int offset = pos.getOffset(); 641 642 if (token == null) { return null; 644 } 645 646 while (true) { 647 String text = token.getImage(); 648 int textLen = text.length(); 649 while (offset < textLen) { 650 if (text.charAt(offset) == '\n') { 651 return getPosition(token, offset); 652 } 653 654 offset++; 655 } 656 657 if (token.getNext() == null) { 658 return null; 659 } 660 661 token = token.getNext(); 662 offset = 0; 663 } 664 } 665 666 670 public boolean isLineEmpty(FormatTokenPosition pos) { 671 return findLineStart(pos).equals(findLineEnd(pos)); 672 } 673 674 678 public boolean isLineWhite(FormatTokenPosition pos) { 679 FormatTokenPosition lineStart = findLineStart(pos); 680 return findLineEndWhitespace(pos).equals(lineStart); 681 } 682 683 684 687 public int getVisualColumnOffset(FormatTokenPosition pos) { 688 TokenItem targetToken = pos.getToken(); 689 int targetOffset = pos.getOffset(); 690 691 FormatTokenPosition lineStart = findLineStart(pos); 692 TokenItem token = lineStart.getToken(); 693 int offset = lineStart.getOffset(); 694 695 int col = 0; 696 int tabSize = formatWriter.getFormatter().getTabSize(); 697 698 while (token != null) { 699 String text = token.getImage(); 700 int textLen = text.length(); 701 while (offset < textLen) { 702 if (token == targetToken && offset == targetOffset) { 703 return col; 704 } 705 706 switch (text.charAt(offset)) { 707 case '\t': 708 col = (col + tabSize) / tabSize * tabSize; 709 break; 710 default: 711 col++; 712 } 713 714 offset++; 715 } 716 717 token = token.getNext(); 718 offset = 0; 719 } 720 721 return col; 722 } 723 724 740 public FormatTokenPosition findNonWhitespace(FormatTokenPosition startPosition, 741 FormatTokenPosition limitPosition, boolean stopOnEOL, boolean backward) { 742 743 if (startPosition.equals(limitPosition)) { 745 return null; 746 } 747 748 if (backward) { TokenItem limitToken; 750 int limitOffset; 751 752 if (limitPosition == null) { 753 limitToken = null; 754 limitOffset = 0; 755 756 } else { limitPosition = getPreviousPosition(limitPosition); 758 if (limitPosition == null) { 759 limitToken = null; 760 limitOffset = 0; 761 762 } else { limitToken = limitPosition.getToken(); 764 limitOffset = limitPosition.getOffset(); 765 } 766 } 767 768 startPosition = getPreviousPosition(startPosition); 769 if (startPosition == null) { 770 return null; 771 } 772 773 TokenItem token = startPosition.getToken(); 774 int offset = startPosition.getOffset(); 775 776 while (true) { 777 String text = token.getImage(); 778 while (offset >= 0) { 779 if (stopOnEOL && text.charAt(offset) == '\n') { 780 return null; 781 } 782 783 if (!isWhitespace(token, offset)) { 784 return getPosition(token, offset); 785 } 786 787 if (token == limitToken && offset == limitOffset) { 788 return null; 789 } 790 791 offset--; 792 } 793 794 token = token.getPrevious(); 795 if (token == null) { 796 return null; 797 } 798 offset = token.getImage().length() - 1; 799 } 800 801 } else { TokenItem limitToken; 803 int limitOffset; 804 805 if (limitPosition == null) { 806 limitToken = null; 807 limitOffset = 0; 808 809 } else { limitToken = limitPosition.getToken(); 811 limitOffset = limitPosition.getOffset(); 812 } 813 814 TokenItem token = startPosition.getToken(); 815 int offset = startPosition.getOffset(); 816 817 while (true) { 818 String text = token.getImage(); 819 int textLen = text.length(); 820 while (offset < textLen) { 821 if (token == limitToken && offset == limitOffset) { 822 return null; 823 } 824 825 if (stopOnEOL && text.charAt(offset) == '\n') { 826 return null; 827 } 828 829 if (!isWhitespace(token, offset)) { 830 return getPosition(token, offset); 831 } 832 833 offset++; 834 } 835 836 token = token.getNext(); 837 if (token == null) { 838 return null; 839 } 840 offset = 0; 841 } 842 } 843 } 844 845 846 public TokenItem getPreviousToken(TokenItem token) { 847 return (token == null) ? getLastToken() : token.getPrevious(); 848 } 849 850 854 public TokenID getWhitespaceTokenID() { 855 return null; 856 } 857 858 861 public TokenID getValidWhitespaceTokenID() { 862 TokenID wsID = getWhitespaceTokenID(); 863 if (wsID == null) { 864 throw new IllegalStateException ("Null whitespace token-id"); } 866 return wsID; 867 } 868 869 873 public TokenContextPath getWhitespaceTokenContextPath() { 874 return null; 875 } 876 877 881 public TokenContextPath getValidWhitespaceTokenContextPath() { 882 TokenContextPath wsTCP = getWhitespaceTokenContextPath(); 883 if (wsTCP == null) { 884 throw new IllegalStateException ("Null whitespace token-context-path"); } 886 return wsTCP; 887 } 888 889 893 public boolean canModifyWhitespace(TokenItem inToken) { 894 return false; 895 } 896 897 898 public String getIndentString(int indent) { 899 return formatWriter.getFormatter().getIndentString(indent); 900 } 901 902 910 public int getLineIndent(FormatTokenPosition pos, boolean zeroForWSLine) { 911 FormatTokenPosition firstNWS = findLineFirstNonWhitespace(pos); 912 if (firstNWS == null) { if (zeroForWSLine) { 914 return 0; 915 916 } else { firstNWS = findLineEnd(pos); 918 } 919 } 920 921 return getVisualColumnOffset(firstNWS); 922 } 923 924 932 public FormatTokenPosition changeLineIndent(FormatTokenPosition pos, int indent) { 933 pos = findLineStart(pos); String indentString = getIndentString(indent); 935 int indentStringLen = indentString.length(); 936 int indentStringInd = 0; TokenItem token = pos.getToken(); 938 int offset = pos.getOffset(); 939 940 if (token == null) { if (indentString.length() > 0) { 942 token = insertToken(null, getValidWhitespaceTokenID(), 943 getValidWhitespaceTokenContextPath(), indentString); 944 } 945 return pos; } 947 948 949 while (true) { 950 951 String text = token.getImage(); 952 int textLen = text.length(); 953 954 while (indentStringInd < indentStringLen && offset < textLen) { 955 if (indentString.charAt(indentStringInd) != text.charAt(offset)) { 956 if (canModifyWhitespace(token)) { 957 insertString(token, offset, indentString.substring(indentStringInd)); 959 offset += indentStringLen - indentStringInd; indentStringInd = indentStringLen; 961 962 } else { if (isWhitespace(token, offset) || offset > 0) { 964 throw new IllegalStateException ( 965 "Cannot modify token=" + token); 967 } else { insertToken(token, getValidWhitespaceTokenID(), 969 getValidWhitespaceTokenContextPath(), 970 indentString.substring(indentStringInd) 971 ); 972 return getPosition(token, 0); 973 } 974 } 975 976 } else { indentStringInd++; offset++; 979 } 980 } 981 982 if (indentStringInd < indentStringLen) { token = token.getNext(); 984 if (token == null) { token = insertToken(null, getValidWhitespaceTokenID(), 986 getValidWhitespaceTokenContextPath(), 987 indentString.substring(indentStringInd) 988 ); 989 return getPosition(token, 0); 990 991 } else { offset = 0; 993 } 994 995 } else { 997 while (true) { 998 text = token.getImage(); 999 textLen = text.length(); 1000 int removeInd = -1; 1001 1002 while (offset < textLen) { 1003 if (!isWhitespace(token, offset) || text.charAt(offset) == '\n') { 1004 if (removeInd >= 0) { 1005 remove(token, removeInd, offset - removeInd); 1006 offset = removeInd; 1007 } 1008 1009 return getPosition(token, offset); 1010 1011 } else { if (removeInd < 0) { 1013 removeInd = offset; 1014 } 1015 } 1016 offset++; 1017 } 1018 1019 if (removeInd == -1) { token = token.getNext(); 1022 } else if (removeInd == 0) { TokenItem nextToken = token.getNext(); 1024 removeToken(token); 1025 token = nextToken; 1026 1027 } else { remove(token, removeInd, textLen - removeInd); 1029 token = token.getNext(); 1030 } 1031 offset = 0; 1032 1033 if (token == null) { 1034 return getPosition(null, 0); 1035 } 1036 } 1037 } 1038 } 1039 } 1040 1041 1044 public String chainToString(TokenItem token) { 1045 return formatWriter.chainToString(token); 1046 } 1047 1048 public String chainToString(TokenItem token, int maxDocumentTokens) { 1049 return formatWriter.chainToString(token, maxDocumentTokens); 1050 } 1051 1052} 1053 | Popular Tags |