diff --git a/build.gradle.kts b/build.gradle.kts index ef28ced..0bb2484 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,6 +5,10 @@ plugins { id("maven-publish") } +application { + mainClass.set("dev.jakub.terminal.example.Examples") +} + tasks.named("run") { jvmArgs("-Ddev.jakub.terminal.ansi=true", "-Dfile.encoding=UTF-8") } diff --git a/docs/Examples.md b/docs/Examples.md index 652b4ad..5032ee5 100644 --- a/docs/Examples.md +++ b/docs/Examples.md @@ -37,6 +37,21 @@ Terminal.table() .row("1", "2", "3") .row("4", "5", "6") .print(System.out); + +// From a list of rows (e.g. from CSV or DB) +List rows = List.of( + new String[]{"Alice", "10"}, + new String[]{"Bob", "20"} +); +Terminal.table() + .header("Name", "Score") + .rows(rows) + .print(System.out); + +// One-liner with header + data +Terminal.table() + .fromRows(new String[]{"A", "B"}, List.of(new String[]{"1", "2"}, new String[]{"3", "4"})) + .print(System.out); ``` ## Tree @@ -178,8 +193,18 @@ Terminal.log() .error("Something failed") .withTimestamp() .print(System.out); + +// Only WARN and ERROR (e.g. for production) +Terminal.log() + .info("Hidden") + .warn("Visible") + .error("Visible") + .minLevel(Log.Level.WARN) + .print(System.out); ``` +(Use `import dev.jakub.terminal.components.Log;` for `Log.Level`.) + ## Timeline ```java diff --git a/src/main/java/dev/jakub/terminal/components/Log.java b/src/main/java/dev/jakub/terminal/components/Log.java index a2f58fe..269d929 100644 --- a/src/main/java/dev/jakub/terminal/components/Log.java +++ b/src/main/java/dev/jakub/terminal/components/Log.java @@ -22,6 +22,7 @@ public final class Log { private final TerminalSupport support; private final List entries = new ArrayList<>(); private boolean withTimestamp; + private Level minLevel; public Log(TerminalSupport support) { this.support = support; @@ -68,11 +69,21 @@ public final class Log { } /** - * Prints all log entries to the given stream. + * Only print entries at this level or higher (e.g. WARN shows WARN and ERROR). + * Useful for "quiet" mode or production. + */ + public Log minLevel(Level level) { + this.minLevel = level; + return this; + } + + /** + * Prints log entries to the given stream (respects minLevel if set). */ public void print(PrintStream out) { DateTimeFormatter fmt = DateTimeFormatter.ofPattern("HH:mm:ss").withZone(ZoneId.systemDefault()); for (Entry e : entries) { + if (minLevel != null && e.level.ordinal() < minLevel.ordinal()) continue; String prefix = withTimestamp ? "[" + fmt.format(Instant.now()) + "] " : ""; String label = "[" + e.level.name() + "]"; while (label.length() < LABEL_WIDTH) label += " "; @@ -104,11 +115,14 @@ public final class Log { } } - private enum Level { + /** + * Log level for filtering. Order: DEBUG < INFO < WARN < ERROR. + */ + public enum Level { + DEBUG(Ansi.FG_BRIGHT_BLACK), INFO(Ansi.FG_CYAN), WARN(Ansi.FG_YELLOW), - ERROR(Ansi.FG_RED), - DEBUG(Ansi.FG_BRIGHT_BLACK); + ERROR(Ansi.FG_RED); final String ansi; diff --git a/src/main/java/dev/jakub/terminal/components/Table.java b/src/main/java/dev/jakub/terminal/components/Table.java index 1e05f27..1c1f173 100644 --- a/src/main/java/dev/jakub/terminal/components/Table.java +++ b/src/main/java/dev/jakub/terminal/components/Table.java @@ -47,6 +47,26 @@ public final class Table { return this; } + /** + * Adds many rows from a list of arrays (e.g. from CSV or a list of records). + * Each array is one row; null cells are treated as empty string. + */ + public Table rows(Iterable dataRows) { + if (dataRows == null) return this; + for (String[] cells : dataRows) { + if (cells != null) row(cells); + } + return this; + } + + /** + * Builds a table from a header and a list of row arrays in one call. + */ + public Table fromRows(String[] headerRow, Iterable dataRows) { + if (headerRow != null && headerRow.length > 0) header(headerRow); + return rows(dataRows); + } + /** * Prints the table to the given stream. */ diff --git a/src/main/java/dev/jakub/terminal/example/Examples.java b/src/main/java/dev/jakub/terminal/example/Examples.java new file mode 100644 index 0000000..29e80aa --- /dev/null +++ b/src/main/java/dev/jakub/terminal/example/Examples.java @@ -0,0 +1,232 @@ +package dev.jakub.terminal.example; + +import dev.jakub.terminal.Terminal; +import dev.jakub.terminal.components.Log; +import dev.jakub.terminal.components.Notification; +import dev.jakub.terminal.components.Steps; +import dev.jakub.terminal.core.Color; + +import java.util.List; + + +public final class Examples { + + public static void main(String[] args) { + runAll(); + } + + public static void runAll() { + textAndRule(); + keyValueAndBox(); + table(); + tableFromRows(); + tree(); + columns(); + steps(); + breadcrumb(); + log(); + logWithMinLevel(); + diff(); + timeline(); + heatmap(); + chart(); + badgeAndNotify(); + codeBlock(); + sysInfo(); + markdown(); + toc(); + } + + static void textAndRule() { + Terminal.print("=== Text & Rule ===").color(Color.CYAN).bold().println(); + Terminal.rule().character('=').print(); + Terminal.print("Hello").color(Color.GREEN).println(); + Terminal.rule().doubles().prefix("-- ").suffix(" --").print(); + System.out.println(); + } + + static void keyValueAndBox() { + Terminal.print("=== KeyValue & Box ===").color(Color.CYAN).bold().println(); + Terminal.keyValue() + .row("Name", "terminal-ui") + .row("Version", "1.0") + .separator(" = ") + .print(System.out); + Terminal.box() + .title("Info") + .line("First line") + .lines("Second", "Third") + .print(System.out); + System.out.println(); + } + + static void table() { + Terminal.print("=== Table ===").color(Color.CYAN).bold().println(); + Terminal.table() + .header("Col A", "Col B", "Col C") + .row("1", "2", "3") + .row("4", "5", "6") + .print(System.out); + System.out.println(); + } + + static void tableFromRows() { + Terminal.print("=== Table from rows ===").color(Color.CYAN).bold().println(); + List rows = List.of( + new String[]{"Alice", "10"}, + new String[]{"Bob", "20"} + ); + Terminal.table() + .header("Name", "Score") + .rows(rows) + .print(System.out); + System.out.println(); + } + + static void tree() { + Terminal.print("=== Tree ===").color(Color.CYAN).bold().println(); + Terminal.tree() + .node("root") + .child("src") + .child("main").end() + .child("test").end() + .end() + .child("docs") + .end() + .print(System.out); + System.out.println(); + } + + static void columns() { + Terminal.print("=== Columns ===").color(Color.CYAN).bold().println(); + Terminal.columns() + .column("Left\ncolumn\ntext") + .column("Middle") + .column("Right") + .print(System.out); + System.out.println(); + } + + static void steps() { + Terminal.print("=== Steps ===").color(Color.CYAN).bold().println(); + Terminal.steps() + .step("Setup", Steps.Status.DONE) + .step("Build", Steps.Status.RUNNING) + .step("Deploy", Steps.Status.PENDING) + .print(System.out); + System.out.println(); + } + + static void breadcrumb() { + Terminal.print("=== Breadcrumb ===").color(Color.CYAN).bold().println(); + Terminal.breadcrumb() + .crumb("Home") + .crumb("Projects") + .crumb("terminal-ui") + .separator(" / ") + .print(System.out); + System.out.println(); + } + + static void log() { + Terminal.print("=== Log ===").color(Color.CYAN).bold().println(); + Terminal.log() + .info("Started") + .warn("Deprecation notice") + .error("Something failed") + .withTimestamp() + .print(System.out); + System.out.println(); + } + + static void logWithMinLevel() { + Terminal.print("=== Log (minLevel WARN) ===").color(Color.CYAN).bold().println(); + Terminal.log() + .info("Hidden") + .warn("Visible") + .error("Visible") + .minLevel(Log.Level.WARN) + .print(System.out); + System.out.println(); + } + + static void diff() { + Terminal.print("=== Diff ===").color(Color.CYAN).bold().println(); + Terminal.diff() + .before("old line 1\nold line 2") + .after("new line 1\nnew line 2\nnew line 3") + .print(System.out); + System.out.println(); + } + + static void timeline() { + Terminal.print("=== Timeline ===").color(Color.CYAN).bold().println(); + Terminal.timeline() + .event("2025-01-01", "First release") + .event("2025-06-01", "Added SelectList") + .event("2026-01-01", "GitHub Packages") + .print(System.out); + System.out.println(); + } + + static void heatmap() { + Terminal.print("=== Heatmap ===").color(Color.CYAN).bold().println(); + Terminal.heatmap() + .row("Mon", 10, 20, 5, 30) + .row("Tue", 15, 25, 10, 20) + .row("Wed", 5, 15, 25, 35) + .print(System.out); + System.out.println(); + } + + static void chart() { + Terminal.print("=== Chart ===").color(Color.CYAN).bold().println(); + Terminal.chart() + .data(1.0, 2.0, 1.5, 3.0, 2.5) + .height(5) + .print(System.out); + System.out.println(); + } + + static void badgeAndNotify() { + Terminal.print("=== Badge & Notify ===").color(Color.CYAN).bold().println(); + Terminal.badge("OK", Color.GREEN).println(); + Terminal.badge("WARN", Color.YELLOW).print(System.out); + Terminal.notify("Done!", Notification.Type.SUCCESS); + Terminal.notify("Warning", Notification.Type.WARNING); + System.out.println(); + } + + static void codeBlock() { + Terminal.print("=== Code block ===").color(Color.CYAN).bold().println(); + Terminal.code("java") + .line("public static void main(String[] args) {") + .line(" System.out.println(\"Hello\");") + .line("}") + .lineNumbers() + .print(System.out); + System.out.println(); + } + + static void sysInfo() { + Terminal.print("=== SysInfo ===").color(Color.CYAN).bold().println(); + Terminal.sysinfo().print(System.out); + System.out.println(); + } + + static void markdown() { + Terminal.print("=== Markdown ===").color(Color.CYAN).bold().println(); + Terminal.markdown("# Title\n\n**Bold** and *italic*.\n\n- Item 1\n- Item 2\n\n---") + .print(System.out); + System.out.println(); + } + + static void toc() { + Terminal.print("=== Table of contents ===").color(Color.CYAN).bold().println(); + Terminal.toc() + .section("Introduction").sub("Overview").sub("Install") + .section("API").sub("Reference") + .section("Examples") + .print(System.out); + } +}