多语言编码Agent解决方案(4)-Eclipse插件实现

Eclipse插件实现:支持多语言的编码Agent集成

本部分包含Eclipse插件的完整实现,包括多语言支持、命令注册、API调用和UI集成。插件使用Java开发,基于Eclipse Plugin Development Environment (PDE)。

1. Eclipse插件目录结构

复制代码
eclipse-plugin/
├── src/                           # 源代码
│   └── com
│       └── codingagent
│           ├── Activator.java     # 插件激活器
│           ├── AgentCommands.java # 命令处理类
│           ├── ApiClient.java     # API调用工具
│           └── i18n
│               └── Messages.java  # 国际化消息类
├── META-INF/                      # 元数据
│   └── MANIFEST.MF                # 清单文件
├── plugin.xml                     # 插件配置
├── build.properties               # 构建属性
└── resources/                     # 资源文件
    └── locales/                   # 语言文件
        ├── messages.properties    # 英文(默认)
        ├── messages_zh_CN.properties # 中文
        └── messages_ja.properties # 日文

2. 国际化支持 (Messages.java)

java 复制代码
// src/com/codingagent/i18n/Messages.java
package com.codingagent.i18n;

import java.util.ResourceBundle;
import java.util.Locale;

public class Messages {
    private static ResourceBundle bundle;
    
    static {
        // 获取当前Locale
        Locale locale = Locale.getDefault();
        String lang = locale.getLanguage();
        
        // 选择语言文件
        if (lang.equals("zh")) {
            bundle = ResourceBundle.getBundle("locales.messages", Locale.SIMPLIFIED_CHINESE);
        } else if (lang.equals("ja")) {
            bundle = ResourceBundle.getBundle("locales.messages", Locale.JAPANESE);
        } else {
            bundle = ResourceBundle.getBundle("locales.messages", Locale.ENGLISH);
        }
    }
    
    public static String getString(String key) {
        try {
            return bundle.getString(key);
        } catch (Exception e) {
            return key; // 回退到key
        }
    }
    
    public static String getString(String key, Object... params) {
        String message = getString(key);
        if (params != null) {
            for (int i = 0; i < params.length; i++) {
                message = message.replace("{" + i + "}", params[i].toString());
            }
        }
        return message;
    }
}

3. 语言文件 (locales)

messages.properties (英文,默认)

复制代码
extension.activated=Coding Agent plugin activated
extension.ready=Agent Ready
extension.completing=Completing...
extension.generating=Generating...
extension.explaining=Explaining...
extension.refactoring=Refactoring...
extension.debugging=Debugging...
extension.generatingTests=Generating tests...
extension.error=Error
extension.disconnected=Disconnected
extension.connected=Coding Agent backend connected
extension.cannotConnect=Cannot connect to Coding Agent backend, please ensure the service is started

commands.complete=Agent: Complete Code
commands.generate=Agent: Generate Code
commands.explain=Agent: Explain Code
commands.refactor=Agent: Refactor Code
commands.debug=Agent: Debug Code
commands.test=Agent: Generate Tests

prompts.generateDescription=Describe the code you want to generate
prompts.generatePlaceholder=e.g., Create a REST API endpoint
prompts.selectCode=Please select code first
prompts.completeFailed=Completion failed: {0}
prompts.generateFailed=Generation failed: {0}
prompts.explainFailed=Explanation failed: {0}
prompts.refactorFailed=Refactoring failed: {0}
prompts.debugFailed=Debug failed: {0}
prompts.testFailed=Test generation failed: {0}
prompts.refactorComplete=Refactoring complete: {0}

output.explanation=Code Explanation
output.debugAnalysis=Debug Analysis
output.aiGenerated=AI Generated
output.agentSuggestion=Coding Agent Suggestion

messages_zh_CN.properties (中文)

复制代码
extension.activated=编码助手插件已激活
extension.ready=助手就绪
extension.completing=正在补全...
extension.generating=正在生成...
extension.explaining=正在解释...
extension.refactoring=正在重构...
extension.debugging=正在调试...
extension.generatingTests=正在生成测试...
extension.error=错误
extension.disconnected=未连接
extension.connected=编码助手后端已连接
extension.cannotConnect=无法连接到编码助手后端,请确保服务已启动

