Ability to create new files from codegpt toolwindow editor (#219)

This commit is contained in:
Carl-Robert 2023-09-30 01:40:37 +03:00 committed by GitHub
parent 6490a2c8d5
commit e417ac8a03
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -3,6 +3,8 @@ package ee.carlrobert.codegpt.toolwindow.chat;
import static ee.carlrobert.codegpt.util.FileUtils.findFileNameExtensionMapping;
import com.intellij.icons.AllIcons;
import com.intellij.icons.AllIcons.Actions;
import com.intellij.ide.util.EditorHelper;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.ActionGroup;
import com.intellij.openapi.actionSystem.ActionManager;
@ -16,16 +18,25 @@ import com.intellij.openapi.editor.EditorKind;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.impl.ContextMenuPopupHandler;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogBuilder;
import com.intellij.openapi.ui.TextBrowseFolderListener;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.psi.PsiManager;
import com.intellij.testFramework.LightVirtualFile;
import com.intellij.ui.JBColor;
import com.intellij.ui.components.JBLabel;
import com.intellij.ui.components.JBTextField;
import com.intellij.util.ui.FormBuilder;
import com.intellij.util.ui.JBUI;
import ee.carlrobert.codegpt.actions.toolwindow.ReplaceCodeInMainEditorAction;
import ee.carlrobert.codegpt.toolwindow.IconActionButton;
import ee.carlrobert.codegpt.util.EditorUtils;
import ee.carlrobert.codegpt.util.FileUtils;
import ee.carlrobert.codegpt.util.OverlayUtils;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
@ -43,28 +54,45 @@ import org.jetbrains.annotations.NotNull;
public class ChatToolWindowTabPanelEditor implements Disposable {
private final Project project;
private final Editor editor;
private final Map.Entry<String, String> fileNameExtensionMapping;
public ChatToolWindowTabPanelEditor(Project project, String code, String language, Disposable disposableParent) {
public ChatToolWindowTabPanelEditor(
Project project,
String code,
String language,
Disposable disposableParent) {
this.project = project;
this.fileNameExtensionMapping = findFileNameExtensionMapping(language);
var fileName = "temp_" + DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now()) + fileNameExtensionMapping.getValue();
var lightVirtualFile = new LightVirtualFile(String.format("%s/%s", PathManager.getTempPath(), fileName), code);
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);
var document = FileDocumentManager.getInstance().getDocument(lightVirtualFile);
if (document == null) {
document = EditorFactory.getInstance().createDocument(code);
}
EditorUtils.disableHighlighting(project, document);
editor = EditorFactory.getInstance().createEditor(document, project, lightVirtualFile, true, EditorKind.UNTYPED);
String originalGroupId = ((EditorEx) editor).getContextMenuGroupId();
AnAction originalGroup = originalGroupId == null ? null : ActionManager.getInstance().getAction(originalGroupId);
editor = EditorFactory.getInstance().createEditor(
document,
project,
lightVirtualFile,
true,
EditorKind.UNTYPED);
DefaultActionGroup group = new DefaultActionGroup();
if (originalGroup instanceof ActionGroup) {
group.addAll(((ActionGroup) originalGroup).getChildren(null));
}
group.add(new ReplaceCodeInMainEditorAction());
String originalGroupId = ((EditorEx) editor).getContextMenuGroupId();
if (originalGroupId != null) {
AnAction originalGroup = ActionManager.getInstance().getAction(originalGroupId);
if (originalGroup instanceof ActionGroup) {
group.addAll(((ActionGroup) originalGroup).getChildren(null));
}
}
var editorEx = ((EditorEx) editor);
editorEx.installPopupHandler(new ContextMenuPopupHandler.Simple(group));
editorEx.setColorsScheme(EditorColorsManager.getInstance().getSchemeForCurrentUITheme());
@ -102,44 +130,105 @@ public class ChatToolWindowTabPanelEditor implements Disposable {
private JPanel createHeaderActions() {
var wrapper = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
wrapper.add(new IconActionButton("Copy", AllIcons.Actions.Copy, new AnAction() {
@Override
public void actionPerformed(@NotNull AnActionEvent event) {
StringSelection stringSelection = new StringSelection(editor.getDocument().getText());
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.setContents(stringSelection, null);
var locationOnScreen = ((MouseEvent) event.getInputEvent()).getLocationOnScreen();
locationOnScreen.y = locationOnScreen.y - 16;
OverlayUtils.showInfoBalloon("Code copied!", locationOnScreen);
}
}));
wrapper.add(new IconActionButton("New File", Actions.AddFile, new NewFileAction()));
wrapper.add(Box.createHorizontalStrut(8));
wrapper.add(new IconActionButton("Replace in Main Editor", AllIcons.Actions.Replace, new AnAction() {
@Override
public void actionPerformed(@NotNull AnActionEvent event) {
var project = event.getProject();
if (project != null) {
if (EditorUtils.isMainEditorTextSelected(project)) {
EditorUtils.replaceMainEditorSelection(project, editor.getDocument().getText());
} else {
var locationOnScreen = ((MouseEvent) event.getInputEvent()).getLocationOnScreen();
locationOnScreen.y = locationOnScreen.y - 16;
OverlayUtils.showWarningBalloon(
EditorUtils.getSelectedEditor(project) == null ? "Unable to locate a selected editor" : "Please select a target code before proceeding",
locationOnScreen);
}
}
}
}));
wrapper.add(new IconActionButton("Copy", AllIcons.Actions.Copy, new CopyAction()));
wrapper.add(Box.createHorizontalStrut(8));
wrapper.add(new IconActionButton(
"Replace in Main Editor",
AllIcons.Actions.Replace,
new ReplaceInMainEditorAction()));
return wrapper;
}
@Override
public void dispose() {
EditorFactory.getInstance().releaseEditor(editor);
}
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);
}
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
if (getDialogBuilder().show() == 0) {
var file = FileUtils.createFile(
textFieldWithBrowseButton.getText(),
fileNameTextField.getText(),
editor.getDocument().getText());
var virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file);
if (virtualFile == null) {
throw new RuntimeException("Couldn't find the saved virtual file");
}
var psiFile = PsiManager.getInstance(project).findFile(virtualFile);
if (psiFile == null) {
throw new RuntimeException("Couldn't find the saved psi file");
}
EditorHelper.openInEditor(psiFile);
}
}
private DialogBuilder getDialogBuilder() {
var dialogBuilder = new DialogBuilder(project);
dialogBuilder.setTitle("New File");
dialogBuilder.setCenterPanel(FormBuilder.createFormBuilder()
.addLabeledComponent("File name:", fileNameTextField)
.addLabeledComponent("Destination:", textFieldWithBrowseButton)
.getPanel());
dialogBuilder.addOkAction();
dialogBuilder.addCancelAction();
return dialogBuilder;
}
}
class CopyAction extends AnAction {
@Override
public void actionPerformed(@NotNull AnActionEvent event) {
StringSelection stringSelection = new StringSelection(editor.getDocument().getText());
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.setContents(stringSelection, null);
var locationOnScreen = ((MouseEvent) event.getInputEvent()).getLocationOnScreen();
locationOnScreen.y = locationOnScreen.y - 16;
OverlayUtils.showInfoBalloon("Code copied!", locationOnScreen);
}
}
class ReplaceInMainEditorAction extends AnAction {
@Override
public void actionPerformed(@NotNull AnActionEvent event) {
var project = event.getProject();
if (project != null) {
if (EditorUtils.isMainEditorTextSelected(project)) {
EditorUtils.replaceMainEditorSelection(project, editor.getDocument().getText());
} else {
var locationOnScreen = ((MouseEvent) event.getInputEvent()).getLocationOnScreen();
locationOnScreen.y = locationOnScreen.y - 16;
OverlayUtils.showWarningBalloon(
EditorUtils.getSelectedEditor(project) == null
? "Unable to locate a selected editor"
: "Please select a target code before proceeding",
locationOnScreen);
}
}
}
}
}