001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.cnd.editor.fortran;
043:
044: import org.netbeans.editor.TokenID;
045: import org.netbeans.editor.TokenItem;
046: import org.netbeans.editor.TokenContextPath;
047: import org.netbeans.editor.BaseImageTokenID;
048: import org.netbeans.editor.BaseDocument;
049: import org.netbeans.editor.ext.FormatTokenPosition;
050: import org.netbeans.editor.ext.ExtFormatSupport;
051: import org.netbeans.editor.ext.FormatWriter;
052:
053: /**
054: * Fortran indentation services are located here
055: *
056: * duped from editor/libsrc/org/netbeans/editor/ext/java/JavaFormatSupport.java
057: */
058:
059: public class FFormatSupport extends ExtFormatSupport {
060:
061: private TokenContextPath tokenContextPath;
062:
063: public FFormatSupport(FormatWriter formatWriter) {
064: this (formatWriter, FTokenContext.contextPath);
065: }
066:
067: public FFormatSupport(FormatWriter formatWriter,
068: TokenContextPath tokenContextPath) {
069: super (formatWriter);
070: this .tokenContextPath = tokenContextPath;
071: }
072:
073: public TokenContextPath getTokenContextPath() {
074: return tokenContextPath;
075: }
076:
077: public boolean isComment(TokenItem token, int offset) {
078: TokenID tokenID = token.getTokenID();
079: return (token.getTokenContextPath() == tokenContextPath && (tokenID == FTokenContext.LINE_COMMENT));
080: }
081:
082: /** Determine if the given token is a "Free Format" Fortran comment.
083: */
084: public boolean isFreeFormatComment(TokenItem token) {
085: return token != null && token.getImage().startsWith("!"); // NOI18N
086: }
087:
088: /** Determine if the given token is a "Fixed Format" Fortran comment.
089: */
090: public boolean isFixedFormatComment(TokenItem token) {
091: return token != null
092: && (token.getImage().startsWith("C") || token
093: .getImage().startsWith("c")) && // NOI18N
094: getTokenIndent(token) == 0 && !getFreeFormat();
095: }
096:
097: public boolean isPreprocessor(TokenItem token) {
098: return token != null && token.getImage().startsWith("#") && // NOI18N
099: getVisualColumnOffset(getPosition(token, 0)) == 0;
100: }
101:
102: public boolean isFixedFormatLabel(TokenItem token) {
103: if (token != null
104: && token.getTokenID() == FTokenContext.NUM_LITERAL_INT
105: && !getFreeFormat()) {
106: FormatTokenPosition tp = getPosition(token, 0);
107: if ((getVisualColumnOffset(tp) + token.getImage().length()) <= 5)
108: return true;
109: }
110: return false;
111: }
112:
113: public boolean isFixedFormatLineContinuation(TokenItem token) {
114: return token != null
115: && (token.getTokenID() == FTokenContext.OP_PLUS || token
116: .getTokenID() == FTokenContext.OP_MINUS)
117: && !getFreeFormat()
118: && getVisualColumnOffset(getPosition(token, 0)) == 5;
119: }
120:
121: public TokenID getWhitespaceTokenID() {
122: return FTokenContext.WHITESPACE;
123: }
124:
125: public TokenContextPath getWhitespaceTokenContextPath() {
126: return tokenContextPath;
127: }
128:
129: public boolean canModifyWhitespace(TokenItem inToken) {
130: if (inToken.getTokenContextPath() == FTokenContext.contextPath) {
131: switch (inToken.getTokenID().getNumericID()) {
132: case FTokenContext.WHITESPACE_ID:
133: return true;
134: }
135: }
136: return false;
137: }
138:
139: /** Find the starting token in the line of code, given a particular token
140: * @param token the starting point token
141: * @return token the token at the start of the line of code
142: */
143: public TokenItem findLineStartToken(TokenItem token) {
144: if (token != null) {
145: FormatTokenPosition pos = getPosition(token, 0);
146: pos = findLineStart(pos);
147: token = pos.getToken();
148: while (token.getTokenID() == FTokenContext.WHITESPACE)
149: token = token.getNext();
150: }
151: return token;
152: }
153:
154: /** Determine if this if statement is a single line if statement or
155: * if it is a multiline if statement. A multiline if statement will
156: * always end with the "then" keyword.
157: * @param startToken the starting token for this line of code
158: * @return true if this is a multiline if statement.
159: */
160: public boolean isIfThenStatement(TokenItem startToken) {
161: FormatTokenPosition pos = getPosition(startToken, 0);
162: pos = findLineEnd(pos);
163: TokenItem lastToken = pos.getToken();
164: lastToken = lastToken.getPrevious();
165: while (lastToken.getTokenID() == FTokenContext.WHITESPACE) {
166: lastToken = lastToken.getPrevious();
167: }
168: if (lastToken.getTokenID() == FTokenContext.KW_THEN) {
169: return true;
170: }
171: return false;
172: }
173:
174: /** Find the matching token for the supplied token. This will always
175: * do a backward search.
176: * @param token - the token that ends the block of code, ie,
177: * "endselect", "end", "enddo", etc.
178: * @param matchTokenID - the token numeric ID that you are trying to match,
179: * ie, KW_SELECT_ID if you are trying to match the "select" token
180: * @param matchEndKeywordID - the token numeric ID of an "end..." token,
181: * ie, KW_ENDSELECT_ID if you are trying to match the "endselect" token
182: * @return corresponding token that begins the block
183: */
184: public TokenItem findMatchingToken(TokenItem token,
185: int matchTokenID, int matchEndKeywordID) {
186: int depth = 0; // depth of multiple "end select" stmts
187: TokenItem startToken;
188: while (true) {
189: TokenItem impToken = findImportantToken(token, null, true);
190: startToken = token = findLineStartToken(impToken);
191: if (token == null) {
192: return null;
193: }
194: if (isFixedFormatLabel(startToken)) {
195: // in fixed format: labels are not treated as start tokens
196: // line cont.can be ignored because a starting matchToken
197: // will not be found on a continuated line.
198: do {
199: startToken = startToken.getNext();
200: } while (startToken.getTokenID() == FTokenContext.WHITESPACE);
201: }
202: int tokenNumericID = startToken.getTokenID().getNumericID();
203: if (tokenNumericID == FTokenContext.KW_END_ID) {
204:
205: // is this "end" token is really an "end..." token then
206: TokenItem tokenAfterEnd = startToken.getNext();
207: while (tokenAfterEnd.getTokenID() == FTokenContext.WHITESPACE)
208: tokenAfterEnd = tokenAfterEnd.getNext();
209: if (tokenAfterEnd == null)
210: return null;
211:
212: if (tokenAfterEnd.getTokenID().getNumericID() == matchTokenID)
213: depth++;
214:
215: } else if (tokenNumericID == matchEndKeywordID) {
216: depth++;
217:
218: } else if (tokenNumericID == matchTokenID) {
219: if (matchTokenID == FTokenContext.KW_IF_ID
220: && matchEndKeywordID == FTokenContext.KW_ENDIF_ID) {
221: // there must be a 'THEN' on this line to be a valid 'IF' match
222: TokenItem nextToken = startToken;
223: do {
224: nextToken = nextToken.getNext();
225: if (nextToken == null)
226: return null;
227: if (nextToken.getImage().indexOf('\n') > -1) {
228: // break, unless the next line is a continuation
229: TokenItem t = nextToken.getNext();
230: if (!isFixedFormatLineContinuation(findLineStartToken(t)))
231: break;
232: }
233: } while (nextToken.getTokenID() != FTokenContext.KW_THEN);
234: if (nextToken.getImage().indexOf('\n') > -1)
235: continue;
236: }
237: if (depth-- == 0) {
238: return token; // successful search
239: }
240: }
241: }// end while
242: }// end findMatchingToken()
243:
244: /** Get the indentation for the given token.
245: * @param token token for which the indent is being searched.
246: * The token itself is ignored and the previous token
247: * is used as a base for the search.
248: */
249: public int getTokenIndent(TokenItem token) {
250:
251: FormatTokenPosition tp = getPosition(token, 0);
252: FormatTokenPosition fnw = findLineFirstNonWhitespace(tp);
253:
254: if (fnw != null) { // valid first non-whitespace
255: TokenItem t = fnw.getToken();
256: if (isFixedFormatLabel(t)
257: || isFixedFormatLineContinuation(t)) {
258: do {
259: t = t.getNext();
260: } while (t != null
261: && t.getTokenID() == getWhitespaceTokenID());
262: fnw = (t == null && t.getImage().length() > 0) ? null
263: : getPosition(t, 0);
264: }
265: if (fnw != null)
266: tp = fnw;
267: }
268: return getVisualColumnOffset(tp);
269: }
270:
271: /** Find the indentation for the first token on the line.
272: * The given token is also examined in some cases.
273: */
274: public int findIndent(TokenItem token) {
275: int indent = -1; // assign invalid indent
276: // First check the given token
277: if (token == null)
278: return 0;
279: TokenItem nextToken;
280: TokenItem matchToken = null;
281: switch (token.getTokenID().getNumericID()) {
282:
283: case FTokenContext.KW_CASE_ID:
284: case FTokenContext.KW_DEFAULT_ID:
285: matchToken = findMatchingToken(token,
286: FTokenContext.KW_SELECT_ID,
287: FTokenContext.KW_ENDSELECT_ID);
288: if (matchToken != null) {
289: indent = getTokenIndent(matchToken) + getShiftWidth();
290: }
291: break;
292:
293: case FTokenContext.KW_PROGRAM_ID:
294: case FTokenContext.KW_ENDPROGRAM_ID:
295: indent = 0;
296: break;
297:
298: case FTokenContext.KW_END_ID:
299: // usually the next token after an "END" token is
300: // the type of block this is.
301: TokenItem lookupToken = null;
302: nextToken = token.getNext();
303: if (nextToken == null) {
304: if (getFreeFormat())
305: indent = 0;
306: else
307: indent = 6;
308: break;
309: }
310: if (nextToken.getTokenID() == FTokenContext.WHITESPACE) {
311: nextToken = nextToken.getNext();
312: }
313: if (nextToken == null) {
314: indent = 0;
315: break;
316: }
317: if (nextToken.getImage().compareTo(BaseDocument.LS_LF) == 0) {
318: // We're at the end of the program
319: indent = 0;
320: } else {
321: // We're at a two word end statement,ie, end if
322: switch (nextToken.getTokenID().getNumericID()) {
323: case FTokenContext.KW_IF_ID:
324: case FTokenContext.KW_ELSE_ID:
325: matchToken = findMatchingToken(token,
326: FTokenContext.KW_IF_ID,
327: FTokenContext.KW_ENDIF_ID);
328: break;
329:
330: case FTokenContext.KW_BLOCK_ID:
331: matchToken = findMatchingToken(token,
332: FTokenContext.KW_BLOCK_ID,
333: FTokenContext.KW_ENDBLOCK_ID);
334: break;
335:
336: case FTokenContext.KW_BLOCKDATA_ID:
337: matchToken = findMatchingToken(token,
338: FTokenContext.KW_BLOCKDATA_ID,
339: FTokenContext.KW_ENDBLOCKDATA_ID);
340: break;
341:
342: case FTokenContext.KW_DO_ID:
343: matchToken = findMatchingToken(token,
344: FTokenContext.KW_DO_ID,
345: FTokenContext.KW_ENDDO_ID);
346: break;
347:
348: case FTokenContext.KW_FORALL_ID:
349: matchToken = findMatchingToken(token,
350: FTokenContext.KW_FORALL_ID,
351: FTokenContext.KW_ENDFORALL_ID);
352: break;
353:
354: case FTokenContext.KW_FUNCTION_ID:
355: matchToken = findMatchingToken(token,
356: FTokenContext.KW_FUNCTION_ID,
357: FTokenContext.KW_ENDFUNCTION_ID);
358: break;
359:
360: case FTokenContext.KW_INTERFACE_ID:
361: matchToken = findMatchingToken(token,
362: FTokenContext.KW_INTERFACE_ID,
363: FTokenContext.KW_ENDINTERFACE_ID);
364: break;
365:
366: case FTokenContext.KW_MAP_ID:
367: matchToken = findMatchingToken(token,
368: FTokenContext.KW_MAP_ID,
369: FTokenContext.KW_ENDMAP_ID);
370: break;
371:
372: case FTokenContext.KW_MODULE_ID:
373: matchToken = findMatchingToken(token,
374: FTokenContext.KW_MODULE_ID,
375: FTokenContext.KW_ENDMODULE_ID);
376: break;
377:
378: case FTokenContext.KW_SELECT_ID:
379: matchToken = findMatchingToken(token,
380: FTokenContext.KW_SELECT_ID,
381: FTokenContext.KW_ENDSELECT_ID);
382: break;
383:
384: case FTokenContext.KW_STRUCTURE_ID:
385: matchToken = findMatchingToken(token,
386: FTokenContext.KW_STRUCTURE_ID,
387: FTokenContext.KW_ENDSTRUCTURE_ID);
388: break;
389:
390: case FTokenContext.KW_ENDSUBROUTINE_ID:
391: matchToken = findMatchingToken(token,
392: FTokenContext.KW_SUBROUTINE_ID,
393: FTokenContext.KW_ENDSUBROUTINE_ID);
394: break;
395:
396: case FTokenContext.KW_TYPE_ID:
397: matchToken = findMatchingToken(token,
398: FTokenContext.KW_TYPE_ID,
399: FTokenContext.KW_ENDTYPE_ID);
400: break;
401:
402: case FTokenContext.KW_UNION_ID:
403: matchToken = findMatchingToken(token,
404: FTokenContext.KW_UNION_ID,
405: FTokenContext.KW_ENDUNION_ID);
406: break;
407:
408: case FTokenContext.KW_WHERE_ID:
409: matchToken = findMatchingToken(token,
410: FTokenContext.KW_WHERE_ID,
411: FTokenContext.KW_ENDWHERE_ID);
412: break;
413: }// END SWITCH
414: if (matchToken != null) {
415: indent = getTokenIndent(matchToken);
416: }
417: }//end else
418: break;
419:
420: default:
421: switch (token.getTokenID().getNumericID()) {
422: case FTokenContext.KW_ELSE_ID:
423: case FTokenContext.KW_ELSEIF_ID:
424: case FTokenContext.KW_ENDIF_ID:
425: matchToken = findMatchingToken(token,
426: FTokenContext.KW_IF_ID,
427: FTokenContext.KW_ENDIF_ID);
428: break;
429:
430: case FTokenContext.KW_ENDBLOCK_ID:
431: matchToken = findMatchingToken(token,
432: FTokenContext.KW_BLOCK_ID,
433: FTokenContext.KW_ENDBLOCK_ID);
434: break;
435:
436: case FTokenContext.KW_ENDBLOCKDATA_ID:
437: matchToken = findMatchingToken(token,
438: FTokenContext.KW_BLOCKDATA_ID,
439: FTokenContext.KW_ENDBLOCKDATA_ID);
440: break;
441:
442: case FTokenContext.KW_ENDDO_ID:
443: matchToken = findMatchingToken(token,
444: FTokenContext.KW_DO_ID,
445: FTokenContext.KW_ENDDO_ID);
446: break;
447:
448: case FTokenContext.KW_ENDFORALL_ID:
449: matchToken = findMatchingToken(token,
450: FTokenContext.KW_FORALL_ID,
451: FTokenContext.KW_ENDFORALL_ID);
452: break;
453:
454: case FTokenContext.KW_ENDFUNCTION_ID:
455: matchToken = findMatchingToken(token,
456: FTokenContext.KW_FUNCTION_ID,
457: FTokenContext.KW_ENDFUNCTION_ID);
458: break;
459:
460: case FTokenContext.KW_ENDINTERFACE_ID:
461: matchToken = findMatchingToken(token,
462: FTokenContext.KW_INTERFACE_ID,
463: FTokenContext.KW_ENDINTERFACE_ID);
464: break;
465:
466: case FTokenContext.KW_ENDMAP_ID:
467: matchToken = findMatchingToken(token,
468: FTokenContext.KW_MAP_ID,
469: FTokenContext.KW_ENDMAP_ID);
470: break;
471:
472: case FTokenContext.KW_ENDMODULE_ID:
473: matchToken = findMatchingToken(token,
474: FTokenContext.KW_MODULE_ID,
475: FTokenContext.KW_ENDMODULE_ID);
476: break;
477:
478: case FTokenContext.KW_ENDSELECT_ID:
479: matchToken = findMatchingToken(token,
480: FTokenContext.KW_SELECT_ID,
481: FTokenContext.KW_ENDSELECT_ID);
482: break;
483:
484: case FTokenContext.KW_ENDSTRUCTURE_ID:
485: matchToken = findMatchingToken(token,
486: FTokenContext.KW_STRUCTURE_ID,
487: FTokenContext.KW_ENDSTRUCTURE_ID);
488: break;
489:
490: case FTokenContext.KW_ENDSUBROUTINE_ID:
491: matchToken = findMatchingToken(token,
492: FTokenContext.KW_SUBROUTINE_ID,
493: FTokenContext.KW_ENDSUBROUTINE_ID);
494: break;
495:
496: case FTokenContext.KW_ENDTYPE_ID:
497: matchToken = findMatchingToken(token,
498: FTokenContext.KW_TYPE_ID,
499: FTokenContext.KW_ENDTYPE_ID);
500: break;
501:
502: case FTokenContext.KW_ENDUNION_ID:
503: matchToken = findMatchingToken(token,
504: FTokenContext.KW_UNION_ID,
505: FTokenContext.KW_ENDUNION_ID);
506: break;
507:
508: case FTokenContext.KW_ENDWHERE_ID:
509: case FTokenContext.KW_ELSEWHERE_ID:
510: matchToken = findMatchingToken(token,
511: FTokenContext.KW_WHERE_ID,
512: FTokenContext.KW_ENDWHERE_ID);
513: break;
514: }//end second switch
515: if (matchToken != null) {
516: indent = getTokenIndent(matchToken);
517: }
518: break; //end default case
519: }//end first switch
520: //}//end if
521:
522: // If indent not found, search back for the first important token
523: if (indent < 0) { // if not yet resolved
524: if (token == null)
525: return 0;
526: //TokenItem matchToken;
527: TokenItem impToken = findImportantToken(token, null, true);
528: TokenItem startToken = findLineStartToken(impToken);
529: // in fixed format: line cont. and preprocessors are not treated as important tokens
530: if (startToken == null)
531: return 0;
532: while (isFixedFormatLineContinuation(startToken)
533: || isPreprocessor(startToken)
534: || startToken.getTokenID() == FTokenContext.KW_ENTRY) {
535: impToken = findImportantToken(startToken, null, true);
536: startToken = findLineStartToken(impToken);
537: if (startToken == null)
538: return 0;
539: }
540: if (impToken != null) { // valid important token
541: // in fixed format: labels are not treated as start tokens
542: while (isFixedFormatLabel(startToken)
543: || startToken.getTokenID() == FTokenContext.WHITESPACE) {
544: startToken = startToken.getNext();
545: if (startToken == null)
546: return 0;
547: }
548: //startToken = findLineStartToken(impToken);
549: switch (startToken.getTokenID().getNumericID()) {
550:
551: case FTokenContext.KW_DO_ID:
552: if (!getFreeFormat()) {
553: // DO ITERATOR or DO LABEL
554: TokenItem nexToken = startToken.getNext();
555: while (nexToken.getTokenID() == FTokenContext.WHITESPACE) {
556: nexToken = nexToken.getNext();
557: }
558: if (nexToken.getTokenID() == FTokenContext.NUM_LITERAL_INT) {
559: // Don't indent inside DO-LABEL for now
560: indent = getTokenIndent(startToken);
561: break;
562: }
563: }
564: indent = getTokenIndent(startToken)
565: + getShiftWidth();
566: break;
567:
568: case FTokenContext.KW_ELSE_ID:
569: case FTokenContext.KW_CASE_ID:
570: case FTokenContext.KW_WHERE_ID:
571: case FTokenContext.KW_ELSEWHERE_ID:
572: case FTokenContext.KW_BLOCK_ID:
573: case FTokenContext.KW_BLOCKDATA_ID:
574: case FTokenContext.KW_SELECT_ID:
575: case FTokenContext.KW_SELECTCASE_ID:
576: case FTokenContext.KW_PROGRAM_ID:
577: case FTokenContext.KW_SUBROUTINE_ID:
578: case FTokenContext.KW_STRUCTURE_ID:
579: case FTokenContext.KW_INTERFACE_ID:
580: case FTokenContext.KW_FUNCTION_ID:
581: case FTokenContext.KW_MODULE_ID:
582: case FTokenContext.KW_UNION_ID:
583: case FTokenContext.KW_TYPE_ID:
584: case FTokenContext.KW_MAP_ID:
585: indent = getTokenIndent(startToken)
586: + getShiftWidth();
587: break;
588:
589: case FTokenContext.KW_IF_ID:
590: case FTokenContext.KW_ELSEIF_ID:
591: if (isIfThenStatement(startToken)) {
592: indent = getTokenIndent(startToken)
593: + getShiftWidth();
594: } else {
595: indent = getTokenIndent(startToken);
596: }
597: break;
598:
599: default:
600: indent = getTokenIndent(startToken);
601: break;
602: }
603:
604: if (indent < 0) { // no indent found yet
605: indent = getTokenIndent(impToken);
606: }
607: } // end if (impToken != null)
608: }
609:
610: if (indent < 0) { // no important token found
611: indent = 0;
612: }
613: return indent;
614: }
615:
616: /** Determines how many characters the token (after a fixed token)
617: * needs to be indented.
618: * The indentation is hence done with spaces NOT tabs.
619: **/
620: public int findInlineSpacing(TokenItem token) {
621: // fill if short fixed format Label
622: int additionalIndent = 0;
623: TokenItem startToken = findLineStartToken(token);
624: if (isFixedFormatLabel(startToken)) {
625: additionalIndent = 4 - token.getImage().length();
626: startToken = startToken.getNext();
627: }
628:
629: // Search backwards ...
630: TokenItem indentToken = findImportantToken(token, null, true);
631: startToken = findLineStartToken(indentToken);
632: // in fixed format: line cont. and preprocessors are not treated as important tokens
633: while (isFixedFormatLineContinuation(startToken)
634: || isPreprocessor(startToken)
635: || startToken.getTokenID() == FTokenContext.KW_ENTRY) {
636: indentToken = findImportantToken(startToken, null, true);
637: startToken = findLineStartToken(indentToken);
638: }
639:
640: // ignore whitespace && fixed format labels
641: while (isFixedFormatLabel(startToken)
642: || startToken.getTokenID() == FTokenContext.WHITESPACE) {
643: startToken = startToken.getNext();
644: }
645:
646: // check for END Tokens
647: while (isFixedFormatLineContinuation(token)
648: || isFixedFormatLabel(token)
649: || token.getTokenID() == FTokenContext.WHITESPACE) {
650: token = token.getNext();
651: }
652: if (token.getTokenID() == FTokenContext.KW_SUBROUTINE
653: || token.getTokenID() == FTokenContext.KW_ENTRY
654: || token.getTokenID() == FTokenContext.KW_FUNCTION)
655: return 6;
656:
657: // although this is cheap and [PENDING] improvement
658: // it was the quickest way without some re-engineering of this class :(
659: if ((token.getImage().length() > 2 && token.getImage()
660: .substring(0, 3).equalsIgnoreCase("end")) //NOI18N
661: || token.getTokenID() == FTokenContext.KW_ELSE
662: || token.getTokenID() == FTokenContext.KW_ELSEIF)
663: additionalIndent -= getShiftWidth();
664:
665: FormatTokenPosition tp1 = getPosition(startToken, 0);
666: return Math.max(6, getVisualColumnOffset(tp1)
667: + additionalIndent);
668: }
669:
670: public FormatTokenPosition indentLine(FormatTokenPosition pos) {
671: int indent = 0; // Desired indent
672:
673: // Get the first non-whitespace position on the line
674: FormatTokenPosition firstNWS = findLineFirstNonWhitespace(pos);
675: if (firstNWS != null) { // some non-WS on the line
676:
677: if (isFixedFormatComment(firstNWS.getToken())
678: || isPreprocessor(firstNWS.getToken())) {//&& getChar(getPreviousPosition(pos)) == '\n' ) {
679: // leave indent at 0
680: } else if (isFreeFormatComment(firstNWS.getToken())) {
681: // comment is first on the line
682: // this will do for now XXX
683: indent = findIndent(firstNWS.getToken());
684:
685: } else if (isFixedFormatLabel(firstNWS.getToken())) { // fixed format label
686: // indent after label token
687: TokenItem nexToken = firstNWS.getToken().getNext();
688: // remove spaces
689: while (nexToken.getTokenID() == getWhitespaceTokenID()) {
690: TokenItem nt = nexToken.getNext();
691: removeToken(nexToken);
692: nexToken = nt;
693: }
694: indent = findInlineSpacing(firstNWS.getToken());
695: // add spaces
696: for (int i = 0; i < indent - 5; ++i)
697: insertToken(nexToken, getValidWhitespaceTokenID(),
698: getValidWhitespaceTokenContextPath(), " "); // NOI18N
699: // the line's real indent
700: indent = 1;
701:
702: } else if (isFixedFormatLineContinuation(firstNWS
703: .getToken())) { // fixed format line continuation
704: // indent after line cont. token
705: TokenItem nexToken = firstNWS.getToken().getNext();
706: // remove spaces
707: while (nexToken.getTokenID() == getWhitespaceTokenID()) {
708: TokenItem nt = nexToken.getNext();
709: removeToken(nexToken);
710: nexToken = nt;
711: }
712: indent = findInlineSpacing(firstNWS.getToken());
713: // add spaces
714: for (int i = 0; i < indent - 5; ++i)
715: insertToken(nexToken, getValidWhitespaceTokenID(),
716: getValidWhitespaceTokenContextPath(), " "); // NOI18N
717: // the line's real indent
718: indent = 5;
719:
720: } else if (!getFreeFormat() // subroutine, entry, and function always at 6 for fixed format
721: && pos.getToken().getTokenID() == FTokenContext.KW_SUBROUTINE
722: || pos.getToken().getTokenID() == FTokenContext.KW_ENTRY
723: || pos.getToken().getTokenID() == FTokenContext.KW_FUNCTION) {
724: indent = 6;
725:
726: } else { // first non-WS char is not comment
727:
728: indent = findIndent(firstNWS.getToken());
729: if (!getFreeFormat() && indent < 6)
730: indent = 6;
731: }
732: } else {
733: // The whole line is WS
734: // Can be empty line inside multi-line comment
735: TokenItem token = pos.getToken();
736: if (token == null) {
737: token = findLineStart(pos).getToken();
738: if (token == null) { // empty line
739: token = getLastToken();
740: }
741: }
742: indent = findIndent(pos.getToken());
743: }
744:
745: // For indent-only always indent
746: return changeLineIndent(pos, indent);
747: }
748:
749: /*
750: NO NEED FOR THESE YET
751: public boolean getFormatSpaceAfterComma() {
752: return getSettingBoolean(FSettingsNames.FORMAT_SPACE_AFTER_COMMA,
753: FSettingsDefaults.defaultFormatSpaceAfterComma);
754: }
755:
756: */
757: public boolean getFreeFormat() {
758: return org.netbeans.modules.cnd.settings.CppSettings
759: .getDefault().isFreeFormatFortran();
760: }
761: }
|