Ability to edit generated code (#220)

* Ability to edit generated code inside the chat toolwindow

* Improve icon behaviour

* Fix browseFolderListener automatic disposal by recreating the inputs on each action

* Replace label
This commit is contained in:
Carl-Robert 2023-10-01 03:59:32 +03:00 committed by GitHub
parent d05f7d4583
commit 7ff48dc928
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 96 additions and 58 deletions

View file

@ -17,7 +17,7 @@ public class DeleteConversationAction extends AnAction {
private final Runnable onDelete;
public DeleteConversationAction(Runnable onDelete) {
super("Delete Conversation", "Delete single conversation", AllIcons.General.Remove);
super("Delete Conversation", "Delete single conversation", AllIcons.Actions.GC);
this.onDelete = onDelete;
EditorActionsUtil.registerOrReplaceAction(this);
}

View file

@ -5,20 +5,20 @@ import com.intellij.openapi.actionSystem.ActionToolbar;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.actionSystem.impl.ActionButton;
import javax.swing.Icon;
public class IconActionButton extends ActionButton {
public IconActionButton(String tooltipText, Icon icon, AnAction onAction) {
super(onAction,
getPresentation(tooltipText, icon),
public IconActionButton(AnAction action) {
super(action,
getPresentation(action),
ActionPlaces.TOOLWINDOW_CONTENT,
ActionToolbar.DEFAULT_MINIMUM_BUTTON_SIZE);
}
private static Presentation getPresentation(String tooltipText, Icon icon) {
var presentation = new Presentation(tooltipText);
presentation.setIcon(icon);
private static Presentation getPresentation(AnAction action) {
var actionPresentation = action.getTemplatePresentation();
var presentation = new Presentation(actionPresentation.getText());
presentation.setIcon(actionPresentation.getIcon());
return presentation;
}
}

View file

@ -1,8 +1,9 @@
package ee.carlrobert.codegpt.toolwindow.chat;
import static com.intellij.openapi.ui.DialogWrapper.OK_EXIT_CODE;
import static ee.carlrobert.codegpt.util.FileUtils.findFileNameExtensionMapping;
import static java.lang.String.format;
import com.intellij.icons.AllIcons;
import com.intellij.icons.AllIcons.Actions;
import com.intellij.ide.util.EditorHelper;
import com.intellij.openapi.Disposable;
@ -69,7 +70,7 @@ public class ChatToolWindowTabPanelEditor implements Disposable {
var timestamp = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now());
var fileName = "temp_" + timestamp + fileNameExtensionMapping.getValue();
var lightVirtualFile = new LightVirtualFile(
String.format("%s/%s", PathManager.getTempPath(), fileName), code);
format("%s/%s", PathManager.getTempPath(), fileName), code);
var document = FileDocumentManager.getInstance().getDocument(lightVirtualFile);
if (document == null) {
document = EditorFactory.getInstance().createDocument(code);
@ -87,7 +88,7 @@ public class ChatToolWindowTabPanelEditor implements Disposable {
String originalGroupId = ((EditorEx) editor).getContextMenuGroupId();
if (originalGroupId != null) {
AnAction originalGroup = ActionManager.getInstance().getAction(originalGroupId);
AnAction originalGroup = ActionManager.getInstance().getAction(originalGroupId);
if (originalGroup instanceof ActionGroup) {
group.addAll(((ActionGroup) originalGroup).getChildren(null));
}
@ -130,14 +131,13 @@ public class ChatToolWindowTabPanelEditor implements Disposable {
private JPanel createHeaderActions() {
var wrapper = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
wrapper.add(new IconActionButton("New File", Actions.AddFile, new NewFileAction()));
wrapper.add(new IconActionButton(new EditAction()));
wrapper.add(Box.createHorizontalStrut(8));
wrapper.add(new IconActionButton("Copy", AllIcons.Actions.Copy, new CopyAction()));
wrapper.add(new IconActionButton(new NewFileAction()));
wrapper.add(Box.createHorizontalStrut(8));
wrapper.add(new IconActionButton(
"Replace in Main Editor",
AllIcons.Actions.Replace,
new ReplaceInMainEditorAction()));
wrapper.add(new IconActionButton(new CopyAction()));
wrapper.add(Box.createHorizontalStrut(8));
wrapper.add(new IconActionButton(new ReplaceInMainEditorAction()));
return wrapper;
}
@ -146,25 +146,49 @@ public class ChatToolWindowTabPanelEditor implements Disposable {
EditorFactory.getInstance().releaseEditor(editor);
}
class EditAction extends AnAction {
EditAction() {
super("Edit Source", "Edit Source description", Actions.EditSource);
}
@Override
public void actionPerformed(@NotNull AnActionEvent event) {
var editorEx = ((EditorEx) editor);
editorEx.setViewer(!editorEx.isViewer());
var viewer = editorEx.isViewer();
editorEx.setCaretVisible(!viewer);
editorEx.setCaretEnabled(!viewer);
var settings = editorEx.getSettings();
settings.setCaretRowShown(!viewer);
event.getPresentation().setIcon(viewer ? Actions.EditSource : Actions.Show);
event.getPresentation().setText(viewer ? "Edit Source" : "Disable Editing");
var locationOnScreen = ((MouseEvent) event.getInputEvent()).getLocationOnScreen();
locationOnScreen.y = locationOnScreen.y - 16;
}
}
class NewFileAction extends AnAction {
private final TextFieldWithBrowseButton textFieldWithBrowseButton;
private final JBTextField fileNameTextField;
NewFileAction() {
var fileChooserDescriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor();
fileChooserDescriptor.setForcedToUseIdeaFileChooser(true);
textFieldWithBrowseButton = new TextFieldWithBrowseButton();
textFieldWithBrowseButton.addBrowseFolderListener(
new TextBrowseFolderListener(fileChooserDescriptor, project));
fileNameTextField = new JBTextField("Untitled" + fileNameExtensionMapping.getValue());
fileNameTextField.setColumns(30);
super("New File", "New File description", Actions.AddFile);
}
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
if (getDialogBuilder().show() == 0) {
var fileChooserDescriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor();
fileChooserDescriptor.setForcedToUseIdeaFileChooser(true);
var textFieldWithBrowseButton = new TextFieldWithBrowseButton();
textFieldWithBrowseButton.addBrowseFolderListener(
new TextBrowseFolderListener(fileChooserDescriptor, project));
var fileNameTextField = new JBTextField("Untitled" + fileNameExtensionMapping.getValue());
fileNameTextField.setColumns(30);
if (showDialog(textFieldWithBrowseButton, fileNameTextField) == OK_EXIT_CODE) {
var file = FileUtils.createFile(
textFieldWithBrowseButton.getText(),
fileNameTextField.getText(),
@ -182,21 +206,27 @@ public class ChatToolWindowTabPanelEditor implements Disposable {
}
}
private DialogBuilder getDialogBuilder() {
var dialogBuilder = new DialogBuilder(project);
dialogBuilder.setTitle("New File");
dialogBuilder.setCenterPanel(FormBuilder.createFormBuilder()
.addLabeledComponent("File name:", fileNameTextField)
.addLabeledComponent("Destination:", textFieldWithBrowseButton)
.getPanel());
private int showDialog(
TextFieldWithBrowseButton textFieldWithBrowseButton,
JBTextField fileNameTextField) {
var dialogBuilder = new DialogBuilder(project)
.title("New File")
.centerPanel(FormBuilder.createFormBuilder()
.addLabeledComponent("File name:", fileNameTextField)
.addLabeledComponent("Destination:", textFieldWithBrowseButton)
.getPanel());
dialogBuilder.addOkAction();
dialogBuilder.addCancelAction();
return dialogBuilder;
return dialogBuilder.show();
}
}
class CopyAction extends AnAction {
CopyAction() {
super("Copy", "Copy description", Actions.Copy);
}
@Override
public void actionPerformed(@NotNull AnActionEvent event) {
StringSelection stringSelection = new StringSelection(editor.getDocument().getText());
@ -212,6 +242,10 @@ public class ChatToolWindowTabPanelEditor implements Disposable {
class ReplaceInMainEditorAction extends AnAction {
ReplaceInMainEditorAction() {
super("Replace in Main Editor", "Replace in Main Editor description", Actions.Replace);
}
@Override
public void actionPerformed(@NotNull AnActionEvent event) {
var project = event.getProject();

View file

@ -82,22 +82,24 @@ public class ResponsePanel extends JPanel {
}
public void addReloadAction(Runnable onReload) {
addIconActionButton(new IconActionButton("Reload response", Actions.Refresh, new AnAction() {
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
enableActions(false);
onReload.run();
}
}));
addIconActionButton(new IconActionButton(
new AnAction("Reload Response", "Reload response description", Actions.Refresh) {
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
enableActions(false);
onReload.run();
}
}));
}
public void addDeleteAction(Runnable onDelete) {
addIconActionButton(new IconActionButton("Delete response", Actions.GC, new AnAction() {
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
onDelete.run();
}
}));
addIconActionButton(new IconActionButton(
new AnAction("Delete Response", "Delete response description", Actions.GC) {
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
onDelete.run();
}
}));
}
private void addIconActionButton(IconActionButton iconActionButton) {

View file

@ -2,7 +2,6 @@ package ee.carlrobert.codegpt.toolwindow.conversations;
import static ee.carlrobert.codegpt.util.ThemeUtils.getPanelBackgroundColor;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.project.Project;
import com.intellij.ui.JBColor;
import com.intellij.ui.components.JBLabel;
@ -17,28 +16,29 @@ import ee.carlrobert.codegpt.toolwindow.ModelIconLabel;
import ee.carlrobert.codegpt.toolwindow.chat.standard.StandardChatToolWindowContentManager;
import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.time.format.DateTimeFormatter;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;
import org.jetbrains.annotations.NotNull;
class ConversationPanel extends JPanel {
ConversationPanel(@NotNull Project project, @NotNull Conversation conversation, @NotNull Runnable onDelete) {
ConversationPanel(
@NotNull Project project,
@NotNull Conversation conversation,
@NotNull Runnable onDelete) {
super(new BorderLayout());
setBackground(JBColor.background());
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
SettingsState.getInstance().sync(conversation);
project.getService(StandardChatToolWindowContentManager.class).displayConversation(conversation);
project.getService(StandardChatToolWindowContentManager.class)
.displayConversation(conversation);
}
});
addStyles(isSelected(conversation));
@ -84,14 +84,16 @@ class ConversationPanel extends JPanel {
gbc.gridx = 1;
gbc.weightx = 0;
headerPanel.add(new IconActionButton("Delete conversation", AllIcons.Actions.GC, new DeleteConversationAction(onDelete)), gbc);
headerPanel.add(new IconActionButton(new DeleteConversationAction(onDelete)), gbc);
var bottomPanel = new JPanel(new BorderLayout());
bottomPanel.setBackground(getPanelBackgroundColor());
bottomPanel.add(new JLabel(conversation.getUpdatedOn()
.format(DateTimeFormatter.ofPattern("M/d/yyyy, h:mm:ss a"))), BorderLayout.WEST);
if (conversation.getModel() != null) {
bottomPanel.add(new ModelIconLabel(conversation.getClientCode(), conversation.getModel()), BorderLayout.EAST);
bottomPanel.add(
new ModelIconLabel(conversation.getClientCode(), conversation.getModel()),
BorderLayout.EAST);
}
var textPanel = new JPanel(new BorderLayout());