001/* 002 * Copyright c 2018 Rusi Popov, MDA Tools.net All rights reserved. 003 * 004 * This program and the accompanying materials are made available under the terms of the 005 * Eclipse Public License v2.0 which accompanies this distribution, and is available at 006 * http://www.eclipse.org/legal/epl-v20.html 007 */ 008package net.mdatools.modelant.core.operation.format; 009 010import java.util.StringTokenizer; 011 012import net.mdatools.modelant.core.api.Function; 013 014/** 015 * Wrap the provided text by adding the prefix to all lines. If the text is empty, 016 * defaultVal is returned. 017 * 018 * @author Rusi Popov (popovr@mdatools.net) 019 */ 020public class FormatWrapText implements Function<String,String>{ 021 022 private static final String SEPARATOR_TAB = "\t"; 023 private static final String SEPARATOR_SPACE = " "; 024 private static final String SEPARATORS = SEPARATOR_SPACE+SEPARATOR_TAB; 025 026 /** 027 * OS specific End-Of-Line terminator 028 */ 029 private final String lineSeparator; 030 031 /** 032 * The maximum length of a line in JavaDoc comments. After that length the text should be wrapped 033 * on the next line. Guaranteed at least one word in a line. 034 */ 035 private final int maxLineLength; 036 private final String prefix; 037 private final String defaultVal; 038 039 /** 040 * Wrap the paragraphs to 105 characters terminated by system-specific line separator 041 * without any prefix and default value. 042 */ 043 public FormatWrapText() { 044 this("", ""); 045 } 046 047 /** 048 * Wrap the paragraphs to 105 characters terminated by "line.separator" 049 * @param prefix not null is prefix to be inserted in the beginning of each new line 050 * @param defaultVal non null is the value to prefix the first line 051 */ 052 public FormatWrapText(String prefix, String defaultVal) { 053 this(prefix, defaultVal, 105); 054 } 055 056 /** 057 * Wrap the paragraphs to maxLineLength characters terminated by "line.separator" 058 * @param prefix not null is prefix to be inserted in the beginning of each new line 059 * @param defaultVal non null is the value to prefix the first line 060 * @param maxLineLength > 0 061 */ 062 public FormatWrapText(String prefix, String defaultVal,int maxLineLength) { 063 this(prefix, defaultVal, maxLineLength, System.getProperty( "line.separator" )); 064 } 065 066 /** 067 * Wrap the paragraphs to maxLineLength characters terminated by lineSeparator 068 * @param prefix not null is prefix to be inserted in the beginning of each new line 069 * @param defaultVal non null is the value to prefix the first line 070 * @param maxLineLength > 0 071 * @param lineSeparator not null 072 */ 073 public FormatWrapText(String prefix, String defaultVal,int maxLineLength, String lineSeparator) { 074 assert prefix != null : "Expected a non-null prefix provided"; 075 assert defaultVal != null : "Expected a non-null default value provided"; 076 assert lineSeparator != null : "Expected a non-null line separator provided"; 077 assert maxLineLength > 0 : "Expected a positive line length"; 078 079 this.prefix = prefix; 080 this.defaultVal = defaultVal; 081 this.maxLineLength = maxLineLength; 082 this.lineSeparator = lineSeparator; 083 } 084 085 086 /** 087 * Adds the prefix to all lines and replaces the line terminators LF or CR LF with the system 088 * specific line terminator (CR LF or LF only). If the line is empty, defaultVal is returned. 089 * 090 * @param line to format 091 * @return a string where all new lines (including the first one) are prefixed with the prefix 092 * string 093 */ 094 public final String execute(String line) { 095 final String result; 096 String paragraph; 097 StringBuilder resultLines; 098 StringTokenizer paragraphs; 099 100 if ( line != null && !line.isEmpty() ) { // there are comments 101 resultLines = new StringBuilder(); 102 103 paragraphs = new StringTokenizer(line, "\n\r\f" ); 104 while ( paragraphs.hasMoreTokens() ) { 105 paragraph = paragraphs.nextToken(); 106 107 wrapParagraph( paragraph, resultLines ); 108 } 109 result = resultLines.toString(); 110 } else { 111 result = defaultVal; 112 } 113 return result; 114 } 115 116 /** 117 * Wrap the paragraph into the result lines 118 * @param paragraph not null 119 * @param resultLines not null 120 */ 121 private void wrapParagraph(String paragraph, StringBuilder resultLines) { 122 String token; 123 StringTokenizer tokens; 124 int linesize; 125 126 linesize = 0; 127 tokens = new StringTokenizer(paragraph, SEPARATORS, true); // keep the separators 128 while ( tokens.hasMoreTokens() ) { 129 token = tokens.nextToken(); 130 131 if ( linesize == 0 ) { // new line started 132 if ( !token.equals( SEPARATOR_SPACE ) && !token.equals( SEPARATOR_TAB ) ) { // first real token 133 resultLines.append( prefix ); 134 linesize += prefix.length(); 135 136 resultLines.append( token ); 137 linesize += token.length(); 138 139 } // else // parsing a separator char leading the line - do nothing, skip it 140 } else { // not the first token - just collect it 141 resultLines.append( token ); 142 linesize += token.length(); 143 } 144 145 if ( linesize >= maxLineLength ) { // end of line reached 146 thrimTrailingSeparator( resultLines ); 147 resultLines.append(lineSeparator); 148 linesize=0; 149 } 150 } 151 if (linesize>0) { // the last line is incomplete 152 thrimTrailingSeparator( resultLines ); 153 resultLines.append(lineSeparator); 154 } 155 } 156 157 /** 158 * Correct the length of the resultLines to trim the trailing separators 159 * @param resultLines 160 */ 161 private void thrimTrailingSeparator(StringBuilder resultLines) { 162 while (SEPARATORS.contains(""+resultLines.charAt( resultLines.length()-1 ))) { 163 resultLines.setLength( resultLines.length()-1 ); 164 } 165 } 166}