跳到主内容
文章阅读

Idea插件开发技巧

2025/12/1678 次阅读9 分钟

高亮代码


    /**
     * 高亮代码段转html
     */
    fun highlightCodeToHtml(code: String, project: Project, lang: Language): String {
        val s = StringBuilder()
        val sb = HtmlSyntaxInfoUtil.appendHighlightedByLexerAndEncodedAsHtmlCodeSnippet(
            s,
            project,
            lang,
            code,
            true,
            0.65f
        )
        return sb.toString()
    }

JBList常见用法


ScrollingUtil.installActions(this)
//右键选中
ListUiUtil.Selection.installSelectionOnRightClick(this)

ListUiUtil.Selection.installSelectionOnFocus(this)
//注册右键菜单
PopupHandler.installPopupMenu(this, rightMenuAction, "Right Menu")
TreeUIHelper.getInstance().installListSpeedSearch(this) { o -> o.api }

//触发搜索关键字
SpeedSearchUtil.applySpeedSearchHighlighting(list, this, false, selected)

JTree


// 安装右键操作
CustomizationUtil.installPopupHandler(
            this, "flutter-l10n-right-menu", "Flutter l10n"
        )
//快速搜索
TreeUIHelper.getInstance().installTreeSpeedSearch(this)
//自动展开收缩子树
SmartExpander.installOn(this)
//增强操作
TreeHoverListener.DEFAULT.addTo(this)
//安装常用操作
TreeUtil.installActions(this)

拷贝文字到剪贴板

可以使用idea plugin 内置的SDK来进行处理


import java.awt.datatransfer.StringSelection
import com.intellij.openapi.ide.CopyPasteManager
//拷贝文本
fun copy(text: String) {
    CopyPasteManager.getInstance().setContents(StringSelection(text))
}

内联操作

在内部弹窗菜单添加内部操作 就是在这个位置添加操作 image.png 在plugin.xml添加



<extensions defaultExtensionNs="com.intellij">
    <intentionAction>
        <className>shop.itbug.salvorstool.intention.CopyAntdTableColumnAction</className>
        <language>Rust</language>
    </intentionAction>
</extensions>

需要两个参数languageclassName,className需要实现IntentionAction接口,如果操作PsiElement,可以继承 PsiElementBaseIntentionAction这个类,但是IntentionAction也要实现

举个例子

这个功能是实现Rust Struct生成antd table columns的模板并拷贝到剪贴板



class CopyAntdTableColumnAction : PsiElementBaseIntentionAction(), IntentionAction {

    override fun getFamilyName(): String {
        return "Copy Antd Table Column"
    }
    override fun getText(): String {
        return familyName
    }
    override fun isAvailable(project: Project, editor: Editor?, element: PsiElement): Boolean {
        return element.parent is RsStructItemImpl
    }
    override fun invoke(project: Project, editor: Editor?, element: PsiElement) {
        val rs = element.parent as? RsStructItemImpl ?: return
        val manager = rs.myManager
        val sb = StringBuilder()
        sb.appendLine("[")
        manager.jsModelList.map {
            sb.append("\
\	\	")
            sb.append(it.antdTableColumnItem)
            sb.append(",\
")
        }
        sb.appendLine("]")
        CopyPasteManager.getInstance().setContents(StringSelection(sb.toString()))
    }

}

获取编辑器的字体


Font font = EditorColorsManager . getInstance ().globalScheme.getFont(EditorFontType.PLAIN)

Searcheverywhere

就是在这个位置注入一个搜索选项tab栏目 image.png 实现searchEverywhereContributor扩展



<searchEverywhereContributor implementation="shop.itbug.salvorstool.searcheverywhere.SalvoSearchApi"/>

demo



fun fetchApiList(project: Project): List<SalvoApiItem> {
    return runReadAction {
        return@runReadAction FinderApiManager(project).findAllApiList()
    }
}

class SalvoSearchApi : SearchEverywhereContributorFactory<SalvoApiItem> {

    override fun createContributor(initEvent: AnActionEvent): SearchEverywhereContributor<SalvoApiItem> {
        return MySearchEverywhereProvider(initEvent.project!!)
    }

    override fun isAvailable(project: Project?): Boolean {
        return project != null
    }

    @OptIn(DelicateCoroutinesApi::class)
    private inner class MySearchEverywhereProvider(val project: Project) : SearchEverywhereContributor<SalvoApiItem> {

        var allApi: List<SalvoApiItem> = emptyList()

        init {
            val job = GlobalScope.launch {
                val result = async { fetchApiList(project) }.await()
                allApi = result
            }
            GlobalScope.launch {
                job.join()
            }
        }

        override fun getSearchProviderId(): String {
            return MySearchEverywhereProvider::class.java.name
        }

        override fun getGroupName(): String {
            return "Salvo"
        }

        override fun getSortWeight(): Int {
            return Integer.MAX_VALUE
        }

        override fun showInFindResults(): Boolean {
            return true
        }

        override fun getElementsRenderer(): ListCellRenderer<in SalvoApiItem> {
            return SalvoApiItemRender()
        }

        override fun getDataForItem(element: SalvoApiItem, dataId: String): Any? {
            return null
        }

        override fun processSelectedItem(selected: SalvoApiItem, modifiers: Int, searchText: String): Boolean {
            selected.navTo(project)
            return true
        }

        override fun fetchElements(
            pattern: String,
            progressIndicator: ProgressIndicator,
            consumer: Processor<in SalvoApiItem>
        ) {
            val list = if (pattern.isEmpty()) allApi else allApi.filter { it.api.contains(pattern) }
            list.forEach {
                if (consumer.process(it).not()) {
                    return
                }
            }
        }

        override fun isShownInSeparateTab(): Boolean {
            return true
        }

    }
}

2024年06月26日09:03:18 更新

同步执行耗时操作


ProgressManager.getInstance().runProcessWithProgressSynchronously({
    println("---")
    Thread.sleep(3000)
}, "执行中", false, null)

执行系统级命令行操作


GeneralCommandLine commandLine =
new GeneralCommandLine (getOptions().getScriptName());
OSProcessHandler processHandler = ProcessHandlerFactory . getInstance ()
    .createColoredProcessHandler(commandLine);
ProcessTerminatedListener.attach(processHandler); //启动run窗口执行

保存所有文档

如果文件被修改后没有马上被触发,需要执行一下这个函数


FileDocumentManager.getInstance().saveAllDocuments()

其他待补充

返回顶部