IntelliJ插件开发:获取OSProcessHandler执行系统命令的输出
解决方法
核心逻辑是给OSProcessHandler注册自定义的输出监听器,在输出流向控制台之前拦截捕获内容,存为字符串完成解析后,再执行控制台输出、菜单生成的后续逻辑,不要在创建handler后立刻直接绑定ConsoleView,否则无法插入自定义解析逻辑。
具体实现调整点:
- 新增StringBuilder变量缓存进程的全量输出,可按需区分标准输出、错误输出分别存储
- 给
OSProcessHandler添加ProcessAdapter类型的监听器,重写onTextAvailable方法逐行接收输出内容,追加到缓存的StringBuilder中 - 重写监听器的
processTerminated方法,在进程执行结束后拿到完整的输出字符串,先执行自定义解析逻辑、生成对应菜单 - 解析逻辑执行完成后,再将输出内容打印到ConsoleView;如果不需要做输出内容修改,也可以在逐行接收输出的时候同步透传给控制台,不会影响前置拦截解析的逻辑
- 所有Swing相关的UI操作(生成菜单、操作ToolWindow/Console组件)必须切到EDT线程执行,避免UI线程阻塞异常
修改后的核心实现代码如下:
public class MyClass extends AnAction { private static ConsoleView view = null; private static ToolWindow window = null; @Override public void actionPerformed(@NotNull AnActionEvent e) { Project project = CommonDataKeys.PROJECT.getData(e.getDataContext()); if (project == null) return; GeneralCommandLine generalCommandLine = new GeneralCommandLine(getAccounts()); generalCommandLine.setCharset(Charset.forName("UTF-8")); OSProcessHandler processHandler = null; try { processHandler = new OSProcessHandler(generalCommandLine); } catch (ExecutionException ex) { throw new RuntimeException(ex); } // 初始化控制台组件 if (view == null) { TextConsoleBuilderFactory factory = TextConsoleBuilderFactory.getInstance(); TextConsoleBuilder builder = factory.createBuilder(project); view = builder.getConsole(); } // 缓存进程全量输出 StringBuilder outputCache = new StringBuilder(); // 注册监听器拦截输出 processHandler.addProcessListener(new ProcessAdapter() { @Override public void onTextAvailable(@NotNull ProcessEvent event, @NotNull Key outputType) { // 过滤系统类提示输出,可按需调整过滤规则 if (outputType == ProcessOutputTypes.STDOUT || outputType == ProcessOutputTypes.STDERR) { String text = event.getText(); outputCache.append(text); // 实时透传输出到控制台,无感知延迟 view.print(text, outputType); } } @Override public void processTerminated(@NotNull ProcessEvent event) { String fullOutput = outputCache.toString(); // 此处执行输出解析逻辑 // UI操作必须切换到事件调度线程执行 ApplicationManager.getApplication().invokeLater(() -> { // 基于解析结果生成菜单的逻辑写在此处 // initMenuFromParseResult(fullOutput); // 初始化ToolWindow if (window == null) { ToolWindowManager manager = ToolWindowManager.getInstance(project); window = manager.registerToolWindow("Cat console", true, ToolWindowAnchor.BOTTOM); final ContentManager contentManager = window.getContentManager(); Content content = contentManager .getFactory() .createContent(view.getComponent(), "", false); contentManager.addContent(content); } window.show(() -> {}); }); } }); processHandler.startNotify(); } private ArrayList<String> getAccounts(){ ArrayList<String> cmds = new ArrayList<>(); cmds.add("/usr/local/bin/getaccountscmd"); cmds.add("ls"); return cmds; } }
如果执行的命令输出体量很大,不要等进程结束再做全量解析,可以在
onTextAvailable回调里做逐行流式解析,避免StringBuilder占用过多内存,同时提升交互响应速度。
内容的提问来源于stack exchange,提问作者Lucas Kauffman
相关产品推荐
相关产品推荐

