diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..a3bd7c5f138a26420aef777d76866d58bf8b2ef6 --- /dev/null +++ b/README.md @@ -0,0 +1,234 @@ +# String Box + +StringBox is very simple terminal-based display. Can be used to place arbitrary strings in arbitrary locations in a +terminal window. StringBox will *not* redraw the screen. Instead, it will produce a string that, when printed, will +fill the screen, causing the screen's previous contents to scroll off of the screen. StringBox also is not designed to +respond to events; however, you may create an Observer that aggregates a StringBox, producing a similar result. + +The default StringBox is 23×80 which, when printed with `System.out.println()`, will fill a standard 24×80 window except +for the last line and will place the cursor at the start of the last line for user input. You may consider creating a +24x80 StringBox with the two-argument constructor and print it with `System.out.print()`, which will fill a standard +24x80 window entirely and place the cursor at the end of the last line for user input. + +A StringBox is populated with repeated calls to `placeString()` and its related methods, `placeStringAlignTopLeft()`, +`placeStringAlignTopRight()`, `placeStringAlignBottomLeft()`, and `placeStringAlignBottomRight()`. The four latter +methods allow you to specify the top/bottom alignment and left/right justification. Since we expect that anchoring +a string with its upper-left corner to be the common case, the shorter-named method `placeString()` defaults to +that behavior. Each of the `placeString*()` methods returns its StringBox object, which allows multiple `placeString*()` +calls to be chained. After you have constructed the screen to be displayed, a call to `toString()` will produce a string +suitable for printing. + +You may pass multi-line strings to the `placeString*()` methods, and the result would be the equivalent of making +several `placeString*()` calls with one-line strings with the same left/right alignment column and adjacent rows. + +Tab characters are converted to four spaces, which may be problematic if you rely on tabs in the middle of strings to +perform alignment. We recommend that you either use separate calls to `placeString*()` to achieve this alignment, or +use other methods that operate on Strings to provide alignment. + +## Examples + +For conciseness, these examples assume a 12×25 StringBox object called `stringBox`. Note that the row/column numbering +and the horizontal/vertical dividers are for illustration only and are not part of the generated string. + +### Basic Usage + +We can place a single line on the screen: +``` +stringBox.placeString("foo",2,10); +``` +produces +``` + 111111111122222 + 0123456789012345678901234 + _________________________ + 0 | + 1 | + 2 | foo + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | +10 | +11 | +``` + +### Multi-line + +Multiple-line strings can be placed either as a single multi-line string or as multiple single-line strings: +``` +stringBox.placeString("foo\nbar baz",2,10); +``` +is equivalent to +``` +stringBox.placeString("foo",2,10).placeString("bar baz",3,10); +``` +as they both produce +``` + 111111111122222 + 0123456789012345678901234 + _________________________ + 0 | + 1 | + 2 | foo + 3 | bar baz + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | +10 | +11 | +``` + +### Right-Justification + +Inserted strings can be right-justified instead of left-justified: +``` +stringBox.placeStringAlignTopRight("foo\nbar baz",2,10); +``` + +produces + +``` + 111111111122222 + 0123456789012345678901234 + _________________________ + 0 | + 1 | + 2 | foo + 3 | bar baz + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | +10 | +11 | +``` + +### Bottom-Aligned + +You can specify the bottom row for an inserted string instead of its top row: +``` +stringBox.placeStringAlignBottomLeft("foo\nbar baz",2,10); +``` + +produces + +``` + 111111111122222 + 0123456789012345678901234 + _________________________ + 0 | + 1 | foo + 2 | bar baz + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | +10 | +11 | +``` + +### Emojis + +Many emojis occupy more than one horizontal space; however, this is not a problem for StringBox because those emojis +are also actually multiple characters: +``` +stringBox.placeStringAlignTopLeft("foo\n_😄_",2,10); +``` +which is equivalent to +``` +stringBox.placeStringAlignTopLeft("foo\n_\uD83D\uDE04_",2,10); +``` +or, using the [com.vdurmont.emoji-java](https://github.com/vdurmont/emoji-java) library: +``` +stringBox.placeStringAlignTopLeft(EmojiParser.parseToUnicode("foo\n_:smile:_"),2,10); +``` +produces + +``` + 111111111122222 + 0123456789012345678901234 + _________________________ + 0 | + 1 | + 2 | foo + 3 | _😄_ + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | +10 | +11 | +``` + +That these emojis will occupy multiple spaces will only be an issue if you rely on them occupying but one space. + +### Text Outside the Borders + +Any text that extends beyond the right-most column or the bottom-most row, or occupies a negative row or a negative +column, will be silently truncated: +``` +stringBox.placeString("foo\nbar baz",-1,-1); +``` + +``` + 111111111122222 + 0123456789012345678901234 + _________________________ + 0 |ar baz + 1 | + 2 | + 3 | + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | +10 | +11 | +``` + +### Interaction Among Inserted Strings + +If two inserted strings overlap, the string inserted last will overwrite a portion of the string written first: +``` +stringBox.placeStringAlignTopLeft("foo\nbar", 2, 10) + .placeStringAlignBottomLeft("larry\ncurly\nmoe", 5, 6) + .placeStringAlignTopRight("quux\nxyzzy", 3, 20) + .placeStringAlignBottomRight("one\ntwo\nthree", 10, 15); +``` + + +``` + 111111111122222 + 0123456789012345678901234 + _________________________ + 0 | + 1 | + 2 | foo + 3 | larryar quux + 4 | curly xyzzy + 5 | moe + 6 | + 7 | + 8 | one + 9 | two +10 | three +11 | +``` + +--- +String Box © 2020 Christopher Bohn, bohn@unl.edu diff --git a/src/main/java/edu/unl/cse/bohn/StringBox.java b/src/main/java/edu/unl/cse/bohn/StringBox.java index 90d73158ab701bf314883ba385a1e588e6a5be8d..baa0d8ad246647eeebd7a706bfbb9aab0ce62f7a 100644 --- a/src/main/java/edu/unl/cse/bohn/StringBox.java +++ b/src/main/java/edu/unl/cse/bohn/StringBox.java @@ -1,5 +1,5 @@ /* - * string_box Copyright (c) 2020 Christopher Bohn, bohn@unl.edu + * String Box Copyright (c) 2020 Christopher Bohn, bohn@unl.edu */ package edu.unl.cse.bohn; @@ -19,6 +19,8 @@ package edu.unl.cse.bohn; * .toString(); * System.out.println(screen); * </code></pre> + * + * <p>Note that StringBox is <i>not</i> robust to hidden characters, such as VT100 escape sequences.</p> */ public class StringBox { private int maximumWidth; @@ -28,7 +30,7 @@ public class StringBox { private StringRow[] rows; /** - * <p>Produces a StringBox suitably-sized for a standard 24x80 terminal. The StringBox will be 23x80; if the string + * <p>Produces a StringBox suitably-sized for a standard 24×80 terminal. The StringBox will be 23×80; if the string * is printed with <code>System.out.println()</code> then it will leave the cursor on the 24th line, where the * user can enter their input without scrolling the top of the string off the screen.</p> * @@ -40,7 +42,7 @@ public class StringBox { * @see #StringBox(int, int) */ public StringBox() { - this(23, 80); // standard terminal is 24x80, but leave room for the user's input + this(23, 80); // standard terminal is 24×80, but leave room for the user's input } /** diff --git a/src/test/java/edu/unl/cse/bohn/StringBoxTest.java b/src/test/java/edu/unl/cse/bohn/StringBoxTest.java index 5dd45784ec9185c1c7c44a571aed4445b5e2a41c..5b68205b93b1ec594730cfeaa98f17d3e2dbec49 100644 --- a/src/test/java/edu/unl/cse/bohn/StringBoxTest.java +++ b/src/test/java/edu/unl/cse/bohn/StringBoxTest.java @@ -1,5 +1,5 @@ /* - * string_box Copyright (c) 2020 Christopher Bohn, bohn@unl.edu + * String Box Copyright (c) 2020 Christopher Bohn, bohn@unl.edu */ package edu.unl.cse.bohn; @@ -116,6 +116,7 @@ public class StringBoxTest { position2).toString(); // Assert assertEquals(expectedOutput, actualOutput); + assertEquals(10, actualOutput.length()); } @Test