commands.complete=助手: 补全代码
commands.generate=助手: 生成代码
commands.explain=助手: 解释代码
commands.refactor=助手: 重构代码
commands.debug=助手: 调试代码
commands.test=助手: 生成测试

prompts.generateDescription=描述你想生成的代码
prompts.generatePlaceholder=例如:创建一个REST API端点
prompts.selectCode=请先选择代码
prompts.completeFailed=补全失败: {0}
prompts.generateFailed=生成失败: {0}
prompts.explainFailed=解释失败: {0}
prompts.refactorFailed=重构失败: {0}
prompts.debugFailed=调试失败: {0}
prompts.testFailed=测试生成失败: {0}
prompts.refactorComplete=重构完成: {0}

output.explanation=代码解释
output.debugAnalysis=调试分析
output.aiGenerated=AI生成
output.agentSuggestion=编码助手建议

messages_ja.properties (日文)

复制代码
extension.activated=コーディングエージェントプラグインが有効になりました
extension.ready=エージェント準備完了
extension.completing=補完中...
extension.generating=生成中...
extension.explaining=説明中...
extension.refactoring=リファクタリング中...
extension.debugging=デバッグ中...
extension.generatingTests=テスト生成中...
extension.error=エラー
extension.disconnected=切断
extension.connected=コーディングエージェントバックエンドに接続しました
extension.cannotConnect=コーディングエージェントバックエンドに接続できません。サービスが起動していることを確認してください

commands.complete=エージェント: コード補完
commands.generate=エージェント: コード生成
commands.explain=エージェント: コード説明
commands.refactor=エージェント: コードリファクタリング
commands.debug=エージェント: コードデバッグ
commands.test=エージェント: テスト生成

prompts.generateDescription=生成したいコードを説明してください
prompts.generatePlaceholder=例:REST APIエンドポイントを作成
prompts.selectCode=最初にコードを選択してください
prompts.completeFailed=補完失敗: {0}
prompts.generateFailed=生成失敗: {0}
prompts.explainFailed=説明失敗: {0}
prompts.refactorFailed=リファクタリング失敗: {0}
prompts.debugFailed=デバッグ失敗: {0}
prompts.testFailed=テスト生成失敗: {0}
prompts.refactorComplete=リファクタリング完了: {0}

output.explanation=コード説明
output.debugAnalysis=デバッグ分析
output.aiGenerated=AI生成
output.agentSuggestion=コーディングエージェントの提案

4. 插件激活器 (Activator.java)

java 复制代码
// src/com/codingagent/Activator.java
package com.codingagent;

import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;

public class Activator extends AbstractUIPlugin {

    public static final String PLUGIN_ID = "com.codingagent"; //$NON-NLS-1$

    private static Activator plugin;
    
    public Activator() {
    }

    @Override
    public void start(BundleContext context) throws Exception {
        super.start(context);
        plugin = this;
        System.out.println(Messages.getString("extension.activated"));
    }

    @Override
    public void stop(BundleContext context) throws Exception {
        plugin = null;
        super.stop(context);
    }

    public static Activator getDefault() {
        return plugin;
    }

    public static ImageDescriptor getImageDescriptor(String path) {
        return imageDescriptorFromPlugin(PLUGIN_ID, path);
    }
}

5. API调用工具 (ApiClient.java)

java 复制代码
// src/com/codingagent/ApiClient.java
package com.codingagent;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import org.json.JSONObject;

public class ApiClient {
    private static final String BASE_URL = "http://localhost:8000/api";
    private final String acceptLanguage;
    
    public ApiClient(String acceptLanguage) {
        this.acceptLanguage = acceptLanguage;
    }
    
    public JSONObject post(String endpoint, JSONObject requestBody) throws Exception {
        URL url = new URL(BASE_URL + endpoint);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "application/json");
        conn.setRequestProperty("Accept-Language", acceptLanguage);
        conn.setDoOutput(true);
        
        try (OutputStream os = conn.getOutputStream()) {
            byte[] input = requestBody.toString().getBytes(StandardCharsets.UTF_8);
            os.write(input, 0, input.length);
        }
        
        int responseCode = conn.getResponseCode();
        if (responseCode != 200) {
            throw new RuntimeException("HTTP error code: " + responseCode);
        }
        
