CodeLocator 应该是我平时工作中使用频率最高的idea插件了,只可惜不适配K2 mode
这里有idea的官方文档 教你怎么做插件适配
之前我是clone了codelocator的源码 想自己改一下的,结果高估了自己的能力,各种编译连环报错弄的比较恼人
直到前几天看到 有人提供了这个方案
这个方案挺不错的,另辟蹊径了,而且我试了一下,这个方案几乎能适配所有的 idea plugin 到k2 mode
恩,考虑了一下,写个简单的程序 处理下就好 , 考虑到很多人可能没有python环境 那就直接go来写吧, 直接编译出对应3个平台的可执行程序多好,拿来即用
然后cursor很快就帮我做好了
package main
import (
"archive/zip"
"bytes"
"flag"
"fmt"
"io"
"os"
"path/filepath"
"strings"
)
func main() {
// 解析命令行参数
zipPath := flag.String("zip", "", "zip文件的绝对路径")
flag.Parse()
if *zipPath == "" {
fmt.Println("请使用 -zip 参数指定zip文件的绝对路径")
return
}
// 打开源zip文件
reader, err := zip.OpenReader(*zipPath)
if err != nil {
fmt.Printf("打开zip文件失败: %v\n", err)
return
}
defer reader.Close()
// 找到CodeLocatorPlugin开头的jar文件
var targetJar *zip.File
for _, file := range reader.File {
// 获取文件名(不包含路径)
fileName := filepath.Base(file.Name)
if strings.HasPrefix(fileName, "CodeLocatorPlugin") && strings.HasSuffix(fileName, ".jar") {
targetJar = file
break
}
}
if targetJar == nil {
fmt.Println("未找到以CodeLocatorPlugin开头的jar文件")
return
}
// 读取jar文件内容
jarReader, err := targetJar.Open()
if err != nil {
fmt.Printf("打开jar文件失败: %v\n", err)
return
}
defer jarReader.Close()
// 将jar文件内容读入内存
jarContent := new(bytes.Buffer)
if _, err := io.Copy(jarContent, jarReader); err != nil {
fmt.Printf("读取jar文件内容失败: %v\n", err)
return
}
// 创建新的zip reader来读取jar内容
jarZipReader, err := zip.NewReader(bytes.NewReader(jarContent.Bytes()), int64(jarContent.Len()))
if err != nil {
fmt.Printf("创建jar文件reader失败: %v\n", err)
return
}
// 创建新的jar文件内容
newJarContent := new(bytes.Buffer)
jarWriter := zip.NewWriter(newJarContent)
// 遍历jar中的所有文件
pluginXmlFound := false
for _, file := range jarZipReader.File {
// 获取文件名(不包含路径)
fileName := filepath.Base(file.Name)
if fileName == "plugin.xml" {
// 处理plugin.xml文件
pluginXmlFound = true
if err := processPluginXml(file, jarWriter); err != nil {
fmt.Printf("处理plugin.xml失败: %v\n", err)
return
}
} else {
// 复制其他文件
if err := copyFileInZip(file, jarWriter); err != nil {
fmt.Printf("复制文件失败 %s: %v\n", file.Name, err)
return
}
}
}
if !pluginXmlFound {
fmt.Println("在jar文件中未找到plugin.xml")
return
}
// 关闭jar writer
if err := jarWriter.Close(); err != nil {
fmt.Printf("关闭jar writer失败: %v\n", err)
return
}
// 创建新的zip文件
newZipPath := strings.TrimSuffix(*zipPath, ".zip") + "k2.zip"
newZipFile, err := os.Create(newZipPath)
if err != nil {
fmt.Printf("创建新的zip文件失败: %v\n", err)
return
}
defer newZipFile.Close()
// 创建新的zip writer
zipWriter := zip.NewWriter(newZipFile)
defer zipWriter.Close()
// 将修改后的jar文件写入新的zip(保持原始路径)
w, err := zipWriter.CreateHeader(&zip.FileHeader{
Name: targetJar.Name, // 保持原始完整路径
Method: zip.Deflate,
Modified: targetJar.Modified,
})
if err != nil {
fmt.Printf("创建jar文件在zip中失败: %v\n", err)
return
}
if _, err := io.Copy(w, bytes.NewReader(newJarContent.Bytes())); err != nil {
fmt.Printf("写入新的jar文件失败: %v\n", err)
return
}
// 复制其他文件到新的zip
for _, file := range reader.File {
if file.Name != targetJar.Name {
if err := copyFileInZip(file, zipWriter); err != nil {
fmt.Printf("复制文件失败 %s: %v\n", file.Name, err)
return
}
}
}
fmt.Printf("成功创建新的zip文件: %s\n", newZipPath)
}
// 处理plugin.xml文件
func processPluginXml(file *zip.File, zipWriter *zip.Writer) error {
// 读取原始plugin.xml内容
rc, err := file.Open()
if err != nil {
return fmt.Errorf("打开plugin.xml失败: %v", err)
}
defer rc.Close()
content := new(bytes.Buffer)
if _, err := io.Copy(content, rc); err != nil {
return fmt.Errorf("读取plugin.xml内容失败: %v", err)
}
// 在文件末尾添加新的扩展配置
// 在</idea-plugin>之前插入新的扩展
newContent := strings.Replace(
content.String(),
"</idea-plugin>",
` <extensions defaultExtensionNs="org.jetbrains.kotlin">
<supportsKotlinPluginMode supportsK1="true" supportsK2="true" />
</extensions>
</idea-plugin>`,
1,
)
// 创建新的plugin.xml文件(保持原始路径)
writer, err := zipWriter.CreateHeader(&zip.FileHeader{
Name: file.Name, // 保持原始完整路径
Method: zip.Deflate,
Modified: file.Modified,
})
if err != nil {
return fmt.Errorf("创建新的plugin.xml失败: %v", err)
}
if _, err := writer.Write([]byte(newContent)); err != nil {
return fmt.Errorf("写入新的plugin.xml内容失败: %v", err)
}
return nil
}
// 在zip文件中复制文件
func copyFileInZip(file *zip.File, zipWriter *zip.Writer) error {
// 创建新的文件头
writer, err := zipWriter.CreateHeader(&zip.FileHeader{
Name: file.Name, // 保持原始完整路径
Method: file.Method,
Modified: file.Modified,
})
if err != nil {
return err
}
// 打开源文件
reader, err := file.Open()
if err != nil {
return err
}
defer reader.Close()
// 复制内容
_, err = io.Copy(writer, reader)
return err
}
甚至很贴心的帮我写了mk 和 readme
# Makefile
# Go source file
SRC = main.go
# Output directories
OUT_DIR = bin
# Executable names
WIN_EXEC = $(OUT_DIR)/main.exe
LINUX_EXEC = $(OUT_DIR)/main-linux
MAC_EXEC = $(OUT_DIR)/main-mac
# Build targets
all: windows linux mac
windows:
GOOS=windows GOARCH=amd64 go build -o $(WIN_EXEC) $(SRC)
linux:
GOOS=linux GOARCH=amd64 go build -o $(LINUX_EXEC) $(SRC)
mac:
GOOS=darwin GOARCH=amd64 go build -o $(MAC_EXEC) $(SRC)
clean:
rm -rf $(OUT_DIR)
.PHONY: all windows linux mac clean
不得不感慨下 时代变了