Skip to content

Commit

Permalink
feat: fast code edits (#601)
Browse files Browse the repository at this point in the history
* feat: initial implementation of direct code edits

* fix: popup model selection

* refactor: simplify code replacement logic

* feat: interactive code modifications

* refactor: remove junk
  • Loading branch information
carlrobertoh committed Jun 29, 2024
1 parent cf5f383 commit 14a0d40
Show file tree
Hide file tree
Showing 21 changed files with 690 additions and 181 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

abstract class BaseEditorAction extends AnAction {
public abstract class BaseEditorAction extends AnAction {

BaseEditorAction(
@Nullable @NlsActions.ActionText String text,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

import com.intellij.icons.AllIcons;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.impl.EditorImpl;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.util.ui.FormBuilder;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

import static java.lang.String.format;

import com.intellij.icons.AllIcons.Actions;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.impl.EditorImpl;
import com.intellij.openapi.extensions.PluginId;
import com.intellij.openapi.project.Project;
import ee.carlrobert.codegpt.CodeGPTKeys;
Expand Down Expand Up @@ -47,6 +47,7 @@ public static void refreshActions() {
if (actionGroup instanceof DefaultActionGroup group) {
group.removeAll();
group.add(new AskAction());
group.add(new EditCodeAction(Actions.EditSource));
group.add(new CustomPromptAction());
group.addSeparator();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ public void actionPerformed(@NotNull AnActionEvent event) {
var project = event.getProject();
var toolWindowEditor = event.getData(PlatformDataKeys.EDITOR);
if (project != null && toolWindowEditor != null) {
EditorUtil.replaceMainEditorSelection(
project,
EditorUtil.replaceEditorSelection(
toolWindowEditor,
requireNonNull(toolWindowEditor.getSelectionModel().getSelectedText()));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,20 @@ public static OpenAIChatCompletionRequest buildOpenAILookupCompletionRequest(
.build();
}

public static OpenAIChatCompletionRequest buildEditCodeRequest(
String context,
String model) {
return new OpenAIChatCompletionRequest.Builder(
List.of(
new OpenAIChatCompletionStandardMessage(
"system",
getResourceContent("/prompts/edit-code.txt")),
new OpenAIChatCompletionStandardMessage("user", context)))
.setModel(model)
.setStream(true)
.build();
}

public static Request buildCustomOpenAICompletionRequest(String system, String context) {
return buildCustomOpenAIChatCompletionRequest(
ApplicationManager.getApplication().getService(CustomServiceSettings.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class ConfigurationState {

private String systemPrompt = COMPLETION_SYSTEM_PROMPT;
private String commitMessagePrompt = GENERATE_COMMIT_MESSAGE_SYSTEM_PROMPT;
private int maxTokens = 1000;
private int maxTokens = 2048;
private double temperature = 0.1;
private boolean checkForPluginUpdates = true;
private boolean checkForNewScreenshots = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.UUID;
import java.util.function.Consumer;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
Expand Down Expand Up @@ -274,7 +275,7 @@ private JPanel createUserPromptPanel(ServiceType selectedService) {
panel.add(JBUI.Panels.simplePanel(createUserPromptTextAreaHeader(
project,
selectedService,
() -> {
(provider) -> {
ConversationService.getInstance().startConversation();
contentManager.createNewTabPanel();
})), BorderLayout.NORTH);
Expand All @@ -285,7 +286,7 @@ private JPanel createUserPromptPanel(ServiceType selectedService) {
private JPanel createUserPromptTextAreaHeader(
Project project,
ServiceType selectedService,
Runnable onModelChange) {
Consumer<ServiceType> onModelChange) {
return JBUI.Panels.simplePanel()
.withBorder(Borders.emptyBottom(8))
.andTransparent()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public ReplaceSelectionAction(@NotNull Editor editor) {
public void handleAction(@NotNull AnActionEvent event) {
var project = requireNonNull(event.getProject());
if (EditorUtil.isMainEditorTextSelected(project)) {
EditorUtil.replaceMainEditorSelection(project, editor.getDocument().getText());
EditorUtil.replaceEditorSelection(editor, editor.getDocument().getText());
} else {
OverlayUtil.showSelectedEditorSelectionWarning(event);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package ee.carlrobert.codegpt.toolwindow.chat.ui.textarea;

import static ee.carlrobert.codegpt.settings.service.ServiceType.ANTHROPIC;
import static ee.carlrobert.codegpt.settings.service.ServiceType.AZURE;
import static ee.carlrobert.codegpt.settings.service.ServiceType.CODEGPT;
import static ee.carlrobert.codegpt.settings.service.ServiceType.CUSTOM_OPENAI;
import static ee.carlrobert.codegpt.settings.service.ServiceType.GOOGLE;
import static ee.carlrobert.codegpt.settings.service.ServiceType.LLAMA_CPP;
import static ee.carlrobert.codegpt.settings.service.ServiceType.OLLAMA;
import static ee.carlrobert.codegpt.settings.service.ServiceType.OPENAI;
import static java.lang.String.format;
Expand All @@ -28,20 +32,35 @@
import ee.carlrobert.codegpt.settings.service.ollama.OllamaSettings;
import ee.carlrobert.codegpt.settings.service.openai.OpenAISettings;
import ee.carlrobert.llm.client.openai.completion.OpenAIChatCompletionModel;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import javax.swing.Icon;
import javax.swing.JComponent;
import org.jetbrains.annotations.NotNull;

public class ModelComboBoxAction extends ComboBoxAction {

private final Runnable onModelChange;
private final Consumer<ServiceType> onModelChange;
private final Project project;
private final List<ServiceType> availableProviders;

public ModelComboBoxAction(Project project, Runnable onModelChange, ServiceType selectedService) {
public ModelComboBoxAction(
Project project,
Consumer<ServiceType> onModelChange,
ServiceType selectedService) {
this(project, onModelChange, selectedService, Arrays.asList(ServiceType.values()));
}

public ModelComboBoxAction(
Project project,
Consumer<ServiceType> onModelChange,
ServiceType selectedProvider,
List<ServiceType> availableProviders) {
this.project = project;
this.onModelChange = onModelChange;
updateTemplatePresentation(selectedService);
this.availableProviders = availableProviders;
updateTemplatePresentation(selectedProvider);
}

public JComponent createCustomComponent(@NotNull String place) {
Expand Down Expand Up @@ -70,52 +89,71 @@ private AnAction[] getCodeGPTModelActions(Project project, Presentation presenta
protected @NotNull DefaultActionGroup createPopupActionGroup(JComponent button) {
var presentation = ((ComboBoxButton) button).getPresentation();
var actionGroup = new DefaultActionGroup();
actionGroup.addSeparator("CodeGPT");
actionGroup.addAll(getCodeGPTModelActions(project, presentation));
actionGroup.addSeparator("OpenAI");
List.of(
OpenAIChatCompletionModel.GPT_4_O,
OpenAIChatCompletionModel.GPT_4_VISION_PREVIEW,
OpenAIChatCompletionModel.GPT_4_0125_128k,
OpenAIChatCompletionModel.GPT_3_5_0125_16k)
.forEach(model -> actionGroup.add(createOpenAIModelAction(model, presentation)));
actionGroup.addSeparator("Custom OpenAI");
actionGroup.add(createModelAction(
CUSTOM_OPENAI,
ApplicationManager.getApplication().getService(CustomServiceSettings.class)
.getState()
.getTemplate()
.getProviderName(),
Icons.OpenAI,
presentation));
actionGroup.addSeparator();
actionGroup.add(createModelAction(
ServiceType.ANTHROPIC,
"Anthropic (Claude)",
Icons.Anthropic,
presentation));
actionGroup.addSeparator();
actionGroup.add(
createModelAction(ServiceType.AZURE, "Azure OpenAI", Icons.Azure, presentation));
actionGroup.addSeparator();
actionGroup.add(createModelAction(
ServiceType.LLAMA_CPP,
getLlamaCppPresentationText(),
Icons.Llama,
presentation));
actionGroup.addSeparator("Ollama");
ApplicationManager.getApplication()
.getService(OllamaSettings.class)
.getState()
.getAvailableModels()
.forEach(model ->
actionGroup.add(createOllamaModelAction(model, presentation)));
actionGroup.addSeparator();
actionGroup.add(createModelAction(
ServiceType.GOOGLE,
"Google (Gemini)",
Icons.Google,
presentation));

if (availableProviders.contains(CODEGPT)) {
actionGroup.addSeparator("CodeGPT");
actionGroup.addAll(getCodeGPTModelActions(project, presentation));
}
if (availableProviders.contains(OPENAI)) {
actionGroup.addSeparator("OpenAI");
List.of(
OpenAIChatCompletionModel.GPT_4_O,
OpenAIChatCompletionModel.GPT_4_VISION_PREVIEW,
OpenAIChatCompletionModel.GPT_4_0125_128k,
OpenAIChatCompletionModel.GPT_3_5_0125_16k)
.forEach(model -> actionGroup.add(createOpenAIModelAction(model, presentation)));
}
if (availableProviders.contains(CUSTOM_OPENAI)) {
actionGroup.addSeparator("Custom OpenAI");
actionGroup.add(createModelAction(
CUSTOM_OPENAI,
ApplicationManager.getApplication().getService(CustomServiceSettings.class)
.getState()
.getTemplate()
.getProviderName(),
Icons.OpenAI,
presentation));
}
if (availableProviders.contains(ANTHROPIC)) {
actionGroup.addSeparator("Anthropic");
actionGroup.add(createModelAction(
ANTHROPIC,
"Anthropic (Claude)",
Icons.Anthropic,
presentation));
}
if (availableProviders.contains(AZURE)) {
actionGroup.addSeparator("Azure");
actionGroup.add(
createModelAction(AZURE, "Azure OpenAI", Icons.Azure, presentation));
}
if (availableProviders.contains(GOOGLE)) {
actionGroup.addSeparator("Google");
actionGroup.add(createModelAction(
GOOGLE,
"Google (Gemini)",
Icons.Google,
presentation));
}
if (availableProviders.contains(LLAMA_CPP)) {
actionGroup.addSeparator("LLaMA C/C++");
actionGroup.add(createModelAction(
LLAMA_CPP,
getLlamaCppPresentationText(),
Icons.Llama,
presentation));
}
if (availableProviders.contains(OLLAMA)) {
actionGroup.addSeparator("Ollama");
createOllamaModelAction("Default model", presentation);
ApplicationManager.getApplication()
.getService(OllamaSettings.class)
.getState()
.getAvailableModels()
.forEach(model ->
actionGroup.add(createOllamaModelAction(model, presentation)));
}

return actionGroup;
}

Expand Down Expand Up @@ -211,7 +249,7 @@ public void update(@NotNull AnActionEvent event) {

@Override
public void actionPerformed(@NotNull AnActionEvent e) {
handleModelChange(serviceType, label, icon, comboBoxPresentation);
handleModelChange(serviceType, label, label, icon, comboBoxPresentation);
}

@Override
Expand All @@ -224,12 +262,13 @@ public void actionPerformed(@NotNull AnActionEvent e) {
private void handleModelChange(
ServiceType serviceType,
String label,
String code,
Icon icon,
Presentation comboBoxPresentation) {
GeneralSettings.getCurrentState().setSelectedService(serviceType);
comboBoxPresentation.setIcon(icon);
comboBoxPresentation.setText(label);
onModelChange.run();
onModelChange.accept(serviceType);
}

private AnAction createCodeGPTModelAction(CodeGPTModel model, Presentation comboBoxPresentation) {
Expand All @@ -249,6 +288,7 @@ public void actionPerformed(@NotNull AnActionEvent e) {
handleModelChange(
CODEGPT,
model.getName(),
model.getCode(),
model.getIcon(),
comboBoxPresentation);
}
Expand Down Expand Up @@ -280,6 +320,7 @@ public void actionPerformed(@NotNull AnActionEvent e) {
handleModelChange(
OLLAMA,
model,
model,
Icons.Ollama,
comboBoxPresentation);
}
Expand Down Expand Up @@ -309,6 +350,7 @@ public void actionPerformed(@NotNull AnActionEvent e) {
handleModelChange(
OPENAI,
model.getDescription(),
model.getCode(),
Icons.OpenAI,
comboBoxPresentation);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package ee.carlrobert.codegpt.actions.editor

import com.intellij.openapi.application.runInEdt
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import ee.carlrobert.codegpt.Icons
import ee.carlrobert.codegpt.ui.EditCodePopover
import javax.swing.Icon

class EditCodeAction : BaseEditorAction {

constructor() : this(Icons.Sparkle)

constructor(icon: Icon) : super(
"Edit Code",
"Allow LLM to edit code directly in your editor",
icon
) {
EditorActionsUtil.registerAction(this)
}

override fun actionPerformed(project: Project, editor: Editor, selectedText: String) {
runInEdt {
EditCodePopover(editor).show()
}
}
}
Loading

0 comments on commit 14a0d40

Please sign in to comment.