        StringBuilder response = new StringBuilder();
        try (BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
            String line;
            while ((line = br.readLine()) != null) {
                response.append(line.trim());
            }
        }
        
        return new JSONObject(response.toString());
    }
    
    public JSONObject get(String endpoint) throws Exception {
        URL url = new URL(BASE_URL + endpoint);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("GET");
        conn.setRequestProperty("Accept-Language", acceptLanguage);
        
        int responseCode = conn.getResponseCode();
        if (responseCode != 200) {
            throw new RuntimeException("HTTP error code: " + responseCode);
        }
        
        StringBuilder response = new StringBuilder();
        try (BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
            String line;
            while ((line = br.readLine()) != null) {
                response.append(line.trim());
            }
        }
        
        return new JSONObject(response.toString());
    }
}

6. 命令处理类 (AgentCommands.java)

java 复制代码
// src/com/codingagent/AgentCommands.java
package com.codingagent;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.ITextEditor;
import org.json.JSONArray;
import org.json.JSONObject;
import com.codingagent.i18n.Messages;

public class AgentCommands {

    private static final ApiClient apiClient = new ApiClient(Locale.getDefault().toString());

    public static class CompleteHandler extends AbstractHandler {
        @Override
        public Object execute(ExecutionEvent event) throws ExecutionException {
            IEditorPart editor = getActiveEditor();
            if (!(editor instanceof ITextEditor)) return null;
            
            ITextEditor textEditor = (ITextEditor) editor;
            IDocument doc = getDocument(textEditor);
            int offset = getCursorOffset(textEditor);
            
            try {
                JSONObject request = new JSONObject();
                request.put("action", "complete");
                request.put("code", doc.get());
                request.put("cursor_position", offset);
                request.put("language", getLanguage(doc));
                
                JSONObject response = apiClient.post("/code", request);
                String result = response.getString("result");
                
                doc.replace(offset, 0, result);
            } catch (Exception e) {
                showError(Messages.getString("prompts.completeFailed", e.getMessage()));
            }
            return null;
        }
    }
    
    public static class GenerateHandler extends AbstractHandler {
        @Override
        public Object execute(ExecutionEvent event) throws ExecutionException {
            Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
            InputDialog dialog = new InputDialog(shell, 
                Messages.getString("prompts.generateDescription"), 
                Messages.getString("prompts.generatePlaceholder"), "", null);
            
            if (dialog.open() != InputDialog.OK) return null;
            String instruction = dialog.getValue();
            
            ITextEditor textEditor = (ITextEditor) getActiveEditor();
            IDocument doc = getDocument(textEditor);
            int offset = getCursorOffset(textEditor);
            
            try {
                JSONObject request = new JSONObject();
                request.put("action", "generate");
                request.put("instruction", instruction);
                request.put("language", getLanguage(doc));
                
                JSONObject response = apiClient.post("/code", request);
                String result = response.getString("result");
                
                doc.replace(offset, 0, result);
            } catch (Exception e) {
                showError(Messages.getString("prompts.generateFailed", e.getMessage()));
            }
            return null;
        }
    }
    
    public static class ExplainHandler extends AbstractHandler {
        @Override
        public Object execute(ExecutionEvent event) throws ExecutionException {
            String code = getSelectedCode();
            if (code.isEmpty()) {
                showWarning(Messages.getString("prompts.selectCode"));
                return null;
            }
            
            try {
                JSONObject request = new JSONObject();
                request.put("action", "explain");
                request.put("code", code);
                
                JSONObject response = apiClient.post("/code", request);
                String result = response.getString("result");
                
                showInfo(Messages.getString("output.explanation"), result);
            } catch (Exception e) {
                showError(Messages.getString("prompts.explainFailed", e.getMessage()));
            }
            return null;
        }
    }
    
    public static class RefactorHandler extends AbstractHandler {
        @Override
        public Object execute(ExecutionEvent event) throws ExecutionException {
            ITextSelection selection = getTextSelection();
            if (selection == null || selection.isEmpty()) {
                showWarning(Messages.getString("prompts.selectCode"));
                return null;
            }
            
            ITextEditor textEditor = (ITextEditor) getActiveEditor();
            IDocument doc = getDocument(textEditor);
            String code = selection.getText();
            
            try {
                JSONObject request = new JSONObject();
                request.put("action", "refactor");
                request.put("code", code);
                
                JSONObject response = apiClient.post("/code", request);
                String result = response.getString("result");
                
                doc.replace(selection.getOffset(), selection.getLength(), result);
                
                JSONArray suggestions = response.optJSONArray("suggestions");
                if (suggestions != null) {
                    showInfo(Messages.getString("prompts.refactorComplete", suggestions.toString()));
                }
            } catch (Exception e) {
                showError(Messages.getString("prompts.refactorFailed", e.getMessage()));
            }
            return null;
        }
    }
    
