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