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

Eclipse中Set Style Range功能未按预期生效问题排查

Eclipse插件插入文本后样式立即消失的解决方案

我们开发了一款Eclipse插件,可从第三方API获取数据并插入至Eclipse编辑器中,需要为插入内容应用特定样式,且该样式需保留至用户执行下一个操作(如按键)。目前文本插入与初始样式应用均正常,但样式会立即消失。尝试用timerExec定时重新设置样式只是临时手段,并非可行方案。

原代码如下:

public Object execute(ExecutionEvent event) throws ExecutionException {
    
    IEditorPart editor = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor();

    if (!(editor instanceof ITextEditor))
        return null;

    try {
        final ITextEditor textEditor = (ITextEditor) editor;
        final IDocument document = textEditor.getDocumentProvider().getDocument(textEditor.getEditorInput());

        final ITextViewer iTextViewer = (ITextViewer) textEditor.getAdapter(ITextViewer.class);
        if (iTextViewer == null) {
            return null;
        }

        styledText = iTextViewer.getTextWidget();
        int insertPosition = styledText.getCaretOffset();


        RestPayload job = new RestPayload();
        job.addJobChangeListener(new JobChangeAdapter() {
            @Override
            public void done(IJobChangeEvent event) {
                if (event.getResult() != null) {
                    IStatus result = event.getResult();
                    Display.getDefault().asyncExec(() -> {
                        if (result.isOK()) {

                            try {
                                String generatedCode = job.getPayload();
                                document.replace(insertPosition, 0, generatedCode);
                                suggestionStyle = new StyleRange();
                                suggestionStyle.start = insertPosition;
                                suggestionStyle.foreground = new Color(Display.getDefault(), 192, 192, 192);
                                suggestionStyle.length = generatedCode.length();
                                styledText.setStyleRange(suggestionStyle);
                                styledText.update();

                                Display.getDefault().timerExec(2000, () -> {
                                    styledText.setStyleRange(suggestionStyle);
                                    styledText.redraw();

                                }); 

                            } catch (Exception ex) {
                                logger.warn("Error inserting/styling code", ex);
                            }
                        } else {
                            showAlert("Code Assist Error", "Code assist failed: " + result.getMessage());
                        }
                    });
                }
            }
        });

        job.schedule();

    } catch (Throwable eGenThrowable) {
        showAlert("Issue", eGenThrowable.getMessage());
        eGenThrowable.printStackTrace();
        logger.warn("Issue while exchanging data", eGenThrowable);
    }

    return styledText;
}

问题原因

直接给StyledText设置StyleRange后,Eclipse编辑器的文档提供者或语法高亮组件会在文档变更后重新计算并应用默认样式,覆盖手动设置的样式。StyledText的样式并非持久绑定在文档上,编辑器的自动刷新会重置这些样式。

解决方案

通过添加文本展示监听器确保样式持续生效,同时监听用户按键操作触发样式清除,具体实现如下:

// 类成员变量,用于保存样式和监听器引用
private StyleRange suggestionStyle;
private int styleStart;
private int styleLength;
private ITextPresentationListener presentationListener;
private KeyListener keyListener;

public Object execute(ExecutionEvent event) throws ExecutionException {
    
    IEditorPart editor = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor();

    if (!(editor instanceof ITextEditor))
        return null;

    try {
        final ITextEditor textEditor = (ITextEditor) editor;
        final IDocument document = textEditor.getDocumentProvider().getDocument(textEditor.getEditorInput());

        final ITextViewer iTextViewer = (ITextViewer) textEditor.getAdapter(ITextViewer.class);
        if (iTextViewer == null) {
            return null;
        }

        final StyledText styledText = iTextViewer.getTextWidget();
        final int insertPosition = styledText.getCaretOffset();


        RestPayload job = new RestPayload();
        job.addJobChangeListener(new JobChangeAdapter() {
            @Override
            public void done(IJobChangeEvent event) {
                if (event.getResult() != null) {
                    IStatus result = event.getResult();
                    Display.getDefault().asyncExec(() -> {
                        if (result.isOK()) {

                            try {
                                String generatedCode = job.getPayload();
                                document.replace(insertPosition, 0, generatedCode);
                                
                                // 保存样式基础信息
                                styleStart = insertPosition;
                                styleLength = generatedCode.length();
                                suggestionStyle = new StyleRange();
                                suggestionStyle.start = styleStart;
                                suggestionStyle.foreground = new Color(Display.getDefault(), 192, 192, 192);
                                suggestionStyle.length = styleLength;

                                // 创建文本展示监听器,确保样式在编辑器刷新时不被覆盖
                                presentationListener = new ITextPresentationListener() {
                                    @Override
                                    public void applyTextPresentation(TextPresentation textPresentation, int offset, int length) {
                                        textPresentation.addStyleRange(suggestionStyle);
                                    }
                                };
                                iTextViewer.addTextPresentationListener(presentationListener);

                                // 创建按键监听器,用户操作时清除样式并释放资源
                                keyListener = new KeyAdapter() {
                                    @Override
                                    public void keyPressed(KeyEvent e) {
                                        // 移除监听器
                                        iTextViewer.removeTextPresentationListener(presentationListener);
                                        styledText.removeKeyListener(this);
                                        // 清除样式
                                        suggestionStyle.length = 0;
                                        styledText.setStyleRange(suggestionStyle);
                                        styledText.redraw();
                                        // 释放Color资源,避免内存泄漏
                                        suggestionStyle.foreground.dispose();
                                    }
                                };
                                styledText.addKeyListener(keyListener);

                                // 初始应用样式
                                styledText.setStyleRange(suggestionStyle);
                                styledText.update();

                            } catch (Exception ex) {
                                logger.warn("Error inserting/styling code", ex);
                                // 异常时清理资源
                                if (presentationListener != null) {
                                    iTextViewer.removeTextPresentationListener(presentationListener);
                                }
                                if (keyListener != null) {
                                    styledText.removeKeyListener(keyListener);
                                }
                                if (suggestionStyle != null && suggestionStyle.foreground != null) {
                                    suggestionStyle.foreground.dispose();
                                }
                            }
                        } else {
                            showAlert("Code Assist Error", "Code assist failed: " + result.getMessage());
                        }
                    });
                }
            }
        });

        job.schedule();

    } catch (Throwable eGenThrowable) {
        showAlert("Issue", eGenThrowable.getMessage());
        eGenThrowable.printStackTrace();
        logger.warn("Issue while exchanging data", eGenThrowable);
    }

    return null;
}

说明

  • ITextPresentationListener会在编辑器每次准备渲染文本时被调用,将自定义样式添加到文本展示队列中,避免被默认样式覆盖。
  • 按键监听器捕获用户的任何按键操作,触发后立即清理样式和监听器,符合“样式保留至用户下一个操作”的需求。
  • 注意手动创建的Color对象需要在不再使用时调用dispose(),防止内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 22:47:12