    public static class DebugHandler extends AbstractHandler {
        @Override
        public Object execute(ExecutionEvent event) throws ExecutionException {
            ITextEditor textEditor = (ITextEditor) getActiveEditor();
            IDocument doc = getDocument(textEditor);
            String code = doc.get();
            
            try {
                JSONObject request = new JSONObject();
                request.put("action", "debug");
                request.put("code", code);
                
                JSONObject response = apiClient.post("/code", request);
                String result = response.getString("result");
                
                showInfo(Messages.getString("output.debugAnalysis"), result);
            } catch (Exception e) {
                showError(Messages.getString("prompts.debugFailed", e.getMessage()));
            }
            return null;
        }
    }
    
    public static class TestHandler extends AbstractHandler {
        @Override
        public Object execute(ExecutionEvent event) throws ExecutionException {
            String code = getSelectedCode();
            if (code.isEmpty()) code = getDocument((ITextEditor) getActiveEditor()).get();
            
            try {
                JSONObject request = new JSONObject();
                request.put("action", "test");
                request.put("code", code);
                
                JSONObject response = apiClient.post("/code", request);
                String result = response.getString("result");
                
                // 创建新编辑器显示测试代码
                PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
                    .openEditor(new org.eclipse.ui.part.FileEditorInput(null), "org.eclipse.ui.DefaultTextEditor");
                // 注意:实际实现中需要正确创建并插入内容,此处简化
                showInfo(Messages.getString("output.aiGenerated"), result);
            } catch (Exception e) {
                showError(Messages.getString("prompts.testFailed", e.getMessage()));
            }
            return null;
        }
    }
    
    // 辅助方法
    private static IEditorPart getActiveEditor() {
        return PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor();
    }
    
    private static IDocument getDocument(ITextEditor editor) {
        IDocumentProvider provider = editor.getDocumentProvider();
        return provider.getDocument(editor.getEditorInput());
    }
    
    private static int getCursorOffset(ITextEditor editor) {
        ISelection selection = editor.getSelectionProvider().getSelection();
        if (selection instanceof ITextSelection) {
            return ((ITextSelection) selection).getOffset();
        }
        return 0;
    }
    
    private static String getSelectedCode() {
        ISelection selection = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getSelectionService().getSelection();
        if (selection instanceof ITextSelection) {
            return ((ITextSelection) selection).getText();
        }
        return "";
    }
    
    private static ITextSelection getTextSelection() {
        ISelection selection = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getSelectionService().getSelection();
        if (selection instanceof ITextSelection) {
            return (ITextSelection) selection;
        }
        return null;
    }
    
    private static String getLanguage(IDocument doc) {
        // 简化:假设从文件扩展或内容推断
        return "java"; // 默认
    }
    
    private static void showError(String message) {
        MessageDialog.openError(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), Messages.getString("extension.error"), message);
    }
    
    private static void showWarning(String message) {
        MessageDialog.openWarning(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), "Warning", message);
    }
    
    private static void showInfo(String title, String message) {
        MessageDialog.openInformation(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), title, message);
    }
}

