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

IntelliJ插件开发:如何实现编辑器内多行内联文本显示

在IntelliJ编辑器中实现多行自动换行的内联文本

问题分析

你尝试用EditorCustomElementRenderer添加块元素,但drawString只能处理单行文本,直接用JBTextArea无法在paint方法中直接绘制——因为Swing组件的绘制依赖自身布局上下文,和编辑器的Inlay绘制逻辑不兼容。

可行解决方案

放弃使用JBTextArea,改为手动处理文本换行+逐行绘制,同时正确实现自定义元素的宽高计算,确保编辑器排版正常。

修改后的实现代码

import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorColorsScheme;
import com.intellij.openapi.editor.EditorFontType;
import com.intellij.openapi.editor.Inlay;
import com.intellij.openapi.editor.TextAttributes;
import org.jetbrains.annotations.NotNull;

import java.awt.*;
import java.awt.font.FontMetrics;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

public class MultilineInlayRenderer implements EditorCustomElementRenderer {
    private final List<String> wrappedLines;
    private final Color textColor;
    private final Font editorFont;
    private final int lineHeight;

    public MultilineInlayRenderer(String content, Color color, Editor editor) {
        this.textColor = color;
        EditorColorsScheme scheme = editor.getColorsScheme();
        this.editorFont = scheme.getFont(EditorFontType.PLAIN);
        this.lineHeight = editor.getLineHeight();
        
        // 根据编辑器可用宽度,提前计算好换行后的文本行(留40px边距避免贴边)
        int maxLineWidth = editor.getContentComponent().getWidth() - 40;
        this.wrappedLines = wrapTextToFitWidth(content, editorFont, maxLineWidth);
    }

    /**
     * 将文本按指定宽度分割成多行,优先在单词边界换行
     */
    private List<String> wrapTextToFitWidth(String content, Font font, int maxWidth) {
        List<String> lines = new ArrayList<>();
        if (content.isEmpty()) return lines;

        FontMetrics metrics = new JPanel().getFontMetrics(font);
        StringBuilder currentLine = new StringBuilder();
        StringTokenizer tokenizer = new StringTokenizer(content, " \n", true);

        while (tokenizer.hasMoreTokens()) {
            String token = tokenizer.nextToken();

            // 遇到换行符直接换行
            if ("\n".equals(token)) {
                lines.add(currentLine.toString().trim());
                currentLine.setLength(0);
                continue;
            }

            int currentLineWidth = metrics.stringWidth(currentLine.toString());
            int tokenWidth = metrics.stringWidth(token);

            // 当前行加token超过宽度时,先提交当前行再添加token
            if (currentLineWidth + tokenWidth > maxWidth && currentLine.length() > 0) {
                lines.add(currentLine.toString().trim());
                currentLine.setLength(0);
            }

            currentLine.append(token);
        }

        // 添加最后一行内容
        if (!currentLine.isEmpty()) {
            lines.add(currentLine.toString().trim());
        }
        return lines;
    }

    @Override
    public void paint(@NotNull Inlay inlay, @NotNull Graphics graphics, @NotNull Rectangle targetRegion, @NotNull TextAttributes textAttributes) {
        Editor editor = inlay.getEditor();
        graphics.setFont(editorFont);
        graphics.setColor(textColor);

        int currentY = targetRegion.y + editor.getAscent();
        int startX = targetRegion.x + 2; // 左内边距

        for (String line : wrappedLines) {
            graphics.drawString(line, startX, currentY);
            currentY += lineHeight;
        }
    }

    @Override
    public int calcWidthInPixels(@NotNull Inlay inlay) {
        // 计算所有行中的最大宽度,加上左右内边距
        FontMetrics metrics = inlay.getEditor().getContentComponent().getFontMetrics(editorFont);
        int maxWidth = 0;
        for (String line : wrappedLines) {
            maxWidth = Math.max(maxWidth, metrics.stringWidth(line));
        }
        return maxWidth + 4;
    }

    @Override
    public int calcHeightInPixels(@NotNull Inlay inlay) {
        // 总高度 = 行数 × 编辑器行高 + 上下内边距
        return wrappedLines.size() * lineHeight + 4;
    }
}

关键说明

  1. 文本换行逻辑:通过FontMetrics计算文本宽度,在单词边界或换行符处分割文本,避免切断单词。
  2. 尺寸计算:必须实现calcWidthInPixels和calcHeightInPixels,让编辑器知道自定义元素的准确大小,防止覆盖其他内容或排版错乱。
  3. 绘制细节:添加内边距优化显示效果,使用编辑器自带的字体和行高,保持与编辑器风格统一。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 11:55:22