Skip to content

Commit da7f546

Browse files
committed
* initial pretty-console commit
0 parents  commit da7f546

File tree

6 files changed

+661
-0
lines changed

6 files changed

+661
-0
lines changed

pom.xml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
5+
<groupId>com.github.epochcoder</groupId>
6+
<artifactId>pretty-console</artifactId>
7+
<version>1.0-SNAPSHOT</version>
8+
<packaging>jar</packaging>
9+
10+
<name>pretty-console</name>
11+
<url>http://maven.apache.org</url>
12+
13+
<properties>
14+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
15+
</properties>
16+
17+
<dependencies>
18+
<dependency>
19+
<groupId>junit</groupId>
20+
<artifactId>junit</artifactId>
21+
<version>3.8.1</version>
22+
<scope>test</scope>
23+
</dependency>
24+
<dependency>
25+
<groupId>com.google.guava</groupId>
26+
<artifactId>guava</artifactId>
27+
<version>15.0</version>
28+
</dependency>
29+
</dependencies>
30+
</project>
Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
package com.github.epochcoder.prettyconsole;
2+
3+
import com.github.epochcoder.prettyconsole.handlers.ConsoleBoxPasswordHandler;
4+
import com.google.common.base.Function;
5+
import com.google.common.base.Joiner;
6+
import com.google.common.base.Preconditions;
7+
import com.google.common.base.Splitter;
8+
import com.google.common.base.Strings;
9+
import com.google.common.collect.Iterables;
10+
import java.awt.Font;
11+
import java.awt.FontMetrics;
12+
import java.awt.Graphics;
13+
import java.awt.Graphics2D;
14+
import java.awt.RenderingHints;
15+
import java.awt.image.BufferedImage;
16+
import java.io.PrintStream;
17+
import java.util.ArrayList;
18+
import java.util.List;
19+
import java.util.regex.Pattern;
20+
21+
/**
22+
* represents a console display box in the system console (or any PrintStream).
23+
* used to display friendly technical information
24+
* @author Willie Scholtz
25+
*/
26+
public final class ConsoleBox {
27+
28+
/**
29+
* the character to use in box corners
30+
*/
31+
private static final String BOX_CHAR = " + ";
32+
33+
/**
34+
* the character to use to pad strings with
35+
*/
36+
private static final char PAD_CHAR = ' ';
37+
38+
/**
39+
* the character used for the box's right and left sides
40+
*/
41+
private static final String END_CHAR = " | ";
42+
43+
/**
44+
* the character used for the box's top, title and bottom sides
45+
*/
46+
private static final String TB_CHAR = "-";
47+
48+
/**
49+
* the character used for representing black in a color
50+
*/
51+
private static final String BLACK_CHAR = " ";
52+
53+
/**
54+
* the character used for representing white in a color
55+
*/
56+
private static final String WHITE_CHAR = "#";
57+
58+
/**
59+
* the character used for representing aliasing of fonts.
60+
* actually other colors, but since our image is only black and white
61+
* it will represent a shade, which in this case is aliasing
62+
*/
63+
private static final String ALIAS_CHAR = " ";
64+
65+
/**
66+
* the key value separator for names and values
67+
*/
68+
private static final String KEY_VALUE_SEP = " : ";
69+
70+
71+
private final List<ConsoleBoxKeyHandler> handlers;
72+
private final StringBuilder builder;
73+
private boolean content;
74+
private final int width;
75+
76+
/**
77+
* creates a new instance of a ConsoleBox
78+
* @param boxWidth the width of the box (in character count)
79+
* @param title the initial title of the box, leave blank for none
80+
*/
81+
public ConsoleBox(int boxWidth, String title) {
82+
this.width = boxWidth;
83+
this.builder = new StringBuilder();
84+
this.handlers = new ArrayList<ConsoleBoxKeyHandler>();
85+
86+
// add default password handler
87+
this.handlers.add(new ConsoleBoxPasswordHandler());
88+
89+
if (!Strings.isNullOrEmpty(title)) {
90+
this.title(title);
91+
}
92+
}
93+
94+
/*
95+
* creates a new instance of a ConsoleBox with no title
96+
* @param boxWidth the width of the box (in character count)
97+
*/
98+
public ConsoleBox(int boxWidth) {
99+
this(boxWidth, null);
100+
}
101+
102+
public ConsoleBox handler(ConsoleBoxKeyHandler handler) {
103+
this.handlers.add(handler);
104+
return this;
105+
}
106+
107+
/**
108+
* builds and writes this box to the specified output stream
109+
* @param output
110+
*/
111+
public void build(PrintStream output) {
112+
this.title("");
113+
output.println(this.builder.toString());
114+
}
115+
116+
private String padBoth(String string, String pad, int length) {
117+
int right = (length - string.length()) / 2 + string.length();
118+
String result = Strings.padEnd(string, right, pad.toCharArray()[0]);
119+
return Strings.padStart(result, length, pad.toCharArray()[0]);
120+
}
121+
122+
/**
123+
* adds a title section to the console box
124+
* @param title the title to use
125+
* @return the current box
126+
*/
127+
public ConsoleBox title(String title) {
128+
this.builder.append("\n" + BOX_CHAR).append(padBoth(title,
129+
TB_CHAR, this.width)).append(BOX_CHAR);
130+
131+
return this;
132+
}
133+
134+
/**
135+
* adds an empty line section to the console box
136+
* @return the current box
137+
*/
138+
public ConsoleBox empty() {
139+
this.builder.append("\n" + BOX_CHAR).append(
140+
padBoth("", " ", this.width)).append(BOX_CHAR);
141+
142+
return this;
143+
}
144+
145+
/**
146+
* generates and writes the specified text as an ASCII image into this box
147+
* @param text the text to write as ASCII
148+
* @param invert should the ASCII colors be inverted?
149+
* @return the current box
150+
*/
151+
public ConsoleBox ascii(String text, boolean invert) {
152+
final BufferedImage image = new BufferedImage(this.width,
153+
32, BufferedImage.TYPE_INT_RGB);
154+
155+
final Graphics graphics = image.getGraphics();
156+
final Graphics2D g2d = (Graphics2D) graphics;
157+
158+
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
159+
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
160+
161+
Font textFont = new Font("Dialog", Font.BOLD, 22);
162+
FontMetrics textMetrics = g2d.getFontMetrics(textFont);
163+
g2d.setFont(textFont);
164+
165+
int tX = (image.getWidth() / 2) - (textMetrics.stringWidth(text) / 2);
166+
int tY = (image.getHeight() / 2) + (textMetrics.getHeight() / 2) - 5;
167+
168+
g2d.drawString(text, tX, tY);
169+
g2d.drawRenderedImage(image, null);
170+
g2d.dispose();
171+
172+
final int iHeight = image.getHeight();
173+
final int iWidth = image.getWidth();
174+
175+
final String bChar = invert ? WHITE_CHAR : BLACK_CHAR;
176+
final String wChar = invert ? BLACK_CHAR : WHITE_CHAR;
177+
178+
for (int y = 0; y < iHeight; y++) {
179+
final StringBuilder sb = new StringBuilder();
180+
for (int x = 0; x < iWidth; x++) {
181+
final int rgbColor = image.getRGB(x, y);
182+
sb.append(rgbColor == -16777216 ? bChar : rgbColor == -1 ? wChar : ALIAS_CHAR);
183+
}
184+
185+
if (sb.toString().trim().isEmpty()) {
186+
continue;
187+
}
188+
189+
this.builder.append("\n" + END_CHAR)
190+
.append(sb).append(END_CHAR);
191+
}
192+
193+
return this;
194+
}
195+
196+
/**
197+
* adds a informational line to the console box,
198+
* automatically splitting large values
199+
* @param key the name of the value to display
200+
* @param value the value of this line
201+
* @return the current box
202+
*/
203+
public ConsoleBox line(String key, String value) {
204+
key = Strings.isNullOrEmpty(key) ? "null" : key;
205+
value = Strings.isNullOrEmpty(value) ? "" : value;
206+
207+
// get the key length
208+
final int kL = key.length();
209+
// calculate remaining box space for the value
210+
final int ths = (this.width - kL - KEY_VALUE_SEP.length());
211+
Preconditions.checkState(ths > -1, "key[" + key + "] is to long "
212+
+ "for box with a " + width + " width!");
213+
214+
// \n | the_key_length_in_spaces
215+
final String joinOn = ("\n" + END_CHAR + Strings.padEnd("",
216+
kL + KEY_VALUE_SEP.length(), PAD_CHAR));
217+
218+
// get key handlers and modify if neccessary
219+
for (ConsoleBoxKeyHandler handler : this.handlers) {
220+
if (handler.shouldHandle(key)) {
221+
value = handler.handleValue(key, value);
222+
// don't break, possibilitty of multiple handlers
223+
}
224+
}
225+
226+
// if a key handler returns null, a key should be skipped
227+
if (value != null) {
228+
// split the string on either length or new lines
229+
Iterable<String> splitted = Splitter.on(Pattern
230+
.compile("(?<=\\G.{" + ths + "})|\\n")).split(value);
231+
232+
// add the value + end characters (multiple lines)
233+
String formatted = Joiner.on(joinOn).join(
234+
Iterables.transform(splitted, new Function<String, String>() {
235+
@Override
236+
public String apply(String input) {
237+
return Strings.padEnd(input, ths, ' ') + END_CHAR;
238+
}
239+
}));
240+
241+
// write completed line to builder
242+
this.builder.append("\n" + END_CHAR).append(key)
243+
.append(KEY_VALUE_SEP).append(formatted);
244+
245+
this.content = true;
246+
}
247+
248+
return this;
249+
}
250+
251+
/**
252+
* @return true if {@link #line(java.lang.String, java.lang.String)}
253+
* has been called at least once
254+
*/
255+
public boolean hasContent() {
256+
return content;
257+
}
258+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.github.epochcoder.prettyconsole;
2+
3+
/**
4+
* interface for defining handlers for certain console box keys
5+
* @author Willie Scholtz
6+
* @version 1.43
7+
*/
8+
public interface ConsoleBoxKeyHandler {
9+
10+
/**
11+
* determines if the specified key should be handled by this key handler
12+
* @param key the key to check
13+
* @return true if this key should be handled by this key handler
14+
*/
15+
public boolean shouldHandle(final String key);
16+
17+
/**
18+
* if this handler is set to handle the specified key it, will execute this method to handle it's value
19+
* @param key the key being handled
20+
* @param value the original value to handle, note that console box automatically handles new lines and long lines
21+
* @return the formatted value for ConsoleBox, or null if the whole line should be skipped
22+
*/
23+
public String handleValue(final String key, final String value);
24+
25+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.github.epochcoder.prettyconsole.handlers;
2+
3+
import com.github.epochcoder.prettyconsole.ConsoleBoxKeyHandler;
4+
import java.util.regex.Pattern;
5+
6+
/**
7+
* ensures no passwords are present in the ConsoleBox
8+
* @author Willie Scholtz
9+
* @version 1.43
10+
*/
11+
public class ConsoleBoxPasswordHandler implements ConsoleBoxKeyHandler {
12+
/**
13+
* pattern defining which attributes should be blurred
14+
*/
15+
private static final Pattern IGNORE_ATT_PATT = Pattern
16+
.compile("pass(word)?", Pattern.CASE_INSENSITIVE);
17+
18+
/**
19+
* replacement value for sensitive data
20+
*/
21+
private static final String SAFE_REPLACEMENT = "*****";
22+
23+
/**
24+
* determines if a certain parameter is safe to transmit over the wire
25+
* @param key the name of the parameter that will be sent
26+
* @return true if the parameter may be sent
27+
*/
28+
private static boolean safeToTransmit(final String key) {
29+
return !IGNORE_ATT_PATT.matcher(key).find();
30+
}
31+
32+
@Override
33+
public boolean shouldHandle(String key) {
34+
return !safeToTransmit(key);
35+
}
36+
37+
@Override
38+
public String handleValue(String key, String value) {
39+
return SAFE_REPLACEMENT;
40+
}
41+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy