2727import java .util .Locale ;
2828
2929import org .fusesource .jansi .internal .CLibrary ;
30+ import org .fusesource .jansi .internal .CLibrary .WinSize ;
3031import org .fusesource .jansi .io .AnsiOutputStream ;
3132import org .fusesource .jansi .io .AnsiProcessor ;
3233import org .fusesource .jansi .io .FastBufferedOutputStream ;
3334import org .fusesource .jansi .io .WindowsAnsiProcessor ;
35+ import org .fusesource .jansi .internal .Kernel32 .CONSOLE_SCREEN_BUFFER_INFO ;
3436
37+ import static org .fusesource .jansi .internal .CLibrary .ioctl ;
3538import static org .fusesource .jansi .internal .CLibrary .isatty ;
3639import static org .fusesource .jansi .internal .Kernel32 .GetConsoleMode ;
3740import static org .fusesource .jansi .internal .Kernel32 .GetStdHandle ;
3841import static org .fusesource .jansi .internal .Kernel32 .STD_ERROR_HANDLE ;
3942import static org .fusesource .jansi .internal .Kernel32 .STD_OUTPUT_HANDLE ;
4043import static org .fusesource .jansi .internal .Kernel32 .SetConsoleMode ;
44+ import static org .fusesource .jansi .internal .Kernel32 .GetConsoleScreenBufferInfo ;
4145
4246/**
4347 * Provides consistent access to an ANSI aware console PrintStream or an ANSI codes stripping PrintStream
@@ -179,6 +183,20 @@ public class AnsiConsole {
179183 @ Deprecated
180184 public static PrintStream err ;
181185
186+ /**
187+ * Try to find the width of the console for this process.
188+ * Both output and error streams will be checked to determine the width.
189+ * A value of 0 is returned if the width can not be determined.
190+ * @since 2.2
191+ */
192+ public static int getTerminalWidth () {
193+ int w = out ().getTerminalWidth ();
194+ if (w <= 0 ) {
195+ w = err ().getTerminalWidth ();
196+ }
197+ return w ;
198+ }
199+
182200 static final boolean IS_WINDOWS = System .getProperty ("os.name" ).toLowerCase (Locale .ENGLISH ).contains ("win" );
183201
184202 static final boolean IS_CYGWIN = IS_WINDOWS
@@ -210,17 +228,19 @@ private AnsiConsole() {
210228 }
211229
212230 private static AnsiPrintStream ansiStream (boolean stdout ) {
213- final OutputStream out = new FastBufferedOutputStream (new FileOutputStream (stdout ? FileDescriptor .out : FileDescriptor .err ));
231+ FileDescriptor descriptor = stdout ? FileDescriptor .out : FileDescriptor .err ;
232+ final OutputStream out = new FastBufferedOutputStream (new FileOutputStream (descriptor ));
214233
215234 String enc = System .getProperty (stdout ? "sun.stdout.encoding" : "sun.stderr.encoding" );
216235
217236 final boolean isatty ;
218237 boolean isAtty ;
219238 boolean withException ;
239+ final int fd = stdout ? CLibrary .STDOUT_FILENO : CLibrary .STDERR_FILENO ;
220240 try {
221241 // If we can detect that stdout is not a tty.. then setup
222242 // to strip the ANSI sequences..
223- isAtty = isatty (stdout ? CLibrary . STDOUT_FILENO : CLibrary . STDERR_FILENO ) != 0 ;
243+ isAtty = isatty (fd ) != 0 ;
224244 withException = false ;
225245 } catch (Throwable ignore ) {
226246 // These errors happen if the JNI lib is not available for your platform.
@@ -230,6 +250,7 @@ private static AnsiPrintStream ansiStream(boolean stdout) {
230250 }
231251 isatty = isAtty ;
232252
253+ final AnsiOutputStream .WidthSupplier width ;
233254 final AnsiProcessor processor ;
234255 final AnsiType type ;
235256 final AnsiOutputStream .IoRunnable installer ;
@@ -238,6 +259,7 @@ private static AnsiPrintStream ansiStream(boolean stdout) {
238259 processor = null ;
239260 type = withException ? AnsiType .Unsupported : AnsiType .Redirected ;
240261 installer = uninstaller = null ;
262+ width = new AnsiOutputStream .ZeroWidthSupplier ();
241263 }
242264 else if (IS_WINDOWS ) {
243265 final long console = GetStdHandle (stdout ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE );
@@ -287,6 +309,14 @@ else if (IS_CONEMU || IS_CYGWIN || IS_MSYSTEM) {
287309 type = ttype ;
288310 installer = uninstaller = null ;
289311 }
312+ width = new AnsiOutputStream .WidthSupplier () {
313+ @ Override
314+ public int getTerminalWidth () {
315+ CONSOLE_SCREEN_BUFFER_INFO info = new CONSOLE_SCREEN_BUFFER_INFO ();
316+ GetConsoleScreenBufferInfo (console , info );
317+ return info .windowWidth ();
318+ }
319+ };
290320 }
291321
292322 // We must be on some Unix variant...
@@ -295,6 +325,14 @@ else if (IS_CONEMU || IS_CYGWIN || IS_MSYSTEM) {
295325 processor = null ;
296326 type = AnsiType .Native ;
297327 installer = uninstaller = null ;
328+ width = new AnsiOutputStream .WidthSupplier () {
329+ @ Override
330+ public int getTerminalWidth () {
331+ WinSize sz = new WinSize ();
332+ ioctl (fd , CLibrary .TIOCGWINSZ , sz );
333+ return sz .ws_col ;
334+ }
335+ };
298336 }
299337
300338 AnsiMode mode ;
@@ -377,7 +415,7 @@ else if (term != null && term.contains("-256color")) {
377415 } catch (UnsupportedCharsetException e ) {
378416 }
379417 }
380- return newPrintStream (new AnsiOutputStream (out , mode , processor , type , colors , cs ,
418+ return newPrintStream (new AnsiOutputStream (out , width , mode , processor , type , colors , cs ,
381419 installer , uninstaller , resetAtUninstall ), cs .name ());
382420 }
383421
0 commit comments