/** * Copyright (C) 2013 Alexander Szczuczko * * This file may be modified and distributed under the terms * of the MIT license. See the LICENSE file for details. */ package ca.szc.keratin.core.misc; import java.util.LinkedList; import java.util.List; public class LineWrap { /** * According to RFC2812, this is strictly 510 characters (as the maximum allowed for the command and its * parameters), however we'll allow less than that to provide for room for the overhead. This is a rough value and * may need to become more smaller. */ public static final int MAX_IRC_LENGTH = 400; /** * Wrap line to lines of the maximum IRC length. Any newline (\n) characters will force a line break where they * exist. * * @param line Long line to wrap * @return List of wrapped lines containing at least one string */ public static List<String> wrap( String line ) { return wrap( line, MAX_IRC_LENGTH ); } /** * Wrap a line to lines of at most the specified length. Any newline (\n) characters will force a line break where * they exist. Otherwise, line breaks will be assigned to the last whitespace character in a line. If neither of * these methods works, the line maximum length will be enforced by splitting the string at the length limit. * * @param line Long line to wrap. * @param maxLineLength The maximum length of a line to allow. * @return List of wrapped lines containing at least one line. */ public static List<String> wrap( String raw, final int maxLineLength ) { // Is this a base case? if ( raw.length() <= maxLineLength ) { // \n characters force a break regardless of where they are. // Search the remainder segment for one. int endIndex = raw.indexOf( '\n' ); if ( endIndex != -1 ) { String line = raw.substring( 0, endIndex ); List<String> lines = wrap( raw.substring( endIndex + 1 ), raw.length() ); lines.add( 0, line ); return lines; } else { // Otherwise this really is a base case // Init return list List<String> lines = new LinkedList<String>(); // Add the whole remainder as the first inserted line lines.add( raw ); return lines; } } else { int endIndex = -1; // \n characters force a break regardless of where they are. // Search in our segment for one. endIndex = raw.substring( 0, maxLineLength ).indexOf( '\n' ); // If no \n was found, search for a whitespace character closest to the end of our segment. if ( endIndex == -1 ) { char[] rawArray = raw.toCharArray(); for ( int i = maxLineLength; i > 0 && endIndex == -1; i-- ) { if ( Character.isWhitespace( rawArray[i] ) ) { endIndex = i; } } } // If no intelligent split point was found, just use the max size as that point if ( endIndex == -1 ) { endIndex = maxLineLength; } int splitSpacing = 0; /* * Remove/skip-over whitespace splitting characters. This avoids including \n manual split characters, which * aren't allowed by the IRC protocol, as well as having a space at the start of each automatically wrapped * line. */ if ( Character.isWhitespace( raw.charAt( endIndex ) ) ) { splitSpacing = 1; } String line = raw.substring( 0, endIndex ); // Recurse on remainder of raw List<String> lines = wrap( raw.substring( endIndex + splitSpacing ), maxLineLength ); // Prepend our line, so the text stays in the original order lines.add( 0, line ); return lines; } } }