7. 插件配置 (plugin.xml)

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
   <extension point="org.eclipse.ui.commands">
      <category
            id="com.codingagent.category"
            name="Coding Agent">
      </category>
      <command
            categoryId="com.codingagent.category"
            id="com.codingagent.complete"
            name="%commands.complete">
      </command>
      <command
            categoryId="com.codingagent.category"
            id="com.codingagent.generate"
            name="%commands.generate">
      </command>
      <command
            categoryId="com.codingagent.category"
            id="com.codingagent.explain"
            name="%commands.explain">
      </command>
      <command
            categoryId="com.codingagent.category"
            id="com.codingagent.refactor"
            name="%commands.refactor">
      </command>
      <command
            categoryId="com.codingagent.category"
            id="com.codingagent.debug"
            name="%commands.debug">
      </command>
      <command
            categoryId="com.codingagent.category"
            id="com.codingagent.test"
            name="%commands.test">
      </command>
   </extension>
   <extension point="org.eclipse.ui.handlers">
      <handler
            class="com.codingagent.AgentCommands$CompleteHandler"
            commandId="com.codingagent.complete">
      </handler>
      <handler
            class="com.codingagent.AgentCommands$GenerateHandler"
            commandId="com.codingagent.generate">
      </handler>
      <handler
            class="com.codingagent.AgentCommands$ExplainHandler"
            commandId="com.codingagent.explain">
      </handler>
      <handler
            class="com.codingagent.AgentCommands$RefactorHandler"
            commandId="com.codingagent.refactor">
      </handler>
      <handler
            class="com.codingagent.AgentCommands$DebugHandler"
            commandId="com.codingagent.debug">
      </handler>
      <handler
            class="com.codingagent.AgentCommands$TestHandler"
            commandId="com.codingagent.test">
      </handler>
   </extension>
   <extension point="org.eclipse.ui.bindings">
      <key
            commandId="com.codingagent.complete"
            contextId="org.eclipse.ui.contexts.window"
            sequence="CTRL+SHIFT+SPACE"
            schemeId="org.eclipse.ui.defaultAcceleratorConfiguration">
      </key>
      <!-- 类似为其他命令添加快捷键 -->
   </extension>
   <extension point="org.eclipse.ui.menus">
      <menuContribution
            locationURI="menu:org.eclipse.ui.main.menu">
         <menu
               id="com.codingagent.menu"
               label="Coding Agent">
            <command
                  commandId="com.codingagent.complete"
                  style="push">
            </command>
            <command
                  commandId="com.codingagent.generate"
                  style="push">
            </command>
            <!-- 添加其他命令 -->
         </menu>
      </menuContribution>
      <menuContribution
            locationURI="popup:org.eclipse.ui.popup.any">
         <command
               commandId="com.codingagent.explain"
               style="push">
         </command>
         <command
               commandId="com.codingagent.refactor"
               style="push">
         </command>
         <!-- 添加上下文菜单 -->
      </menuContribution>
   </extension>
</plugin>

8. 清单文件 (META-INF/MANIFEST.MF)

复制代码
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Coding Agent Eclipse Plugin
Bundle-SymbolicName: com.codingagent;singleton:=true
Bundle-Version: 1.0.0.qualifier
Bundle-Activator: com.codingagent.Activator
Require-Bundle: org.eclipse.ui,
 org.eclipse.core.runtime,
 org.eclipse.jface.text,
 org.eclipse.ui.editors
Bundle-RequiredExecutionEnvironment: JavaSE-11
Automatic-Module-Name: com.codingagent
Bundle-ActivationPolicy: lazy

9. 构建属性 (build.properties)

复制代码
source.. = src/
output.. = bin/
bin.includes = META-INF/,\
               .,\
               plugin.xml,\
               resources/

这个Eclipse插件实现提供了完整的编码辅助功能,支持多语言界面,并与本地后端服务集成。注意:实际开发中可能需要添加更多依赖和错误处理。

相关推荐
杨杨杨大侠2 小时前
Atlas Mapper 教程系列 (7/10):单元测试与集成测试
java·开源·github
叽哥2 小时前
Kotlin学习第 7 课:Kotlin 空安全:解决空指针问题的核心机制
android·java·kotlin
guslegend3 小时前
Java面试小册(3)
java
派葛穆3 小时前
Unity-按钮实现场景跳转
java·unity·游戏引擎
弥巷3 小时前
【Android】Viewpager2实现无限轮播图
java
虫小宝3 小时前
返利app排行榜的缓存更新策略:基于过期时间与主动更新的混合方案
java·spring·缓存
SimonKing3 小时前
告别繁琐配置!Retrofit-Spring-Boot-Starter让HTTP调用更优雅
java·后端·程序员
召摇3 小时前
Spring Boot 内置工具类深度指南
java·spring boot
JJJJ_iii3 小时前
【左程云算法09】栈的入门题目-最小栈
java·开发语言·数据结构·算法·时间复杂度