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)
// 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 {// 獲取當前LocaleLocale 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 startedcommands.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 Testsprompts.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)
// 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() {}@Overridepublic void start(BundleContext context) throws Exception {super.start(context);plugin = this;System.out.println(Messages.getString("extension.activated"));}@Overridepublic 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)
// 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)
// 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 {@Overridepublic 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 {@Overridepublic 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 {@Overridepublic 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 {@Overridepublic 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 {@Overridepublic 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 {@Overridepublic 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 version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin><extension point="org.eclipse.ui.commands"><categoryid="com.codingagent.category"name="Coding Agent"></category><commandcategoryId="com.codingagent.category"id="com.codingagent.complete"name="%commands.complete"></command><commandcategoryId="com.codingagent.category"id="com.codingagent.generate"name="%commands.generate"></command><commandcategoryId="com.codingagent.category"id="com.codingagent.explain"name="%commands.explain"></command><commandcategoryId="com.codingagent.category"id="com.codingagent.refactor"name="%commands.refactor"></command><commandcategoryId="com.codingagent.category"id="com.codingagent.debug"name="%commands.debug"></command><commandcategoryId="com.codingagent.category"id="com.codingagent.test"name="%commands.test"></command></extension><extension point="org.eclipse.ui.handlers"><handlerclass="com.codingagent.AgentCommands$CompleteHandler"commandId="com.codingagent.complete"></handler><handlerclass="com.codingagent.AgentCommands$GenerateHandler"commandId="com.codingagent.generate"></handler><handlerclass="com.codingagent.AgentCommands$ExplainHandler"commandId="com.codingagent.explain"></handler><handlerclass="com.codingagent.AgentCommands$RefactorHandler"commandId="com.codingagent.refactor"></handler><handlerclass="com.codingagent.AgentCommands$DebugHandler"commandId="com.codingagent.debug"></handler><handlerclass="com.codingagent.AgentCommands$TestHandler"commandId="com.codingagent.test"></handler></extension><extension point="org.eclipse.ui.bindings"><keycommandId="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"><menuContributionlocationURI="menu:org.eclipse.ui.main.menu"><menuid="com.codingagent.menu"label="Coding Agent"><commandcommandId="com.codingagent.complete"style="push"></command><commandcommandId="com.codingagent.generate"style="push"></command><!-- 添加其他命令 --></menu></menuContribution><menuContributionlocationURI="popup:org.eclipse.ui.popup.any"><commandcommandId="com.codingagent.explain"style="push"></command><commandcommandId="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插件實現提供了完整的編碼輔助功能,支持多語言界面,并與本地后端服務集成。注意:實際開發中可能需要添加更多依賴和錯誤處理。