跳到主要内容
ansicode
Java

在 Java 中使用 ANSI 转义码

Java 字符串字面量没有 `\e` 转义 —— 请写 `\033`(八进制)或 `\u001b`(Unicode 转义)。`System.out.println("\033[31mred\033[0m")` 在任意 JVM 上均按字节透传。Windows 10 1709+ 的 Conhost 原生解析 VT,但为了兼容更早的 Conhost(并处理 Maven / Gradle / IntelliJ 输出包装常常去色的情形),可调用 **Jansi** 的 `AnsiConsole.systemInstall()` —— 它替换 `System.out` 与 `System.err` 包装,在旧主机上将 ANSI 翻译为 Win32 控制台 API 调用,在新主机上透传。 超出零散 print 语句的场景:**JLine 3** 是 Java 的 `readline`(原始模式、行编辑、历史、补全、密码遮罩、终端能力检测)—— Spring Shell、JBang、Groovy `groovysh`、OpenJDK `jshell` 的底层。**picocli** 通过注解驱动 CLI 参数解析,并经 `Help.Ansi.AUTO` 自动彩色化帮助文档(遵守 `NO_COLOR` 与 `isatty`)。完整全屏 TUI 请用 **Lanterna** —— 以 Swing 式的 `Window` / `Panel` / `Component` 层次渲染到 ANSI。

推荐库

  • Jansi

    Windows VT 适配 + ANSI 构建器的事实标准。`AnsiConsole.systemInstall()` 替换 `System.out` / `System.err`,让转义码在 1709 之前的 Conhost 上工作(将 ANSI 翻译为 Win32 控制台 API)。流式构建:`Ansi.ansi().fg(RED).bold().a("error:").reset().a(" perm denied")`。Maven、Gradle、Spring Boot 开发工具的输出层。

  • JLine 3

    Java 的 `readline` —— 原始模式、行编辑、历史、Tab 补全、密码遮罩、终端能力检测。Spring Shell、JBang、Groovy `groovysh`、OpenJDK `jshell` 的底层。Windows 上桥接到 Jansi;POSIX 上使用原生 PTY(`org.jline.terminal.impl.PosixSysTerminal`)。

  • picocli

    注解驱动的 CLI 框架 —— `@Command`、`@Option`、`@Parameters`。通过 `Help.Ansi.AUTO` 自动彩色化 `--help`(遵守 `NO_COLOR` + `isatty`)。description 字符串中的标记语法:`@|bold,fg(red) error|@`、`@|underline link|@`。与 Jansi 集成以支持 Windows VT。

  • Lanterna

    跨平台全屏 TUI 库 —— 以 Swing 式的 `Window`、`Panel`、`Component`、`Label`、`Button`、`TextBox` 层次渲染到 ANSI。支持键盘与鼠标、多窗口布局、主题。被经典 Java TUI 项目使用(文本模式游戏、运维仪表板)。

常用写法

直接 System.out —— \033(八进制)或 \u001b(Unicode)
public class Main {
    public static void main(String[] args) {
        // Java has no \e literal — use \033 (octal) or \u001b (Unicode).
        System.out.println("\033[1;31merror:\033[0m permission denied");
        System.out.println("\u001b[1;32mok:\u001b[0m all 142 tests passed");
    }
}
Jansi 构建器 + AnsiConsole.systemInstall(Windows 安全)
import org.fusesource.jansi.AnsiConsole;
import static org.fusesource.jansi.Ansi.*;
import static org.fusesource.jansi.Ansi.Color.*;

public class Main {
    public static void main(String[] args) {
        AnsiConsole.systemInstall();   // safe no-op on modern hosts
        try {
            System.out.println(ansi()
                .fg(RED).bold().a("error:")
                .reset().a(" permission denied"));

            // Truecolor (Jansi 2.x):
            System.out.println(ansi()
                .fgRgb(0xcb, 0xa6, 0xf7).a("lavender truecolor").reset());
        } finally {
            AnsiConsole.systemUninstall();
        }
    }
}
picocli @Command 与彩色帮助
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
import picocli.CommandLine.Help.Ansi;

@Command(
    name = "deploy",
    mixinStandardHelpOptions = true,
    description = "@|bold,fg(blue) Deploy|@ a service to @|fg(yellow) production|@."
)
public class Deploy implements Runnable {
    @Option(names = {"-r", "--region"},
            description = "AWS region (@|fg(cyan) e.g. us-east-1|@)")
    String region;

    public void run() {
        // Ansi.AUTO respects NO_COLOR + isatty automatically.
        System.out.println(Ansi.AUTO.string(
            "@|bold,fg(green) ok|@: deploying to " + region));
    }

    public static void main(String[] args) {
        System.exit(new CommandLine(new Deploy()).execute(args));
    }
}
JLine 3 原始模式按键读取
import org.jline.terminal.Terminal;
import org.jline.terminal.TerminalBuilder;

public class Main {
    public static void main(String[] args) throws Exception {
        try (Terminal term = TerminalBuilder.builder()
                .jansi(true)     // bridge to Jansi on Windows
                .system(true)    // attach to controlling TTY
                .build()) {

            Terminal.SignalHandler prev = term.handle(Terminal.Signal.INT, sig -> System.exit(0));
            term.enterRawMode();
            term.writer().println("press any key (q to quit):");
            term.writer().flush();

            int c;
            while ((c = term.reader().read()) != 'q') {
                term.writer().printf("0x%02x %n", c);
                term.writer().flush();
            }
        }
    }
}

相关序列

其他语言