diff --git a/src/main/java/com/devoxx/genie/model/Constant.java b/src/main/java/com/devoxx/genie/model/Constant.java index c6a8c805..e3ec34c7 100644 --- a/src/main/java/com/devoxx/genie/model/Constant.java +++ b/src/main/java/com/devoxx/genie/model/Constant.java @@ -26,6 +26,7 @@ private Constant() { public static final String TEST_PROMPT = "Write a unit test for this code using JUnit."; public static final String REVIEW_PROMPT = "Review the selected code, can it be improved or are there any bugs?"; public static final String EXPLAIN_PROMPT = "Break down the code in simple terms to help a junior developer grasp its functionality."; + public static final String TDG_PROMPT = "You are a professional Java developer. Give me a SINGLE FILE COMPLETE java implementation that will pass this test. Do not respond with a test. Give me only complete code and no snippets. Include imports and use the right package."; // The Local LLM Model URLs, these can be overridden in the settings page public static final String OLLAMA_MODEL_URL = "http://localhost:11434/"; diff --git a/src/main/java/com/devoxx/genie/model/request/ChatMessageContext.java b/src/main/java/com/devoxx/genie/model/request/ChatMessageContext.java index f2113fbb..deff1503 100644 --- a/src/main/java/com/devoxx/genie/model/request/ChatMessageContext.java +++ b/src/main/java/com/devoxx/genie/model/request/ChatMessageContext.java @@ -16,7 +16,7 @@ @Builder public class ChatMessageContext { private final LocalDateTime createdOn = LocalDateTime.now(); - private String name; + private String id; private Project project; private Integer timeout; private String userPrompt; @@ -30,6 +30,7 @@ public class ChatMessageContext { private int totalFileCount; private long executionTimeMs; private TokenUsage tokenUsage; + private String commandName; // Custom command name for the prompt, for example /test, /review etc. private double cost; @Builder.Default diff --git a/src/main/java/com/devoxx/genie/service/ChatPromptExecutor.java b/src/main/java/com/devoxx/genie/service/ChatPromptExecutor.java index 74124e30..ca5c2991 100644 --- a/src/main/java/com/devoxx/genie/service/ChatPromptExecutor.java +++ b/src/main/java/com/devoxx/genie/service/ChatPromptExecutor.java @@ -18,7 +18,6 @@ import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; -import javax.swing.*; import java.util.Arrays; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; @@ -38,7 +37,6 @@ public ChatPromptExecutor(PromptInputArea promptInputArea) { /** * Execute the prompt. - * * @param chatMessageContext the chat message context * @param promptOutputPanel the prompt output panel * @param enableButtons the Enable buttons @@ -92,13 +90,12 @@ public void run(@NotNull ProgressIndicator progressIndicator) { /** * Process possible command prompt. - * * @param chatMessageContext the chat message context * @param promptOutputPanel the prompt output panel */ public Optional updatePromptWithCommandIfPresent(@NotNull ChatMessageContext chatMessageContext, PromptOutputPanel promptOutputPanel) { - Optional commandFromPrompt = getCommandFromPrompt(chatMessageContext.getUserPrompt().trim(), promptOutputPanel); + Optional commandFromPrompt = getCommandFromPrompt(chatMessageContext, promptOutputPanel); chatMessageContext.setUserPrompt(commandFromPrompt.orElse(chatMessageContext.getUserPrompt())); // Ensure that EditorInfo is set in the ChatMessageContext @@ -109,6 +106,11 @@ public Optional updatePromptWithCommandIfPresent(@NotNull ChatMessageCon return commandFromPrompt; } + /** + * Get the editor info. + * @param project the project + * @return the editor info + */ private @NotNull EditorInfo getEditorInfo(Project project) { EditorInfo editorInfo = new EditorInfo(); FileEditorManager fileEditorManager = FileEditorManager.getInstance(project); @@ -132,7 +134,6 @@ public Optional updatePromptWithCommandIfPresent(@NotNull ChatMessageCon /** * Stop streaming or the non-streaming prompt execution - * * @param project the project */ public void stopPromptExecution(Project project) { @@ -145,21 +146,21 @@ public void stopPromptExecution(Project project) { /** * Get the command from the prompt. - * - * @param prompt the prompt + * @param chatMessageContext the chat message context * @param promptOutputPanel the prompt output panel * @return the command */ - private Optional getCommandFromPrompt(@NotNull String prompt, + private Optional getCommandFromPrompt(@NotNull ChatMessageContext chatMessageContext, PromptOutputPanel promptOutputPanel) { + String prompt = chatMessageContext.getUserPrompt().trim(); if (prompt.startsWith("/")) { DevoxxGenieSettingsService settings = DevoxxGenieStateService.getInstance(); // Check for custom prompts for (CustomPrompt customPrompt : settings.getCustomPrompts()) { if (prompt.equalsIgnoreCase("/" + customPrompt.getName())) { - prompt = customPrompt.getPrompt(); - return Optional.of(prompt); + chatMessageContext.setCommandName(customPrompt.getName()); + return Optional.of(customPrompt.getPrompt()); } } promptOutputPanel.showHelpText(); diff --git a/src/main/java/com/devoxx/genie/service/streaming/StreamingResponseHandler.java b/src/main/java/com/devoxx/genie/service/streaming/StreamingResponseHandler.java index e85ef5bf..761159e8 100644 --- a/src/main/java/com/devoxx/genie/service/streaming/StreamingResponseHandler.java +++ b/src/main/java/com/devoxx/genie/service/streaming/StreamingResponseHandler.java @@ -13,8 +13,6 @@ import dev.langchain4j.model.output.Response; import org.jetbrains.annotations.NotNull; -import javax.swing.*; - public class StreamingResponseHandler implements dev.langchain4j.model.StreamingResponseHandler { private final ChatMessageContext chatMessageContext; private final Runnable enableButtons; @@ -70,7 +68,7 @@ private void addExpandablePanelIfNeeded() { ApplicationManager.getApplication().invokeLater(() -> { ExpandablePanel fileListPanel = new ExpandablePanel(chatMessageContext, FileListManager.getInstance().getFiles()); - fileListPanel.setName(chatMessageContext.getName()); + fileListPanel.setName(chatMessageContext.getId()); promptOutputPanel.addStreamFileReferencesResponse(fileListPanel); }); } diff --git a/src/main/java/com/devoxx/genie/service/tdg/ClassNameNotFoundException.java b/src/main/java/com/devoxx/genie/service/tdg/ClassNameNotFoundException.java new file mode 100644 index 00000000..89324880 --- /dev/null +++ b/src/main/java/com/devoxx/genie/service/tdg/ClassNameNotFoundException.java @@ -0,0 +1,7 @@ +package com.devoxx.genie.service.tdg; + +public class ClassNameNotFoundException extends Exception { + public ClassNameNotFoundException(String message) { + super(message); + } +} diff --git a/src/main/java/com/devoxx/genie/service/tdg/CodeContainer.java b/src/main/java/com/devoxx/genie/service/tdg/CodeContainer.java new file mode 100644 index 00000000..c757e07a --- /dev/null +++ b/src/main/java/com/devoxx/genie/service/tdg/CodeContainer.java @@ -0,0 +1,54 @@ +package com.devoxx.genie.service.tdg; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +@ToString +@EqualsAndHashCode +@Setter +@Getter +public final class CodeContainer { + + private final String content; + private final String fileName; + private final String packageName; + private final int attempts; + + public CodeContainer(String content) throws ClassNameNotFoundException { + this(content, 1); + } + + public CodeContainer(String content, int attempts) throws ClassNameNotFoundException { + this.content = content; + this.fileName = extractClassName() + ".java"; + this.packageName = extractPackageName(); + this.attempts = attempts; + } + + // TODO: first look for 'public class' and then for 'class + private String extractClassName() throws ClassNameNotFoundException { + // matches "public" (optional) followed by "class" and then the class name + String regex = "\\b(?:public\\s+)?class\\s+(\\w+)\\b"; + Matcher matcher = Pattern.compile(regex).matcher(content); + if (matcher.find()) { + return matcher.group(1); + } else { + throw new ClassNameNotFoundException("Class name not found in: " + content); + } + } + + private String extractPackageName() { + String regex = "package\\s+(\\w+(\\.\\w+)*)"; + Matcher matcher = Pattern.compile(regex).matcher(content); + if (matcher.find()) { + return matcher.group(1); + } else { + return ""; + } + } +} diff --git a/src/main/java/com/devoxx/genie/service/tdg/CodeGeneratorService.java b/src/main/java/com/devoxx/genie/service/tdg/CodeGeneratorService.java new file mode 100644 index 00000000..edc1923c --- /dev/null +++ b/src/main/java/com/devoxx/genie/service/tdg/CodeGeneratorService.java @@ -0,0 +1,128 @@ +package com.devoxx.genie.service.tdg; + +import com.devoxx.genie.model.request.ChatMessageContext; +import com.devoxx.genie.ui.util.NotificationUtil; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.Task; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +public class CodeGeneratorService { + + public static void createClassFromCodeSnippet(@NotNull ChatMessageContext chatMessageContext, + String selectedText) { + Project project = chatMessageContext.getProject(); + + new Task.Backgroundable(project, "Creating java class", false) { + @Override + public void run(@NotNull ProgressIndicator indicator) { + try { + indicator.setIndeterminate(true); + indicator.setText("Parsing code..."); + + CodeContainer codeContainer = new CodeContainer(selectedText); + String packageName = codeContainer.getPackageName(); + String fileName = codeContainer.getFileName(); + + indicator.setText("Creating class file..."); + + ApplicationManager.getApplication().invokeAndWait(() -> + ApplicationManager.getApplication().runWriteAction(() -> + createFile(packageName, fileName, project, selectedText)), + ModalityState.defaultModalityState()); + + } catch (Exception e) { + NotificationUtil.sendNotification(project, + "Error creating class: " + e.getMessage()); + } + } + }.queue(); + } + + private static void createFile(String packageName, + String fileName, + Project project, + String selectedText) { + try { + // Find the proper source root for Java files + VirtualFile sourceRoot = findSourceRoot(project); + if (sourceRoot == null) { + NotificationUtil.sendNotification(project, + "Error: Could not find source root directory"); + return; + } + + VirtualFile packageDir = createPackageDirectories(sourceRoot, packageName); + VirtualFile existingFile = packageDir.findChild(fileName); + VirtualFile javaFile; + + if (existingFile != null) { + existingFile.setBinaryContent( + selectedText.getBytes(StandardCharsets.UTF_8)); + javaFile = existingFile; + NotificationUtil.sendNotification(project, + "Class updated successfully"); + } else { + javaFile = packageDir.createChildData(null, fileName); + javaFile.setBinaryContent( + selectedText.getBytes(StandardCharsets.UTF_8)); + NotificationUtil.sendNotification(project, + "Class created successfully"); + } + + FileEditorManager.getInstance(project).openFile(javaFile, true); + + } catch (IOException e) { + NotificationUtil.sendNotification(project, + "Error creating class: " + e.getMessage()); + } + } + + private static @Nullable VirtualFile findSourceRoot(Project project) { + ModuleManager moduleManager = ModuleManager.getInstance(project); + for (Module module : moduleManager.getModules()) { + ModuleRootManager rootManager = ModuleRootManager.getInstance(module); + // Get source roots for the module + for (VirtualFile root : rootManager.getSourceRoots(false)) { + // Look for the main source root, typically ending with "src/main/java" + if (root.getPath().endsWith("src/main/java")) { + return root; + } + } + // Fallback to first source root if we can't find main/java + VirtualFile[] sourceRoots = rootManager.getSourceRoots(false); + if (sourceRoots.length > 0) { + return sourceRoots[0]; + } + } + return null; + } + + private static VirtualFile createPackageDirectories(@NotNull VirtualFile sourceRoot, + @NotNull String packageName) throws IOException { + if (packageName.isEmpty()) { + return sourceRoot; + } + + VirtualFile currentDir = sourceRoot; + for (String part : packageName.split("\\.")) { + VirtualFile subDir = currentDir.findChild(part); + if (subDir == null) { + subDir = currentDir.createChildDirectory(null, part); + } + currentDir = subDir; + } + return currentDir; + } +} diff --git a/src/main/java/com/devoxx/genie/ui/component/CommandAutoCompleteTextField.java b/src/main/java/com/devoxx/genie/ui/component/CommandAutoCompleteTextField.java index e9adf807..5c28d84e 100644 --- a/src/main/java/com/devoxx/genie/ui/component/CommandAutoCompleteTextField.java +++ b/src/main/java/com/devoxx/genie/ui/component/CommandAutoCompleteTextField.java @@ -50,6 +50,7 @@ private void initializeCommands() { commands.add("/test"); commands.add("/explain"); commands.add("/review"); + commands.add("/tdg"); commands.add("/help"); DevoxxGenieSettingsService stateService = DevoxxGenieStateService.getInstance(); diff --git a/src/main/java/com/devoxx/genie/ui/panel/ChatResponsePanel.java b/src/main/java/com/devoxx/genie/ui/panel/ChatResponsePanel.java index 4df475ab..d3796c09 100644 --- a/src/main/java/com/devoxx/genie/ui/panel/ChatResponsePanel.java +++ b/src/main/java/com/devoxx/genie/ui/panel/ChatResponsePanel.java @@ -36,7 +36,7 @@ public class ChatResponsePanel extends BackgroundPanel { * @param chatMessageContext the chat message context */ public ChatResponsePanel(@NotNull ChatMessageContext chatMessageContext) { - super(chatMessageContext.getName()); + super(chatMessageContext.getId()); setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); this.chatMessageContext = chatMessageContext; diff --git a/src/main/java/com/devoxx/genie/ui/panel/ChatStreamingResponsePanel.java b/src/main/java/com/devoxx/genie/ui/panel/ChatStreamingResponsePanel.java index 3aa3f9c3..44445d46 100644 --- a/src/main/java/com/devoxx/genie/ui/panel/ChatStreamingResponsePanel.java +++ b/src/main/java/com/devoxx/genie/ui/panel/ChatStreamingResponsePanel.java @@ -30,7 +30,7 @@ public class ChatStreamingResponsePanel extends BackgroundPanel { * @param chatMessageContext the chat message context */ public ChatStreamingResponsePanel(@NotNull ChatMessageContext chatMessageContext) { - super(chatMessageContext.getName()); + super(chatMessageContext.getId()); setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); add(new ResponseHeaderPanel(chatMessageContext)); diff --git a/src/main/java/com/devoxx/genie/ui/panel/PromptOutputPanel.java b/src/main/java/com/devoxx/genie/ui/panel/PromptOutputPanel.java index c03ef5d7..1625fefa 100644 --- a/src/main/java/com/devoxx/genie/ui/panel/PromptOutputPanel.java +++ b/src/main/java/com/devoxx/genie/ui/panel/PromptOutputPanel.java @@ -84,14 +84,14 @@ public void addUserPrompt(ChatMessageContext chatMessageContext) { userPromptPanel.add(waitingPanel, BorderLayout.SOUTH); } - addFiller(chatMessageContext.getName()); + addFiller(chatMessageContext.getId()); container.add(userPromptPanel); scrollToBottom(); } public void addChatResponse(@NotNull ChatMessageContext chatMessageContext) { waitingPanel.hideMsg(); - addFiller(chatMessageContext.getName()); + addFiller(chatMessageContext.getId()); container.add(new ChatResponsePanel(chatMessageContext)); scrollToBottom(); } @@ -108,7 +108,7 @@ public void addStreamFileReferencesResponse(ExpandablePanel fileListPanel) { public void removeLastUserPrompt(ChatMessageContext chatMessageContext) { for (Component component : container.getComponents()) { - if (component instanceof UserPromptPanel && component.getName().equals(chatMessageContext.getName())) { + if (component instanceof UserPromptPanel && component.getName().equals(chatMessageContext.getId())) { container.remove(component); break; } @@ -153,7 +153,7 @@ private ChatMessageContext createChatMessageContext(Project project, @NotNull Conversation conversation, @NotNull ChatMessage message) { return ChatMessageContext.builder() - .name(conversation.getId()) + .id(conversation.getId()) .project(project) .userPrompt(message.isUser() ? message.getContent() : "") .aiMessage(message.isUser() ? null : AiMessage.aiMessage(message.getContent())) diff --git a/src/main/java/com/devoxx/genie/ui/panel/UserPromptPanel.java b/src/main/java/com/devoxx/genie/ui/panel/UserPromptPanel.java index 90185655..bfc70b63 100644 --- a/src/main/java/com/devoxx/genie/ui/panel/UserPromptPanel.java +++ b/src/main/java/com/devoxx/genie/ui/panel/UserPromptPanel.java @@ -27,7 +27,7 @@ public class UserPromptPanel extends BackgroundPanel { */ public UserPromptPanel(JPanel container, @NotNull ChatMessageContext chatMessageContext) { - super(chatMessageContext.getName()); + super(chatMessageContext.getId()); this.container = container; setLayout(new BorderLayout()); @@ -77,7 +77,7 @@ public UserPromptPanel(JPanel container, * @param chatMessageContext the chat message context */ private void removeChat(@NotNull ChatMessageContext chatMessageContext) { - String nameToRemove = chatMessageContext.getName(); + String nameToRemove = chatMessageContext.getId(); java.util.List componentsToRemove = new ArrayList<>(); for (Component c : container.getComponents()) { diff --git a/src/main/java/com/devoxx/genie/ui/panel/WarningPanel.java b/src/main/java/com/devoxx/genie/ui/panel/WarningPanel.java index 042265c6..aeb295f4 100644 --- a/src/main/java/com/devoxx/genie/ui/panel/WarningPanel.java +++ b/src/main/java/com/devoxx/genie/ui/panel/WarningPanel.java @@ -20,7 +20,7 @@ public class WarningPanel extends BackgroundPanel { public WarningPanel(String warning, ChatMessageContext chatMessageContext) { super(warning); - setName(chatMessageContext.getName()); + setName(chatMessageContext.getId()); setLayout(new BorderLayout()); withMaximumSize(1500, 75) .withBorder(BorderFactory.createCompoundBorder( diff --git a/src/main/java/com/devoxx/genie/ui/processor/FencedCodeBlockProcessor.java b/src/main/java/com/devoxx/genie/ui/processor/FencedCodeBlockProcessor.java index cbbc6240..9f71acd8 100644 --- a/src/main/java/com/devoxx/genie/ui/processor/FencedCodeBlockProcessor.java +++ b/src/main/java/com/devoxx/genie/ui/processor/FencedCodeBlockProcessor.java @@ -27,7 +27,6 @@ public FencedCodeBlockProcessor(ChatMessageContext chatMessageContext, /** * Process the fenced code block. - * * @return the panel */ @Override @@ -43,8 +42,8 @@ public JPanel processNode() { overlayPanel.setOpaque(true); // Add components to the overlay panel in the correct order - overlayPanel.add(editorPane, BorderLayout.CENTER); // Editor pane at the bottom - overlayPanel.add(codeSnippetAction.createClipBoardButtonPanel(fencedCodeBlock), BorderLayout.NORTH); // Button panel on top + overlayPanel.add(editorPane, BorderLayout.CENTER); + overlayPanel.add(codeSnippetAction.createClipBoardButtonPanel(chatMessageContext, fencedCodeBlock), BorderLayout.NORTH); return overlayPanel; } diff --git a/src/main/java/com/devoxx/genie/ui/processor/IndentedCodeBlockProcessor.java b/src/main/java/com/devoxx/genie/ui/processor/IndentedCodeBlockProcessor.java index 6a974633..fc75deda 100644 --- a/src/main/java/com/devoxx/genie/ui/processor/IndentedCodeBlockProcessor.java +++ b/src/main/java/com/devoxx/genie/ui/processor/IndentedCodeBlockProcessor.java @@ -22,7 +22,6 @@ public IndentedCodeBlockProcessor(ChatMessageContext chatMessageContext, /** * Process the fenced code block. - * * @return the panel */ @Override diff --git a/src/main/java/com/devoxx/genie/ui/processor/NodeProcessor.java b/src/main/java/com/devoxx/genie/ui/processor/NodeProcessor.java index db21ca6a..8e7f0889 100644 --- a/src/main/java/com/devoxx/genie/ui/processor/NodeProcessor.java +++ b/src/main/java/com/devoxx/genie/ui/processor/NodeProcessor.java @@ -16,14 +16,12 @@ public interface NodeProcessor { /** * Process the node. - * * @return the panel */ JPanel processNode(); /** * Create an editor pane. - * * @param htmlResponse the HTML response * @return the editor pane */ @@ -39,7 +37,6 @@ default JEditorPane createEditorPane(@NotNull String htmlResponse, StyleSheet st /** * Create an HTML renderer. - * * @return the HTML renderer */ default HtmlRenderer createHtmlRenderer(Project project) { diff --git a/src/main/java/com/devoxx/genie/ui/processor/NodeProcessorFactory.java b/src/main/java/com/devoxx/genie/ui/processor/NodeProcessorFactory.java index 476aa418..9c3fe126 100644 --- a/src/main/java/com/devoxx/genie/ui/processor/NodeProcessorFactory.java +++ b/src/main/java/com/devoxx/genie/ui/processor/NodeProcessorFactory.java @@ -11,7 +11,6 @@ public class NodeProcessorFactory { /** * Create a processor for the given block - * * @param chatMessageContext the chat message context * @param theBlock the block * @return the processor diff --git a/src/main/java/com/devoxx/genie/ui/renderer/CodeBlockNodeRenderer.java b/src/main/java/com/devoxx/genie/ui/renderer/CodeBlockNodeRenderer.java index 95a17939..89db047d 100644 --- a/src/main/java/com/devoxx/genie/ui/renderer/CodeBlockNodeRenderer.java +++ b/src/main/java/com/devoxx/genie/ui/renderer/CodeBlockNodeRenderer.java @@ -133,13 +133,6 @@ private HighlightingMode determineHighlightingMode(boolean block) { TextAttributes codeAttributes = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(HighlighterColors.TEXT).clone(); codeAttributes.setBackgroundColor(null); - -// highlightedAndEncodedAsHtmlCodeSnippet = new StringBuilder( -// HtmlSyntaxInfoUtil.appendStyledSpan( -// highlightedAndEncodedAsHtmlCodeSnippet, -// codeAttributes, -// DocumentationSettings.getHighlightingSaturation(true) -// )); } return highlightedAndEncodedAsHtmlCodeSnippet.toString(); diff --git a/src/main/java/com/devoxx/genie/ui/settings/DevoxxGenieStateService.java b/src/main/java/com/devoxx/genie/ui/settings/DevoxxGenieStateService.java index 6766890e..4849b512 100644 --- a/src/main/java/com/devoxx/genie/ui/settings/DevoxxGenieStateService.java +++ b/src/main/java/com/devoxx/genie/ui/settings/DevoxxGenieStateService.java @@ -127,6 +127,7 @@ private void initializeDefaultPrompts() { customPrompts.add(new CustomPrompt("test", TEST_PROMPT)); customPrompts.add(new CustomPrompt("explain", EXPLAIN_PROMPT)); customPrompts.add(new CustomPrompt("review", REVIEW_PROMPT)); + customPrompts.add(new CustomPrompt("tdg", TDG_PROMPT)); } } diff --git a/src/main/java/com/devoxx/genie/ui/settings/prompt/PromptSettingsComponent.java b/src/main/java/com/devoxx/genie/ui/settings/prompt/PromptSettingsComponent.java index 55b95d24..5dc2c097 100644 --- a/src/main/java/com/devoxx/genie/ui/settings/prompt/PromptSettingsComponent.java +++ b/src/main/java/com/devoxx/genie/ui/settings/prompt/PromptSettingsComponent.java @@ -1,7 +1,6 @@ package com.devoxx.genie.ui.settings.prompt; import com.devoxx.genie.model.CustomPrompt; -import com.devoxx.genie.service.DevoxxGenieSettingsService; import com.devoxx.genie.ui.dialog.CustomPromptDialog; import com.devoxx.genie.ui.settings.AbstractSettingsComponent; import com.devoxx.genie.ui.settings.DevoxxGenieStateService; @@ -26,7 +25,6 @@ public class PromptSettingsComponent extends AbstractSettingsComponent { private final DevoxxGenieStateService stateService = DevoxxGenieStateService.getInstance(); - private final int NAME_COLUMN = 0; private final int PROMPT_COLUMN = 1; @Getter @@ -72,9 +70,7 @@ public JPanel createPanel() { gbc.insets = JBUI.insets(5); addSection(panel, gbc, "Prompts"); - addPromptArea(panel, gbc, "System prompt", systemPromptField); - addSection(panel, gbc, "Custom Prompts"); gbc.gridy++; @@ -165,6 +161,7 @@ private void removeCustomPrompt() { } public List getCustomPrompts() { + int NAME_COLUMN = 0; List prompts = new ArrayList<>(); for (int i = 0; i < customPromptsTableModel.getRowCount(); i++) { String name = (String) customPromptsTableModel.getValueAt(i, NAME_COLUMN); diff --git a/src/main/java/com/devoxx/genie/ui/util/CodeSnippetAction.java b/src/main/java/com/devoxx/genie/ui/util/CodeSnippetAction.java index 30435679..01366d49 100644 --- a/src/main/java/com/devoxx/genie/ui/util/CodeSnippetAction.java +++ b/src/main/java/com/devoxx/genie/ui/util/CodeSnippetAction.java @@ -1,6 +1,7 @@ package com.devoxx.genie.ui.util; import com.devoxx.genie.model.request.ChatMessageContext; +import com.devoxx.genie.service.tdg.CodeGeneratorService; import com.devoxx.genie.ui.component.JHoverButton; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.diagnostic.Logger; @@ -8,6 +9,7 @@ import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.vfs.VirtualFile; import org.commonmark.node.FencedCodeBlock; import javax.swing.*; @@ -15,8 +17,7 @@ import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.StringSelection; -import static com.devoxx.genie.ui.util.DevoxxGenieIconsUtil.CopyIcon; -import static com.devoxx.genie.ui.util.DevoxxGenieIconsUtil.InsertCodeIcon; +import static com.devoxx.genie.ui.util.DevoxxGenieIconsUtil.*; public class CodeSnippetAction { @@ -26,7 +27,7 @@ public CodeSnippetAction(ChatMessageContext chatMessageContext) { this.chatMessageContext = chatMessageContext; } - public JPanel createClipBoardButtonPanel(FencedCodeBlock fencedCodeBlock) { + public JPanel createClipBoardButtonPanel(ChatMessageContext chatMessageContext, FencedCodeBlock fencedCodeBlock) { JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 4, 2)); buttonPanel.setOpaque(true); @@ -40,15 +41,30 @@ public JPanel createClipBoardButtonPanel(FencedCodeBlock fencedCodeBlock) { insertButton.addActionListener(e -> insertCode(fencedCodeBlock.getLiteral())); buttonPanel.add(insertButton); + if (chatMessageContext.getCommandName().equalsIgnoreCase("tdg")) { + JHoverButton createButton = new JHoverButton(CreateIcon, true); + createButton.setToolTipText("Create class"); + createButton.addActionListener(e -> createClass(fencedCodeBlock.getLiteral())); + buttonPanel.add(createButton); + } + return buttonPanel; } + /** + * Copy the given code snippet to the clipboard. + * @param codeSnippet The code snippet to copy + */ private void copyToClipboard(String codeSnippet) { Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); clipboard.setContents(new StringSelection(codeSnippet), null); NotificationUtil.sendNotification(chatMessageContext.getProject(), "Code copied to clipboard"); } + /** + * Insert the given code snippet into the editor. + * @param codeSnippet The code snippet to insert + */ private void insertCode(String codeSnippet) { FileEditorManager fileEditorManager = FileEditorManager.getInstance(chatMessageContext.getProject()); Editor editor = fileEditorManager.getSelectedTextEditor(); @@ -64,4 +80,14 @@ private void insertCode(String codeSnippet) { }); } } + + /** + * Create a class from the given code snippet. + * @param codeSnippet The code snippet to create the class from + */ + private void createClass(String codeSnippet) { + if (chatMessageContext.getCommandName().equalsIgnoreCase("tdg")) { + CodeGeneratorService.createClassFromCodeSnippet(chatMessageContext, codeSnippet); + } + } } diff --git a/src/main/java/com/devoxx/genie/ui/util/DevoxxGenieIconsUtil.java b/src/main/java/com/devoxx/genie/ui/util/DevoxxGenieIconsUtil.java index 791aaeb6..acf9cf60 100644 --- a/src/main/java/com/devoxx/genie/ui/util/DevoxxGenieIconsUtil.java +++ b/src/main/java/com/devoxx/genie/ui/util/DevoxxGenieIconsUtil.java @@ -29,6 +29,7 @@ public final class DevoxxGenieIconsUtil { public static final Icon CopyIcon = load("/icons/copy.svg"); public static final Icon InsertCodeIcon = load("/icons/insertCode.svg"); public static final Icon RefreshIcon = load("/icons/refresh.svg"); + public static final Icon CreateIcon = load("/icons/event.svg"); private DevoxxGenieIconsUtil() { } diff --git a/src/main/java/com/devoxx/genie/util/ChatMessageContextUtil.java b/src/main/java/com/devoxx/genie/util/ChatMessageContextUtil.java index 1b7e6b73..6d8459fe 100644 --- a/src/main/java/com/devoxx/genie/util/ChatMessageContextUtil.java +++ b/src/main/java/com/devoxx/genie/util/ChatMessageContextUtil.java @@ -42,7 +42,7 @@ public class ChatMessageContextUtil { boolean isProjectContextAdded) { ChatMessageContext context = ChatMessageContext.builder() .project(project) - .name(String.valueOf(System.currentTimeMillis())) + .id(String.valueOf(System.currentTimeMillis())) .userPrompt(userPromptText) .userMessage(UserMessage.userMessage(userPromptText)) .languageModel(languageModel) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 7cd46929..760076c1 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,2 +1,2 @@ -#Fri Nov 08 15:30:17 CET 2024 +#Fri Nov 08 15:50:43 CET 2024 version=0.2.27 diff --git a/src/main/resources/icons/event.svg b/src/main/resources/icons/event.svg new file mode 100644 index 00000000..b5296e24 --- /dev/null +++ b/src/main/resources/icons/event.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/main/resources/icons/event_dark.svg b/src/main/resources/icons/event_dark.svg new file mode 100644 index 00000000..9bb6c229 --- /dev/null +++ b/src/main/resources/icons/event_dark.svg @@ -0,0 +1,5 @@ + + + + +