You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用非公开类jdk.jshell.CompletenessAnalyzer实现自定义JShell自动补全?

基于JShell实现自定义Shell的命令自动补全方案

一、自定义命令自动补全实现

JShell原生Tab补全仅针对Java代码,要实现自定义命令的补全,需手动处理输入事件(Scanner无法捕获Tab键),推荐使用java.io.Console读取输入,结合自定义命令列表实现补全逻辑:

核心思路

  • 用Console替代Scanner,支持读取单个字符以捕获Tab键(ASCII码为9)
  • 维护自定义命令集合,匹配用户输入前缀生成补全候选
  • 处理Tab输入时,输出匹配的补全选项或自动补全唯一匹配项

修改后的示例代码

import jdk.jshell.JShell;
import java.io.Console;
import java.util.ArrayList;
import java.util.List;

public class CustomShell {
    private static JShell jshell;
    private static final List<String> CUSTOM_COMMANDS = List.of("/exit", "/help", "/clear", "/list");

    public static void main(String[] args) {
        jshell = JShell.create();
        Console console = System.console();
        if (console == null) {
            System.err.println("无法获取控制台,请在终端中运行程序");
            System.exit(1);
        }

        System.out.println("Custom Shell");
        System.out.println("Type '/exit' to exit the shell");

        StringBuilder inputBuffer = new StringBuilder();
        while (true) {
            console.printf("> ");
            int charCode;
            try {
                charCode = System.in.read();
            } catch (Exception e) {
                break;
            }

            if (charCode == '\n' || charCode == '\r') {
                // 处理回车,执行命令
                String userInput = inputBuffer.toString().trim();
                inputBuffer.setLength(0);
                if (userInput.equals("/exit")) {
                    break;
                }
                executeCommand(userInput);
            } else if (charCode == 9) { // Tab键触发补全
                handleTabCompletion(inputBuffer, console);
            } else {
                // 普通字符追加到输入缓冲区并回显
                inputBuffer.append((char) charCode);
                console.printf("%c", (char) charCode);
            }
        }

        jshell.close();
    }

    private static void handleTabCompletion(StringBuilder inputBuffer, Console console) {
        String prefix = inputBuffer.toString().trim();
        List<String> matches = new ArrayList<>();
        for (String cmd : CUSTOM_COMMANDS) {
            if (cmd.startsWith(prefix)) {
                matches.add(cmd);
            }
        }

        if (matches.isEmpty()) {
            console.printf("\t");
            return;
        }

        if (matches.size() == 1) {
            // 唯一匹配,自动补全剩余部分
            String completion = matches.get(0).substring(prefix.length());
            inputBuffer.append(completion);
            console.printf("%s", completion);
        } else {
            // 多个匹配,换行输出所有候选
            console.printf("\n");
            for (String match : matches) {
                console.printf("%s\n", match);
            }
            console.printf("> %s", inputBuffer);
        }
    }

    private static void executeCommand(String command) {
        jshell.eval(command).forEach(System.out::println);
    }
}

二、非公开类jdk.jshell.CompletenessAnalyzer的使用

CompletenessAnalyzer是JShell内部用于分析代码完整性的非公开类,需通过反射调用,注意该类的API在不同JDK版本可能存在变动:

核心用法

  1. 通过反射获取类实例:依赖JShell内部的JShell.State对象
  2. 调用analyze方法判断输入代码是否为完整的Java语句/表达式

反射调用示例代码

import jdk.jshell.JShell;
import java.lang.reflect.Method;
import java.lang.reflect.Field;

public class CompletenessAnalyzerDemo {
    public static void main(String[] args) throws Exception {
        JShell jshell = JShell.create();

        // 获取JShell内部的state字段
        Field stateField = JShell.class.getDeclaredField("state");
        stateField.setAccessible(true);
        Object state = stateField.get(jshell);

        // 获取CompletenessAnalyzer类并创建实例
        Class<?> analyzerClass = Class.forName("jdk.jshell.CompletenessAnalyzer");
        Object analyzer = analyzerClass.getConstructor(state.getClass()).newInstance(state);

        // 获取analyze方法并调用
        Method analyzeMethod = analyzerClass.getMethod("analyze", String.class);
        Object result = analyzeMethod.invoke(analyzer, "List<String> list = new Array");

        // 解析结果枚举
        Class<?> resultEnum = Class.forName("jdk.jshell.CompletenessAnalyzer$Result");
        System.out.println("代码完整性状态:" + resultEnum.cast(result).name());
    }
}

注意事项

  • 非公开类无官方兼容性保证,升级JDK时需验证逻辑是否可用
  • 若仅需判断输入是否可执行,也可直接调用JShell.eval捕获异常,但CompletenessAnalyzer能提前判断代码完整性,避免不必要的执行

内容的提问来源于stack exchange,提问作者mah454

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 00:23:21