为Goploy写一款Jetbrains插件

原创
2023/07/25 16:11
阅读数 74

Goploy

目前已经可以在Jetbrains全家桶的插件市场中搜索到。

为什么我要做这个插件

发布项目要经常在idea与浏览器之间切换,很不爽,于是决定把goploy发布项目功能搬进jetbrains全家桶

下面给大家介绍一下插件从0到1的编写流程以及在查阅官方文档时的一些心得体会。

插件开发

一开始图省事儿,想直接根据网友的插件开发经验来做,但发现要么资料过时,要么是跟着做了不成功,最后索性直接找官方文档了。

因此这个小插件90%的时间都花在了阅读官方文档上了。

网上说得很多种插件开发方式,我只说一种,避免大家迷糊,按我教程做,至少能动起来,剩下的就是靠大家自己填充内容了。

使用Gradle开发

创建后,等待项目初始化完成。

修改plugin.xml

找到对应的位置加上<toolWindow factoryClass="com.example.toolwindow.ToolWindowFactory" id="Goploy" />

拷贝最小化代码到ToolWindowFactory

package com.example.toolwindow

import com.intellij.icons.AllIcons import com.intellij.openapi.diagnostic.thisLogger import com.intellij.openapi.project.Project import com.intellij.openapi.wm.ToolWindow import com.intellij.openapi.wm.ToolWindowFactory import com.intellij.ui.ColoredTreeCellRenderer import com.intellij.ui.SimpleTextAttributes import com.intellij.ui.TreeSpeedSearch import com.intellij.ui.components.JBScrollPane import com.intellij.ui.content.ContentFactory import com.intellij.ui.treeStructure.Tree import java.awt.BorderLayout import java.awt.event.MouseAdapter import java.awt.event.MouseEvent import javax.swing.* import javax.swing.tree.DefaultMutableTreeNode import javax.swing.tree.DefaultTreeModel

class ToolWindowFactory : ToolWindowFactory { init { thisLogger().warn("Don't forget to remove all non-needed sample code files with their corresponding registration entries in `plugin.xml`.") }

override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) {

    val pRoot = DefaultMutableTreeNode("fake root")
    val treeModel = DefaultTreeModel(pRoot)
    val jTree = Tree(treeModel)
    val speedSearch = TreeSpeedSearch(jTree)
    pRoot.add(DefaultMutableTreeNode("fake"))

    jTree.cellRenderer = object : ColoredTreeCellRenderer() {
        override fun customizeCellRenderer(
                tree: JTree,
                value: Any?,
                selected: Boolean,
                expanded: Boolean,
                leaf: Boolean,
                row: Int,
                hasFocus: Boolean
        ) {
            if (value is DefaultMutableTreeNode) {
                val userObject = value.userObject.toString()
                // Highlight text matches
                val matchingFragments = speedSearch.matchingFragments(userObject)
                if (matchingFragments.toString().isNotEmpty()) {
                    var lastIndex = 0
                    if (matchingFragments != null) {
                        for (fragment in matchingFragments) {
                            append(userObject.substring(lastIndex, fragment.startOffset), SimpleTextAttributes.REGULAR_ATTRIBUTES)
                            append(userObject.substring(fragment.startOffset, fragment.endOffset),
                                    SimpleTextAttributes(SimpleTextAttributes.STYLE_SEARCH_MATCH, null))
                            lastIndex = fragment.endOffset
                        }
                    }
                    append(userObject.substring(lastIndex), SimpleTextAttributes.REGULAR_ATTRIBUTES)
                } else {
                    append(userObject, SimpleTextAttributes.REGULAR_ATTRIBUTES)
                }
            }
            icon = if (leaf) {
                AllIcons.Actions.Run_anything
            } else {
                AllIcons.Actions.ModuleDirectory
            }
        }
    }

    jTree.addMouseListener(object : MouseAdapter() {
        override fun mousePressed(e: MouseEvent) {
            val path = jTree.getClosestPathForLocation(e.x, e.y)
            jTree.selectionPath = path
        }

        override fun mouseReleased(e: MouseEvent) {
            val treePath = jTree.getClosestPathForLocation(e.x, e.y)
            if (treePath != null) {
                if (e.isPopupTrigger || SwingUtilities.isRightMouseButton(e)) {
                    createPopupMenu(jTree).show(jTree, e.x, e.y)
                }
            }
        }
    })

    val jBPanel = JPanel(BorderLayout())
    jBPanel.add(jTree, BorderLayout.CENTER)
    jBPanel.background = UIManager.getColor("Tree.background")
    val jBScrollPane = JBScrollPane(jBPanel)
    val content = ContentFactory.getInstance().createContent(jBScrollPane, null, false)
    toolWindow.contentManager.addContent(content)
}

fun createPopupMenu(jTree: Tree): JPopupMenu {
    val popup = JPopupMenu()
    popup.add(resultItem(jTree))
    return popup
}



private fun resultItem(jTree: Tree): JMenuItem {
    val menuItem = JMenuItem("Result", AllIcons.Actions.Preview)

    menuItem.addActionListener {
        val selectedPath = jTree.selectionPath
        if (selectedPath?.lastPathComponent is DefaultMutableTreeNode) {
            val node = selectedPath.lastPathComponent as DefaultMutableTreeNode
            println(node)
        }
    }
    return menuItem
}


override fun shouldBeAvailable(project: Project) = true

}

最小化toolwindow代码已经完成,里面包含树,ctrl+f搜索节点,右键菜单等功能。

调式插件

插件发布

 

插件上传

JetBrains Marketplace

 

dialog的参数按照提示填就行,没有特别要注意的。

完整版代码

goploy-devops/goploy-jetbrains (github.com)

大家看着cv就行,里面有接口访问,config参数储存,toolbar action,自定义dialog。

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
0 评论
0 收藏
0
分享
返回顶部
顶部