mirror of
https://github.com/carlrobertoh/ProxyAI.git
synced 2026-05-12 05:51:28 +00:00
Update toolwindow UI (#290)
This commit is contained in:
parent
3797126de4
commit
1df20ccb86
38 changed files with 538 additions and 356 deletions
|
|
@ -5,13 +5,15 @@ import javax.swing.Icon;
|
|||
|
||||
public final class Icons {
|
||||
|
||||
public static final Icon DefaultIcon = IconLoader.getIcon("/icons/codegpt.svg", Icons.class);
|
||||
public static final Icon DefaultSmallIcon =
|
||||
public static final Icon Default = IconLoader.getIcon("/icons/codegpt.svg", Icons.class);
|
||||
public static final Icon DefaultSmall =
|
||||
IconLoader.getIcon("/icons/codegpt-small.svg", Icons.class);
|
||||
public static final Icon AzureIcon = IconLoader.getIcon("/icons/azure.svg", Icons.class);
|
||||
public static final Icon LlamaIcon = IconLoader.getIcon("/icons/llama.svg", Icons.class);
|
||||
public static final Icon OpenAIIcon = IconLoader.getIcon("/icons/openai.svg", Icons.class);
|
||||
public static final Icon SendIcon = IconLoader.getIcon("/icons/send.svg", Icons.class);
|
||||
public static final Icon SparkleIcon = IconLoader.getIcon("/icons/sparkle.svg", Icons.class);
|
||||
public static final Icon YouIcon = IconLoader.getIcon("/icons/you.svg", Icons.class);
|
||||
public static final Icon Azure = IconLoader.getIcon("/icons/azure.svg", Icons.class);
|
||||
public static final Icon Llama = IconLoader.getIcon("/icons/llama.svg", Icons.class);
|
||||
public static final Icon OpenAI = IconLoader.getIcon("/icons/openai.svg", Icons.class);
|
||||
public static final Icon Send = IconLoader.getIcon("/icons/send.svg", Icons.class);
|
||||
public static final Icon Sparkle = IconLoader.getIcon("/icons/sparkle.svg", Icons.class);
|
||||
public static final Icon You = IconLoader.getIcon("/icons/you.svg", Icons.class);
|
||||
public static final Icon YouSmall = IconLoader.getIcon("/icons/you_small.png", Icons.class);
|
||||
public static final Icon User = IconLoader.getIcon("/icons/user.svg", Icons.class);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ public class GenerateGitCommitMessageAction extends AnAction {
|
|||
super(
|
||||
CodeGPTBundle.get("action.generateCommitMessage.title"),
|
||||
CodeGPTBundle.get("action.generateCommitMessage.description"),
|
||||
Icons.SparkleIcon);
|
||||
Icons.Sparkle);
|
||||
encodingManager = EncodingManager.getInstance();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import org.jetbrains.annotations.NotNull;
|
|||
public class AskAction extends AnAction {
|
||||
|
||||
public AskAction() {
|
||||
super("New Chat", "Chat with CodeGPT", Icons.SparkleIcon);
|
||||
super("New Chat", "Chat with CodeGPT", Icons.Sparkle);
|
||||
EditorActionsUtil.registerOrReplaceAction(this);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package ee.carlrobert.codegpt.actions.toolwindow;
|
||||
|
||||
import static ee.carlrobert.codegpt.Icons.DefaultIcon;
|
||||
import static ee.carlrobert.codegpt.Icons.Default;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
|
|
@ -37,7 +37,7 @@ public class DeleteAllConversationsAction extends AnAction {
|
|||
int answer = Messages.showYesNoDialog(
|
||||
"Are you sure you want to delete all conversations?",
|
||||
"Clear History",
|
||||
DefaultIcon);
|
||||
Default);
|
||||
if (answer == Messages.YES) {
|
||||
var project = event.getProject();
|
||||
if (project != null) {
|
||||
|
|
|
|||
|
|
@ -100,8 +100,10 @@ public class CompletionRequestProvider {
|
|||
COMPLETION_SYSTEM_PROMPT,
|
||||
message.getPrompt(),
|
||||
conversation.getMessages());
|
||||
var configuration = ConfigurationState.getInstance();
|
||||
return new LlamaCompletionRequest.Builder(prompt)
|
||||
.setN_predict(512)
|
||||
.setN_predict(configuration.getMaxTokens())
|
||||
.setTemperature(configuration.getTemperature())
|
||||
.build();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ public class MethodNameLookupListener implements LookupManagerListener {
|
|||
for (var value : response.split(",")) {
|
||||
application.runReadAction(() -> {
|
||||
lookup.addItem(
|
||||
LookupElementBuilder.create(value.trim()).withIcon(Icons.SparkleIcon),
|
||||
LookupElementBuilder.create(value.trim()).withIcon(Icons.Sparkle),
|
||||
PrefixMatcher.ALWAYS_TRUE);
|
||||
});
|
||||
application.invokeLater(() -> lookup.refreshUi(true, true));
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ public class ConfigurationState implements PersistentStateComponent<Configuratio
|
|||
|
||||
private String systemPrompt = COMPLETION_SYSTEM_PROMPT;
|
||||
private int maxTokens = 1000;
|
||||
private double temperature = 0.2;
|
||||
private double temperature = 0.1;
|
||||
private boolean createNewChatOnEachAction;
|
||||
private boolean ignoreGitCommitTokenLimit;
|
||||
private boolean methodNameGenerationEnabled = true;
|
||||
|
|
|
|||
|
|
@ -11,21 +11,21 @@ public class ModelIconLabel extends JBLabel {
|
|||
|
||||
public ModelIconLabel(String clientCode, String modelCode) {
|
||||
if ("you.chat.completion".equals(clientCode)) {
|
||||
setIcon(Icons.YouIcon);
|
||||
setIcon(Icons.You);
|
||||
return;
|
||||
}
|
||||
|
||||
if ("chat.completion".equals(clientCode)) {
|
||||
setIcon(Icons.OpenAIIcon);
|
||||
setIcon(Icons.OpenAI);
|
||||
}
|
||||
if ("azure.chat.completion".equals(clientCode)) {
|
||||
setIcon(Icons.AzureIcon);
|
||||
setIcon(Icons.Azure);
|
||||
}
|
||||
if ("llama.chat.completion".equals(clientCode)) {
|
||||
setIcon(Icons.LlamaIcon);
|
||||
setIcon(Icons.Llama);
|
||||
}
|
||||
setText(formatModelName(modelCode));
|
||||
setFont(JBFont.small().asBold());
|
||||
setFont(JBFont.small());
|
||||
setHorizontalAlignment(SwingConstants.LEADING);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package ee.carlrobert.codegpt.toolwindow.chat;
|
||||
|
||||
import static ee.carlrobert.codegpt.util.UIUtil.createScrollPaneWithSmartScroller;
|
||||
import static ee.carlrobert.codegpt.util.UIUtil.getPanelBackgroundColor;
|
||||
import static java.lang.String.format;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
|
|
@ -16,6 +15,7 @@ import ee.carlrobert.codegpt.completions.CompletionRequestService;
|
|||
import ee.carlrobert.codegpt.conversations.Conversation;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationService;
|
||||
import ee.carlrobert.codegpt.conversations.message.Message;
|
||||
import ee.carlrobert.codegpt.settings.service.ServiceType;
|
||||
import ee.carlrobert.codegpt.settings.state.SettingsState;
|
||||
import ee.carlrobert.codegpt.telemetry.TelemetryAction;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.components.ChatMessageResponseBody;
|
||||
|
|
@ -24,6 +24,7 @@ import ee.carlrobert.codegpt.toolwindow.chat.components.TotalTokensPanel;
|
|||
import ee.carlrobert.codegpt.toolwindow.chat.components.UserMessagePanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.components.UserPromptTextArea;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.components.UserPromptTextAreaHeader;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.standard.StandardChatToolWindowContentManager;
|
||||
import ee.carlrobert.codegpt.util.EditorUtil;
|
||||
import ee.carlrobert.codegpt.util.file.FileUtil;
|
||||
import java.awt.BorderLayout;
|
||||
|
|
@ -65,7 +66,7 @@ public abstract class BaseChatToolWindowTabPanel implements ChatToolWindowTabPan
|
|||
EditorUtil.getSelectedEditorSelectedText(project),
|
||||
this);
|
||||
userPromptTextArea = new UserPromptTextArea(this::handleSubmit, totalTokensPanel);
|
||||
rootPanel = createRootPanel(settings);
|
||||
rootPanel = createRootPanel(settings.getSelectedService());
|
||||
userPromptTextArea.requestFocusInWindow();
|
||||
userPromptTextArea.requestFocus();
|
||||
}
|
||||
|
|
@ -201,18 +202,21 @@ public abstract class BaseChatToolWindowTabPanel implements ChatToolWindowTabPan
|
|||
sendMessage(message);
|
||||
}
|
||||
|
||||
private JPanel createUserPromptPanel(SettingsState settings) {
|
||||
private JPanel createUserPromptPanel(ServiceType selectedService) {
|
||||
var panel = new JPanel(new BorderLayout());
|
||||
panel.setBorder(JBUI.Borders.compound(
|
||||
JBUI.Borders.customLine(JBColor.border(), 1, 0, 0, 0),
|
||||
JBUI.Borders.empty(8)));
|
||||
panel.setBackground(getPanelBackgroundColor());
|
||||
panel.add(new UserPromptTextAreaHeader(settings, totalTokensPanel), BorderLayout.NORTH);
|
||||
panel.add(userPromptTextArea, BorderLayout.SOUTH);
|
||||
var contentManager = project.getService(StandardChatToolWindowContentManager.class);
|
||||
panel.add(JBUI.Panels.simplePanel(new UserPromptTextAreaHeader(
|
||||
selectedService,
|
||||
totalTokensPanel,
|
||||
contentManager::createNewTabPanel)), BorderLayout.NORTH);
|
||||
panel.add(JBUI.Panels.simplePanel(userPromptTextArea), BorderLayout.CENTER);
|
||||
return panel;
|
||||
}
|
||||
|
||||
private JPanel createRootPanel(SettingsState settings) {
|
||||
private JPanel createRootPanel(ServiceType selectedService) {
|
||||
var gbc = new GridBagConstraints();
|
||||
gbc.fill = GridBagConstraints.BOTH;
|
||||
gbc.weighty = 1;
|
||||
|
|
@ -226,7 +230,7 @@ public abstract class BaseChatToolWindowTabPanel implements ChatToolWindowTabPan
|
|||
gbc.weighty = 0;
|
||||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
||||
gbc.gridy = 1;
|
||||
rootPanel.add(createUserPromptPanel(settings), gbc);
|
||||
rootPanel.add(createUserPromptPanel(selectedService), gbc);
|
||||
return rootPanel;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,5 @@
|
|||
package ee.carlrobert.codegpt.toolwindow.chat;
|
||||
|
||||
import static ee.carlrobert.codegpt.util.UIUtil.getPanelBackgroundColor;
|
||||
|
||||
import com.intellij.openapi.roots.ui.componentsList.components.ScrollablePanel;
|
||||
import com.intellij.openapi.roots.ui.componentsList.layout.VerticalStackLayout;
|
||||
import ee.carlrobert.codegpt.completions.you.YouUserManager;
|
||||
|
|
@ -73,7 +71,7 @@ public class ChatToolWindowScrollablePanel extends ScrollablePanel {
|
|||
|
||||
// TODO: Move
|
||||
private JTextPane createYouCouponTextPane() {
|
||||
var textPane = UIUtil.createTextPane(
|
||||
return UIUtil.createTextPane(
|
||||
"<html>\n"
|
||||
+ "<body>\n"
|
||||
+ " <p style=\"margin: 4px 0;\">Use CodeGPT coupon for free month of GPT-4.</p>\n"
|
||||
|
|
@ -81,10 +79,7 @@ public class ChatToolWindowScrollablePanel extends ScrollablePanel {
|
|||
+ " <a href=\"https://you.com/plans\">Sign up here</a>\n"
|
||||
+ " </p>\n"
|
||||
+ "</body>\n"
|
||||
+ "</html>"
|
||||
);
|
||||
textPane.setBackground(getPanelBackgroundColor());
|
||||
textPane.setFocusable(false);
|
||||
return textPane;
|
||||
+ "</html>",
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ import com.intellij.ui.ColorUtil;
|
|||
import com.intellij.ui.JBColor;
|
||||
import com.vladsch.flexmark.ast.BulletListItem;
|
||||
import com.vladsch.flexmark.ast.Code;
|
||||
import com.vladsch.flexmark.ast.CodeBlock;
|
||||
import com.vladsch.flexmark.ast.Heading;
|
||||
import com.vladsch.flexmark.ast.OrderedListItem;
|
||||
import com.vladsch.flexmark.ast.Paragraph;
|
||||
import com.vladsch.flexmark.html.HtmlWriter;
|
||||
|
|
@ -21,12 +23,23 @@ public class ResponseNodeRenderer implements NodeRenderer {
|
|||
public Set<NodeRenderingHandler<?>> getNodeRenderingHandlers() {
|
||||
return Set.of(
|
||||
new NodeRenderingHandler<>(Paragraph.class, this::renderParagraph),
|
||||
new NodeRenderingHandler<>(Code.class, this::renderCode)
|
||||
new NodeRenderingHandler<>(Code.class, this::renderCode),
|
||||
new NodeRenderingHandler<>(CodeBlock.class, this::renderCodeBlock),
|
||||
new NodeRenderingHandler<>(BulletListItem.class, this::renderBulletListItem),
|
||||
new NodeRenderingHandler<>(Heading.class, this::renderHeading),
|
||||
new NodeRenderingHandler<>(OrderedListItem.class, this::renderOrderedListItem)
|
||||
);
|
||||
}
|
||||
|
||||
private void renderCode(Code node, NodeRendererContext context, HtmlWriter html) {
|
||||
html.attr("style", "color: " + ColorUtil.toHex(new JBColor(0x00627A, 0xCC7832)));
|
||||
private void renderCodeBlock(CodeBlock node, NodeRendererContext context, HtmlWriter html) {
|
||||
html.attr("style", "white-space: pre-wrap;");
|
||||
context.delegateRender();
|
||||
}
|
||||
|
||||
private void renderHeading(Heading node, NodeRendererContext context, HtmlWriter html) {
|
||||
if (node.getLevel() == 3) {
|
||||
html.attr("style", "margin-top: 4px; margin-bottom: 4px;");
|
||||
}
|
||||
context.delegateRender();
|
||||
}
|
||||
|
||||
|
|
@ -39,6 +52,27 @@ public class ResponseNodeRenderer implements NodeRenderer {
|
|||
context.delegateRender();
|
||||
}
|
||||
|
||||
private void renderCode(Code node, NodeRendererContext context, HtmlWriter html) {
|
||||
html.attr("style", "color: " + ColorUtil.toHex(new JBColor(0x00627A, 0xCC7832)));
|
||||
context.delegateRender();
|
||||
}
|
||||
|
||||
private void renderBulletListItem(
|
||||
BulletListItem node,
|
||||
NodeRendererContext context,
|
||||
HtmlWriter html) {
|
||||
html.attr("style", "margin-bottom: 4px;");
|
||||
context.delegateRender();
|
||||
}
|
||||
|
||||
private void renderOrderedListItem(
|
||||
OrderedListItem node,
|
||||
NodeRendererContext context,
|
||||
HtmlWriter html) {
|
||||
html.attr("style", "margin-bottom: 4px;");
|
||||
context.delegateRender();
|
||||
}
|
||||
|
||||
public static class Factory implements NodeRendererFactory {
|
||||
|
||||
@NotNull
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package ee.carlrobert.codegpt.toolwindow.chat.components;
|
||||
|
||||
import static ee.carlrobert.codegpt.util.UIUtil.getPanelBackgroundColor;
|
||||
import static java.lang.String.format;
|
||||
import static javax.swing.event.HyperlinkEvent.EventType.ACTIVATED;
|
||||
|
||||
|
|
@ -13,6 +12,7 @@ import com.intellij.openapi.project.Project;
|
|||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.ui.JBColor;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.vladsch.flexmark.ast.FencedCodeBlock;
|
||||
import com.vladsch.flexmark.html.HtmlRenderer;
|
||||
|
|
@ -36,7 +36,6 @@ import java.util.stream.Collectors;
|
|||
import javax.swing.BoxLayout;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextPane;
|
||||
import javax.swing.UIManager;
|
||||
|
||||
public class ChatMessageResponseBody extends JPanel {
|
||||
|
||||
|
|
@ -44,33 +43,23 @@ public class ChatMessageResponseBody extends JPanel {
|
|||
private final Disposable parentDisposable;
|
||||
private final StreamParser streamParser;
|
||||
private final boolean readOnly;
|
||||
private JPanel currentlyProcessedElement;
|
||||
private ResponseEditorPanel currentlyProcessedEditor;
|
||||
private JTextPane currentlyProcessedTextPane;
|
||||
private boolean responseReceived;
|
||||
|
||||
public ChatMessageResponseBody(Project project, Disposable parentDisposable) {
|
||||
this(project, getPanelBackgroundColor(), false, parentDisposable);
|
||||
this(project, false, parentDisposable);
|
||||
}
|
||||
|
||||
public ChatMessageResponseBody(
|
||||
Project project,
|
||||
boolean withGhostText,
|
||||
Disposable parentDisposable) {
|
||||
this(project, getPanelBackgroundColor(), withGhostText, parentDisposable);
|
||||
this(project, withGhostText, false, parentDisposable);
|
||||
}
|
||||
|
||||
public ChatMessageResponseBody(
|
||||
Project project,
|
||||
Color backgroundColor,
|
||||
boolean withGhostText,
|
||||
Disposable parentDisposable) {
|
||||
this(project, backgroundColor, withGhostText, false, parentDisposable);
|
||||
}
|
||||
|
||||
public ChatMessageResponseBody(
|
||||
Project project,
|
||||
Color backgroundColor,
|
||||
boolean withGhostText,
|
||||
boolean readOnly,
|
||||
Disposable parentDisposable) {
|
||||
|
|
@ -80,15 +69,13 @@ public class ChatMessageResponseBody extends JPanel {
|
|||
this.streamParser = new StreamParser();
|
||||
this.readOnly = readOnly;
|
||||
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
|
||||
setBackground(backgroundColor);
|
||||
setOpaque(false);
|
||||
|
||||
if (withGhostText) {
|
||||
prepareProcessingTextResponse(!readOnly);
|
||||
currentlyProcessedTextPane.setText(
|
||||
"<html><p style=\"margin-top: 4px; margin-bottom: 8px;\">‍</p></html>");
|
||||
}
|
||||
|
||||
UIManager.addPropertyChangeListener(propertyChangeEvent -> setBackground(backgroundColor));
|
||||
}
|
||||
|
||||
public ChatMessageResponseBody withResponse(String response) {
|
||||
|
|
@ -146,7 +133,7 @@ public class ChatMessageResponseBody extends JPanel {
|
|||
"<html><p style=\"margin-top: 4px; margin-bottom: 8px;\">%s</p></html>",
|
||||
message);
|
||||
if (responseReceived) {
|
||||
add(new ResponseWrapper().add(createTextPane(errorText, false)));
|
||||
add(createTextPane(errorText, false));
|
||||
} else {
|
||||
currentlyProcessedTextPane.setText(errorText);
|
||||
}
|
||||
|
|
@ -159,24 +146,12 @@ public class ChatMessageResponseBody extends JPanel {
|
|||
public void displaySerpResults(List<YouSerpResult> serpResults) {
|
||||
var html = getSearchResultsHtml(serpResults);
|
||||
if (responseReceived) {
|
||||
add(new ResponseWrapper().add(createTextPane(html, false)));
|
||||
add(createTextPane(html, false));
|
||||
} else {
|
||||
currentlyProcessedTextPane.setText(html);
|
||||
}
|
||||
}
|
||||
|
||||
private String getSearchResultsHtml(List<YouSerpResult> serpResults) {
|
||||
var titles = serpResults.stream()
|
||||
.map(result -> format("<li style=\"margin-bottom: 4px;\"><a href=\"%s\">%s</a></li>",
|
||||
result.getUrl(), result.getName()))
|
||||
.collect(Collectors.joining());
|
||||
return format(
|
||||
"<html>"
|
||||
+ "<p><strong>Search results:</strong></p>"
|
||||
+ "<ol>%s</ol>"
|
||||
+ "</html>", titles);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
removeAll();
|
||||
|
||||
|
|
@ -190,6 +165,18 @@ public class ChatMessageResponseBody extends JPanel {
|
|||
revalidate();
|
||||
}
|
||||
|
||||
private String getSearchResultsHtml(List<YouSerpResult> serpResults) {
|
||||
var titles = serpResults.stream()
|
||||
.map(result -> format("<li style=\"margin-bottom: 4px;\"><a href=\"%s\">%s</a></li>",
|
||||
result.getUrl(), result.getName()))
|
||||
.collect(Collectors.joining());
|
||||
return format(
|
||||
"<html>"
|
||||
+ "<p><strong>Search results:</strong></p>"
|
||||
+ "<ol>%s</ol>"
|
||||
+ "</html>", titles);
|
||||
}
|
||||
|
||||
private void processResponse(String markdownInput, boolean codeResponse, boolean caretVisible) {
|
||||
responseReceived = true;
|
||||
|
||||
|
|
@ -225,24 +212,17 @@ public class ChatMessageResponseBody extends JPanel {
|
|||
private void prepareProcessingTextResponse(boolean caretVisible) {
|
||||
currentlyProcessedEditor = null;
|
||||
currentlyProcessedTextPane = createTextPane("", caretVisible);
|
||||
currentlyProcessedElement = new ResponseWrapper();
|
||||
currentlyProcessedElement.add(currentlyProcessedTextPane);
|
||||
add(currentlyProcessedElement);
|
||||
add(currentlyProcessedTextPane);
|
||||
}
|
||||
|
||||
private void prepareProcessingCodeResponse(String code, String markdownLanguage) {
|
||||
currentlyProcessedTextPane.getCaret().setVisible(false);
|
||||
if (currentlyProcessedTextPane != null) {
|
||||
currentlyProcessedTextPane.getCaret().setVisible(false);
|
||||
}
|
||||
currentlyProcessedTextPane = null;
|
||||
currentlyProcessedEditor = new ResponseEditorPanel(
|
||||
project,
|
||||
code,
|
||||
markdownLanguage,
|
||||
readOnly,
|
||||
getPanelBackgroundColor(),
|
||||
parentDisposable);
|
||||
currentlyProcessedElement = new ResponseWrapper();
|
||||
currentlyProcessedElement.add(currentlyProcessedEditor);
|
||||
add(currentlyProcessedElement);
|
||||
currentlyProcessedEditor =
|
||||
new ResponseEditorPanel(project, code, markdownLanguage, readOnly, parentDisposable);
|
||||
add(currentlyProcessedEditor);
|
||||
}
|
||||
|
||||
private void updateEditorDocument(String code) {
|
||||
|
|
@ -250,8 +230,11 @@ public class ChatMessageResponseBody extends JPanel {
|
|||
var document = editor.getDocument();
|
||||
var application = ApplicationManager.getApplication();
|
||||
Runnable updateDocumentRunnable = () -> application.runWriteAction(() ->
|
||||
WriteCommandAction.runWriteCommandAction(project, () ->
|
||||
document.replaceString(0, document.getTextLength(), code)));
|
||||
WriteCommandAction.runWriteCommandAction(project, () -> {
|
||||
document.replaceString(0, document.getTextLength(), code);
|
||||
editor.getComponent().repaint();
|
||||
editor.getComponent().revalidate();
|
||||
}));
|
||||
|
||||
if (application.isUnitTestMode()) {
|
||||
application.invokeAndWait(updateDocumentRunnable);
|
||||
|
|
@ -261,7 +244,7 @@ public class ChatMessageResponseBody extends JPanel {
|
|||
}
|
||||
|
||||
private JTextPane createTextPane(String text, boolean caretVisible) {
|
||||
var textPane = UIUtil.createTextPane(text, event -> {
|
||||
var textPane = UIUtil.createTextPane(text, false, event -> {
|
||||
if (FileUtil.exists(event.getDescription()) && ACTIVATED.equals(event.getEventType())) {
|
||||
VirtualFile file = LocalFileSystem.getInstance().findFileByPath(event.getDescription());
|
||||
FileEditorManager.getInstance(project).openFile(Objects.requireNonNull(file), true);
|
||||
|
|
@ -275,7 +258,6 @@ public class ChatMessageResponseBody extends JPanel {
|
|||
textPane.setCaretPosition(textPane.getDocument().getLength());
|
||||
}
|
||||
textPane.setBorder(JBUI.Borders.empty());
|
||||
textPane.setBackground(getBackground());
|
||||
return textPane;
|
||||
}
|
||||
|
||||
|
|
@ -287,15 +269,4 @@ public class ChatMessageResponseBody extends JPanel {
|
|||
.build()
|
||||
.render(document);
|
||||
}
|
||||
|
||||
private static class ResponseWrapper extends JPanel {
|
||||
|
||||
ResponseWrapper() {
|
||||
super(new BorderLayout());
|
||||
setBorder(JBUI.Borders.empty());
|
||||
setBackground(getBackground());
|
||||
|
||||
UIManager.addPropertyChangeListener(propertyChangeEvent -> setBackground(getBackground()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,8 @@
|
|||
package ee.carlrobert.codegpt.toolwindow.chat.components;
|
||||
|
||||
import static ee.carlrobert.codegpt.util.UIUtil.getPanelBackgroundColor;
|
||||
|
||||
import com.intellij.icons.AllIcons.Actions;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.ui.JBColor;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
import com.intellij.util.ui.JBFont;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
|
|
@ -66,7 +63,6 @@ public class ResponsePanel extends JPanel {
|
|||
|
||||
Header() {
|
||||
super(new BorderLayout());
|
||||
setBackground(getPanelBackgroundColor());
|
||||
setBorder(JBUI.Borders.empty(12, 8, 4, 8));
|
||||
add(getIconLabel(), BorderLayout.LINE_START);
|
||||
|
||||
|
|
@ -118,7 +114,7 @@ public class ResponsePanel extends JPanel {
|
|||
private JBLabel getIconLabel() {
|
||||
return new JBLabel(
|
||||
CodeGPTBundle.get("project.label"),
|
||||
Icons.DefaultIcon,
|
||||
Icons.Default,
|
||||
SwingConstants.LEADING)
|
||||
.setAllowAutoWrapping(true)
|
||||
.withFont(JBFont.label().asBold());
|
||||
|
|
@ -131,10 +127,7 @@ public class ResponsePanel extends JPanel {
|
|||
|
||||
Body() {
|
||||
super(new BorderLayout());
|
||||
setBackground(getPanelBackgroundColor());
|
||||
setBorder(JBUI.Borders.compound(
|
||||
JBUI.Borders.customLine(JBColor.border(), 0, 0, 1, 0),
|
||||
JBUI.Borders.empty(4, 8, 8, 8)));
|
||||
setBorder(JBUI.Borders.empty(4, 8, 8, 8));
|
||||
}
|
||||
|
||||
public void addContent(JComponent content) {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import com.intellij.openapi.editor.event.EditorFactoryListener;
|
|||
import com.intellij.openapi.editor.event.SelectionEvent;
|
||||
import com.intellij.openapi.editor.event.SelectionListener;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import ee.carlrobert.codegpt.EncodingManager;
|
||||
import ee.carlrobert.codegpt.conversations.Conversation;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.TokenDetails;
|
||||
|
|
@ -35,6 +36,7 @@ public class TotalTokensPanel extends JPanel {
|
|||
@Nullable String highlightedText,
|
||||
Disposable parentDisposable) {
|
||||
super(new FlowLayout(FlowLayout.LEADING, 0, 0));
|
||||
setBorder(JBUI.Borders.empty(4));
|
||||
this.encodingManager = EncodingManager.getInstance();
|
||||
this.tokenDetails = createTokenDetails(conversation, highlightedText);
|
||||
this.label = getLabel(tokenDetails);
|
||||
|
|
|
|||
|
|
@ -2,38 +2,45 @@ package ee.carlrobert.codegpt.toolwindow.chat.components;
|
|||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.ui.ColorUtil;
|
||||
import com.intellij.ui.JBColor;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
import com.intellij.util.ui.JBFont;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import ee.carlrobert.codegpt.Icons;
|
||||
import ee.carlrobert.codegpt.conversations.message.Message;
|
||||
import ee.carlrobert.codegpt.settings.state.SettingsState;
|
||||
import java.awt.BorderLayout;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.SwingConstants;
|
||||
|
||||
public class UserMessagePanel extends JPanel {
|
||||
|
||||
public UserMessagePanel(Project project, Message message, Disposable parentDisposable) {
|
||||
super(new BorderLayout());
|
||||
setBorder(JBUI.Borders.compound(
|
||||
JBUI.Borders.customLine(JBColor.border(), 0, 0, 1, 0),
|
||||
JBUI.Borders.customLine(JBColor.border(), 1, 0, 1, 0),
|
||||
JBUI.Borders.empty(12, 8, 8, 8)));
|
||||
add(createDisplayNameWrapper(), BorderLayout.NORTH);
|
||||
add(new ChatMessageResponseBody(
|
||||
project,
|
||||
UIUtil.getPanelBackground(),
|
||||
false,
|
||||
true,
|
||||
parentDisposable).withResponse(message.getPrompt()),
|
||||
BorderLayout.SOUTH);
|
||||
setBackground(ColorUtil.brighter(getBackground(), 2));
|
||||
add(createDisplayNameLabel(), BorderLayout.NORTH);
|
||||
add(createResponseBody(project, message, parentDisposable), BorderLayout.SOUTH);
|
||||
}
|
||||
|
||||
private JPanel createDisplayNameWrapper() {
|
||||
return JBUI.Panels.simplePanel()
|
||||
.withBorder(JBUI.Borders.emptyBottom(6))
|
||||
.addToLeft(new JBLabel(SettingsState.getInstance().getDisplayName())
|
||||
.setAllowAutoWrapping(true)
|
||||
.withFont(JBFont.label().asBold()));
|
||||
private ChatMessageResponseBody createResponseBody(
|
||||
Project project,
|
||||
Message message,
|
||||
Disposable parentDisposable) {
|
||||
return new ChatMessageResponseBody(project, false, true, parentDisposable)
|
||||
.withResponse(message.getPrompt());
|
||||
}
|
||||
|
||||
private JBLabel createDisplayNameLabel() {
|
||||
return new JBLabel(
|
||||
SettingsState.getInstance().getDisplayName(),
|
||||
Icons.User,
|
||||
SwingConstants.LEADING)
|
||||
.setAllowAutoWrapping(true)
|
||||
.withFont(JBFont.label().asBold())
|
||||
.withBorder(JBUI.Borders.emptyBottom(6));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ public class UserPromptTextArea extends JPanel {
|
|||
private boolean submitEnabled = true;
|
||||
|
||||
public UserPromptTextArea(Consumer<String> onSubmit, TotalTokensPanel totalTokensPanel) {
|
||||
super(new BorderLayout());
|
||||
this.onSubmit = onSubmit;
|
||||
|
||||
textArea = new JBTextArea();
|
||||
|
|
@ -160,7 +161,6 @@ public class UserPromptTextArea extends JPanel {
|
|||
|
||||
private void init() {
|
||||
setOpaque(false);
|
||||
setLayout(new BorderLayout());
|
||||
add(textArea, BorderLayout.CENTER);
|
||||
|
||||
stopButton = createIconButton(AllIcons.Actions.Suspend, null);
|
||||
|
|
@ -168,9 +168,9 @@ public class UserPromptTextArea extends JPanel {
|
|||
var flowLayout = new FlowLayout(FlowLayout.RIGHT);
|
||||
flowLayout.setHgap(8);
|
||||
iconsPanel = new JPanel(flowLayout);
|
||||
iconsPanel.add(createIconButton(Icons.SendIcon, this::handleSubmit));
|
||||
iconsPanel.add(createIconButton(Icons.Send, this::handleSubmit));
|
||||
iconsPanel.add(stopButton);
|
||||
add(JBUI.Panels.simplePanel().addToBottom(iconsPanel), BorderLayout.EAST);
|
||||
add(iconsPanel, BorderLayout.EAST);
|
||||
}
|
||||
|
||||
private void updateFont() {
|
||||
|
|
|
|||
|
|
@ -1,26 +1,27 @@
|
|||
package ee.carlrobert.codegpt.toolwindow.chat.components;
|
||||
|
||||
import static ee.carlrobert.codegpt.util.UIUtil.getPanelBackgroundColor;
|
||||
|
||||
import com.intellij.openapi.actionSystem.ActionPlaces;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.ui.components.JBCheckBox;
|
||||
import com.intellij.util.messages.MessageBusConnection;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.ui.JBUI.Borders;
|
||||
import ee.carlrobert.codegpt.completions.you.YouSubscriptionNotifier;
|
||||
import ee.carlrobert.codegpt.completions.you.auth.SignedOutNotifier;
|
||||
import ee.carlrobert.codegpt.settings.state.SettingsState;
|
||||
import ee.carlrobert.codegpt.toolwindow.ModelIconLabel;
|
||||
import ee.carlrobert.codegpt.settings.service.ServiceType;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.standard.ModelComboBoxAction;
|
||||
import java.awt.BorderLayout;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
public class UserPromptTextAreaHeader extends JPanel {
|
||||
|
||||
public UserPromptTextAreaHeader(SettingsState settings, TotalTokensPanel totalTokensPanel) {
|
||||
public UserPromptTextAreaHeader(
|
||||
ServiceType selectedService,
|
||||
TotalTokensPanel totalTokensPanel,
|
||||
Runnable onAddNewTab) {
|
||||
super(new BorderLayout());
|
||||
setBackground(getPanelBackgroundColor());
|
||||
setBorder(JBUI.Borders.emptyBottom(8));
|
||||
switch (settings.getSelectedService()) {
|
||||
setOpaque(false);
|
||||
setBorder(JBUI.Borders.emptyBottom(4));
|
||||
switch (selectedService) {
|
||||
case OPENAI:
|
||||
case AZURE:
|
||||
add(totalTokensPanel, BorderLayout.LINE_START);
|
||||
|
|
@ -32,12 +33,8 @@ public class UserPromptTextAreaHeader extends JPanel {
|
|||
break;
|
||||
default:
|
||||
}
|
||||
add(JBUI.Panels
|
||||
.simplePanel(new ModelIconLabel(
|
||||
settings.getSelectedService().getCompletionCode(),
|
||||
settings.getModel()))
|
||||
.withBorder(Borders.emptyRight(4))
|
||||
.withBackground(getPanelBackgroundColor()), BorderLayout.LINE_END);
|
||||
add(new ModelComboBoxAction(onAddNewTab, selectedService)
|
||||
.createCustomComponent(ActionPlaces.UNKNOWN), BorderLayout.LINE_END);
|
||||
}
|
||||
|
||||
private void subscribeToYouTopics(JBCheckBox gpt4CheckBox) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package ee.carlrobert.codegpt.toolwindow.chat.contextual;
|
||||
|
||||
import static com.intellij.openapi.ui.DialogWrapper.OK_EXIT_CODE;
|
||||
import static ee.carlrobert.codegpt.util.UIUtil.getPanelBackgroundColor;
|
||||
import static javax.swing.event.HyperlinkEvent.EventType.ACTIVATED;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
|
|
@ -37,7 +36,7 @@ class ContextualChatToolWindowLandingPanel extends ResponsePanel {
|
|||
}
|
||||
|
||||
private JTextPane createContent() {
|
||||
var description = createTextPane();
|
||||
var description = UIUtil.createTextPane("", false, this::handleHyperlinkClicked);
|
||||
if (VectorStore.getInstance(CodeGPTPlugin.getPluginBasePath()).isIndexExists()) {
|
||||
description.setText("<html>"
|
||||
+ "<p style=\"margin-top: 4px; margin-bottom: 4px;\">"
|
||||
|
|
@ -76,12 +75,6 @@ class ContextualChatToolWindowLandingPanel extends ResponsePanel {
|
|||
return description;
|
||||
}
|
||||
|
||||
private JTextPane createTextPane() {
|
||||
var textPane = UIUtil.createTextPane("", this::handleHyperlinkClicked);
|
||||
textPane.setBackground(getPanelBackgroundColor());
|
||||
return textPane;
|
||||
}
|
||||
|
||||
private void handleHyperlinkClicked(HyperlinkEvent event) {
|
||||
if (ACTIVATED.equals(event.getEventType())) {
|
||||
if (event.getURL() == null) {
|
||||
|
|
|
|||
|
|
@ -7,18 +7,23 @@ import com.intellij.icons.AllIcons.General;
|
|||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.actionSystem.ActionGroup;
|
||||
import com.intellij.openapi.actionSystem.ActionManager;
|
||||
import com.intellij.openapi.actionSystem.ActionToolbar;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.DefaultActionGroup;
|
||||
import com.intellij.openapi.actionSystem.DefaultCompactActionGroup;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.EditorFactory;
|
||||
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.project.Project;
|
||||
import com.intellij.openapi.ui.JBMenuItem;
|
||||
import com.intellij.openapi.ui.JBPopupMenu;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.ui.JBColor;
|
||||
import com.intellij.ui.ColorUtil;
|
||||
import com.intellij.ui.IdeBorderFactory;
|
||||
import com.intellij.ui.components.ActionLink;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import ee.carlrobert.codegpt.CodeGPTBundle;
|
||||
import ee.carlrobert.codegpt.actions.toolwindow.ReplaceCodeInMainEditorAction;
|
||||
|
|
@ -30,34 +35,32 @@ import ee.carlrobert.codegpt.toolwindow.chat.editor.actions.NewFileAction;
|
|||
import ee.carlrobert.codegpt.toolwindow.chat.editor.actions.ReplaceSelectionAction;
|
||||
import ee.carlrobert.codegpt.util.EditorUtil;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.FlowLayout;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.JPanel;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ResponseEditorPanel extends JPanel implements Disposable {
|
||||
|
||||
private final Editor editor;
|
||||
private final String language;
|
||||
private final String extension;
|
||||
|
||||
public ResponseEditorPanel(
|
||||
Project project,
|
||||
String code,
|
||||
String markdownLanguage,
|
||||
boolean readOnly,
|
||||
Color backgroundColor,
|
||||
Disposable disposableParent) {
|
||||
super(new BorderLayout());
|
||||
setBorder(JBUI.Borders.empty(8, 0));
|
||||
setOpaque(false);
|
||||
|
||||
var extensionMapping = findLanguageExtensionMapping(markdownLanguage);
|
||||
language = extensionMapping.getKey();
|
||||
extension = extensionMapping.getValue();
|
||||
editor = EditorUtil.createEditor(project, extension, code);
|
||||
editor = EditorUtil.createEditor(
|
||||
project,
|
||||
findLanguageExtensionMapping(markdownLanguage).getValue(),
|
||||
code);
|
||||
|
||||
DefaultActionGroup group = new DefaultActionGroup();
|
||||
var group = new DefaultActionGroup();
|
||||
group.add(new ReplaceCodeInMainEditorAction());
|
||||
|
||||
String originalGroupId = ((EditorEx) editor).getContextMenuGroupId();
|
||||
if (originalGroupId != null) {
|
||||
AnAction originalGroup = ActionManager.getInstance().getAction(originalGroupId);
|
||||
|
|
@ -65,12 +68,12 @@ public class ResponseEditorPanel extends JPanel implements Disposable {
|
|||
group.addAll(((ActionGroup) originalGroup).getChildren(null));
|
||||
}
|
||||
}
|
||||
|
||||
configureEditor((EditorEx) editor, readOnly, new ContextMenuPopupHandler.Simple(group));
|
||||
|
||||
add(createHeaderComponent(readOnly), BorderLayout.NORTH);
|
||||
configureEditor(
|
||||
(EditorEx) editor,
|
||||
readOnly,
|
||||
new ContextMenuPopupHandler.Simple(group),
|
||||
findLanguageExtensionMapping(markdownLanguage).getValue());
|
||||
add(editor.getComponent(), BorderLayout.CENTER);
|
||||
add(createFooterComponent(readOnly ? getBackground() : backgroundColor), BorderLayout.SOUTH);
|
||||
|
||||
Disposer.register(disposableParent, this);
|
||||
}
|
||||
|
|
@ -87,7 +90,8 @@ public class ResponseEditorPanel extends JPanel implements Disposable {
|
|||
private void configureEditor(
|
||||
EditorEx editorEx,
|
||||
boolean readOnly,
|
||||
ContextMenuPopupHandler popupHandler) {
|
||||
ContextMenuPopupHandler popupHandler,
|
||||
String extension) {
|
||||
if (readOnly) {
|
||||
editorEx.setOneLineMode(true);
|
||||
editorEx.setHorizontalScrollbarVisible(false);
|
||||
|
|
@ -97,23 +101,32 @@ public class ResponseEditorPanel extends JPanel implements Disposable {
|
|||
|
||||
var settings = editorEx.getSettings();
|
||||
settings.setAdditionalColumnsCount(0);
|
||||
settings.setAdditionalLinesCount(1);
|
||||
settings.setAdditionalLinesCount(0);
|
||||
settings.setAdditionalPageAtBottom(false);
|
||||
settings.setVirtualSpace(false);
|
||||
settings.setUseSoftWraps(false);
|
||||
settings.setLineMarkerAreaShown(false);
|
||||
settings.setGutterIconsShown(false);
|
||||
settings.setLineNumbersShown(false);
|
||||
|
||||
editorEx.getGutterComponentEx().setVisible(true);
|
||||
editorEx.getGutterComponentEx().getParent().setVisible(false);
|
||||
editorEx.setVerticalScrollbarVisible(false);
|
||||
editorEx.getContentComponent().setBorder(JBUI.Borders.emptyLeft(4));
|
||||
editorEx.setBorder(IdeBorderFactory.createBorder(ColorUtil.fromHex("#48494b")));
|
||||
editorEx.setPermanentHeaderComponent(createHeaderComponent(editorEx, extension));
|
||||
editorEx.setHeaderComponent(null);
|
||||
}
|
||||
|
||||
private JPanel createHeaderComponent(boolean readOnly) {
|
||||
private JPanel createHeaderComponent(EditorEx editorEx, String extension) {
|
||||
var headerComponent = new JPanel(new BorderLayout());
|
||||
headerComponent.setBorder(JBUI.Borders.compound(
|
||||
JBUI.Borders.customLine(JBColor.border(), 1, 1, 1, 1),
|
||||
JBUI.Borders.empty(4, 8)));
|
||||
headerComponent.add(new JBLabel(language), BorderLayout.LINE_START);
|
||||
if (!readOnly) {
|
||||
headerComponent.add(createHeaderActions(), BorderLayout.LINE_END);
|
||||
}
|
||||
headerComponent.setBorder(
|
||||
JBUI.Borders.compound(
|
||||
JBUI.Borders.customLine(ColorUtil.fromHex("#48494b"), 1, 1, 0, 1),
|
||||
JBUI.Borders.empty(4)));
|
||||
headerComponent.add(createExpandLink(editorEx), BorderLayout.LINE_START);
|
||||
headerComponent.add(createHeaderActions(extension, editorEx).getComponent(),
|
||||
BorderLayout.LINE_END);
|
||||
return headerComponent;
|
||||
}
|
||||
|
||||
|
|
@ -125,8 +138,7 @@ public class ResponseEditorPanel extends JPanel implements Disposable {
|
|||
: CodeGPTBundle.get("toolwindow.chat.editor.action.collapse");
|
||||
}
|
||||
|
||||
private JPanel createFooterComponent(Color backgroundColor) {
|
||||
var editorEx = ((EditorEx) editor);
|
||||
private ActionLink createExpandLink(EditorEx editorEx) {
|
||||
var linkText = getLinkText(editorEx.isOneLineMode());
|
||||
var expandLink = new ActionLink(
|
||||
linkText,
|
||||
|
|
@ -134,32 +146,44 @@ public class ResponseEditorPanel extends JPanel implements Disposable {
|
|||
var oneLineMode = editorEx.isOneLineMode();
|
||||
var source = (ActionLink) event.getSource();
|
||||
source.setText(getLinkText(!oneLineMode));
|
||||
source.setIcon(oneLineMode ? General.ArrowUp : General.ArrowDown, true);
|
||||
source.setIcon(oneLineMode ? General.ArrowDown : General.ArrowRight);
|
||||
|
||||
editorEx.setOneLineMode(!oneLineMode);
|
||||
editorEx.setHorizontalScrollbarVisible(oneLineMode);
|
||||
editorEx.getContentComponent().revalidate();
|
||||
editorEx.getContentComponent().repaint();
|
||||
});
|
||||
expandLink.setIcon(editorEx.isOneLineMode() ? General.ArrowDown : General.ArrowUp, true);
|
||||
|
||||
var panel = new JPanel(new FlowLayout(FlowLayout.CENTER));
|
||||
panel.setBackground(backgroundColor);
|
||||
panel.add(expandLink);
|
||||
return panel;
|
||||
expandLink.setIcon(editorEx.isOneLineMode() ? General.ArrowRight : General.ArrowDown);
|
||||
return expandLink;
|
||||
}
|
||||
|
||||
private JPanel createHeaderActions() {
|
||||
private ActionToolbar createHeaderActions(String extension, EditorEx editorEx) {
|
||||
var actionGroup = new DefaultCompactActionGroup("EDITOR_TOOLBAR_ACTION_GROUP", false);
|
||||
actionGroup.add(new CopyAction(editor));
|
||||
actionGroup.add(new ReplaceSelectionAction(editor));
|
||||
actionGroup.addSeparator();
|
||||
|
||||
var wrapper = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
|
||||
wrapper.add(new IconActionButton(new DiffAction(editor)));
|
||||
wrapper.add(Box.createHorizontalStrut(8));
|
||||
wrapper.add(new IconActionButton(new EditAction(editor)));
|
||||
wrapper.add(Box.createHorizontalStrut(8));
|
||||
wrapper.add(new IconActionButton(new NewFileAction(editor, extension)));
|
||||
wrapper.add(Box.createHorizontalStrut(8));
|
||||
wrapper.add(new IconActionButton(new CopyAction(editor)));
|
||||
wrapper.add(Box.createHorizontalStrut(8));
|
||||
wrapper.add(Box.createHorizontalStrut(4));
|
||||
wrapper.add(new IconActionButton(new ReplaceSelectionAction(editor)));
|
||||
return wrapper;
|
||||
|
||||
var menu = new JBPopupMenu();
|
||||
menu.add(new JBMenuItem(new DiffAction(editorEx, menu.getLocation())));
|
||||
menu.add(new JBMenuItem(new EditAction(editorEx)));
|
||||
menu.add(new JBMenuItem(new NewFileAction(editorEx, extension)));
|
||||
|
||||
var toolbar = ActionManager.getInstance()
|
||||
.createActionToolbar("NAVIGATION_BAR_TOOLBAR", actionGroup, true);
|
||||
actionGroup.add(new AnAction("Editor Actions", "Editor Actions", General.GearPlain) {
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
menu.show(e.getInputEvent().getComponent(), 0, 0);
|
||||
}
|
||||
});
|
||||
toolbar.setLayoutPolicy(ActionToolbar.NOWRAP_LAYOUT_POLICY);
|
||||
toolbar.setTargetComponent(editorEx.getComponent());
|
||||
toolbar.getComponent().setBorder(JBUI.Borders.empty());
|
||||
return toolbar;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,35 +10,35 @@ import com.intellij.diff.util.DiffUserDataKeys;
|
|||
import com.intellij.diff.util.DiffUtil;
|
||||
import com.intellij.diff.util.Side;
|
||||
import com.intellij.icons.AllIcons.Actions;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.ex.EditorEx;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import ee.carlrobert.codegpt.CodeGPTBundle;
|
||||
import ee.carlrobert.codegpt.actions.ActionType;
|
||||
import ee.carlrobert.codegpt.actions.TrackableAction;
|
||||
import ee.carlrobert.codegpt.util.EditorUtil;
|
||||
import ee.carlrobert.codegpt.util.OverlayUtil;
|
||||
import ee.carlrobert.codegpt.util.file.FileUtil;
|
||||
import java.awt.Point;
|
||||
import java.awt.event.ActionEvent;
|
||||
import javax.swing.AbstractAction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class DiffAction extends TrackableAction {
|
||||
public class DiffAction extends AbstractAction {
|
||||
|
||||
public DiffAction(@NotNull Editor editor) {
|
||||
super(
|
||||
editor,
|
||||
CodeGPTBundle.get("toolwindow.chat.editor.action.diff.title"),
|
||||
CodeGPTBundle.get("toolwindow.chat.editor.action.diff.description"),
|
||||
Actions.DiffWithClipboard,
|
||||
ActionType.DIFF_CODE);
|
||||
private final EditorEx editor;
|
||||
private final Point locationOnScreen;
|
||||
|
||||
public DiffAction(@NotNull EditorEx editor, @NotNull Point locationOnScreen) {
|
||||
super("Diff", Actions.DiffWithClipboard);
|
||||
this.editor = editor;
|
||||
this.locationOnScreen = locationOnScreen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleAction(@NotNull AnActionEvent event) {
|
||||
var project = requireNonNull(event.getProject());
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
var project = requireNonNull(editor.getProject());
|
||||
var selectedTextEditor = FileEditorManager.getInstance(project).getSelectedTextEditor();
|
||||
if (!EditorUtil.hasSelection(selectedTextEditor)) {
|
||||
OverlayUtil.showSelectedEditorSelectionWarning(event);
|
||||
OverlayUtil.showSelectedEditorSelectionWarning(project, locationOnScreen);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,44 +1,38 @@
|
|||
package ee.carlrobert.codegpt.toolwindow.chat.editor.actions;
|
||||
|
||||
import com.intellij.icons.AllIcons.Actions;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.icons.AllIcons.Diff;
|
||||
import com.intellij.openapi.editor.ex.EditorEx;
|
||||
import com.intellij.openapi.ui.JBMenuItem;
|
||||
import ee.carlrobert.codegpt.CodeGPTBundle;
|
||||
import ee.carlrobert.codegpt.actions.ActionType;
|
||||
import ee.carlrobert.codegpt.actions.TrackableAction;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.ActionEvent;
|
||||
import javax.swing.AbstractAction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class EditAction extends TrackableAction {
|
||||
public class EditAction extends AbstractAction {
|
||||
|
||||
public EditAction(@NotNull Editor editor) {
|
||||
super(
|
||||
editor,
|
||||
CodeGPTBundle.get("toolwindow.chat.editor.action.edit.title"),
|
||||
CodeGPTBundle.get("toolwindow.chat.editor.action.edit.description"),
|
||||
Actions.EditSource,
|
||||
ActionType.EDIT_CODE);
|
||||
private final EditorEx editor;
|
||||
|
||||
public EditAction(@NotNull EditorEx editor) {
|
||||
super("Edit Source", Actions.EditSource);
|
||||
this.editor = editor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleAction(@NotNull AnActionEvent event) {
|
||||
var editorEx = ((EditorEx) editor);
|
||||
editorEx.setViewer(!editorEx.isViewer());
|
||||
public void actionPerformed(@NotNull ActionEvent event) {
|
||||
editor.setViewer(!editor.isViewer());
|
||||
|
||||
var viewer = editorEx.isViewer();
|
||||
editorEx.setCaretVisible(!viewer);
|
||||
editorEx.setCaretEnabled(!viewer);
|
||||
var viewer = editor.isViewer();
|
||||
editor.setCaretVisible(!viewer);
|
||||
editor.setCaretEnabled(!viewer);
|
||||
|
||||
var settings = editorEx.getSettings();
|
||||
var settings = editor.getSettings();
|
||||
settings.setCaretRowShown(!viewer);
|
||||
|
||||
event.getPresentation().setIcon(viewer ? Actions.EditSource : Actions.Show);
|
||||
event.getPresentation().setText(viewer
|
||||
var menuItem = (JBMenuItem) event.getSource();
|
||||
menuItem.setText(viewer
|
||||
? CodeGPTBundle.get("toolwindow.chat.editor.action.edit.title")
|
||||
: CodeGPTBundle.get("toolwindow.chat.editor.action.disableEditing.title"));
|
||||
|
||||
var locationOnScreen = ((MouseEvent) event.getInputEvent()).getLocationOnScreen();
|
||||
locationOnScreen.y = locationOnScreen.y - 16;
|
||||
menuItem.setIcon(viewer ? Actions.EditSource : Diff.Lock);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
package ee.carlrobert.codegpt.toolwindow.chat.editor.actions;
|
||||
|
||||
import static com.intellij.openapi.ui.DialogWrapper.OK_EXIT_CODE;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import com.intellij.icons.AllIcons.Actions;
|
||||
import com.intellij.ide.util.EditorHelper;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.ex.EditorEx;
|
||||
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogBuilder;
|
||||
|
|
@ -15,30 +15,25 @@ import com.intellij.openapi.vfs.LocalFileSystem;
|
|||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.ui.components.JBTextField;
|
||||
import com.intellij.util.ui.FormBuilder;
|
||||
import ee.carlrobert.codegpt.CodeGPTBundle;
|
||||
import ee.carlrobert.codegpt.actions.ActionType;
|
||||
import ee.carlrobert.codegpt.actions.TrackableAction;
|
||||
import ee.carlrobert.codegpt.util.file.FileUtil;
|
||||
import java.util.Objects;
|
||||
import java.awt.event.ActionEvent;
|
||||
import javax.swing.AbstractAction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class NewFileAction extends TrackableAction {
|
||||
public class NewFileAction extends AbstractAction {
|
||||
|
||||
private final String fileExtension;
|
||||
private final EditorEx editor;
|
||||
|
||||
public NewFileAction(@NotNull Editor editor, String fileExtension) {
|
||||
super(
|
||||
editor,
|
||||
CodeGPTBundle.get("toolwindow.chat.editor.action.newFile.title"),
|
||||
CodeGPTBundle.get("toolwindow.chat.editor.action.newFile.description"),
|
||||
Actions.AddFile,
|
||||
ActionType.CREATE_NEW_FILE);
|
||||
public NewFileAction(@NotNull EditorEx editor, String fileExtension) {
|
||||
super("Create New File", Actions.AddFile);
|
||||
this.fileExtension = fileExtension;
|
||||
this.editor = editor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleAction(@NotNull AnActionEvent e) {
|
||||
var project = Objects.requireNonNull(e.getProject());
|
||||
public void actionPerformed(@NotNull ActionEvent event) {
|
||||
var project = requireNonNull(editor.getProject());
|
||||
var fileChooserDescriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor();
|
||||
fileChooserDescriptor.setForcedToUseIdeaFileChooser(true);
|
||||
var textFieldWithBrowseButton = new TextFieldWithBrowseButton();
|
||||
|
|
|
|||
|
|
@ -3,24 +3,24 @@ package ee.carlrobert.codegpt.toolwindow.chat.standard;
|
|||
enum EditorAction {
|
||||
FIND_BUGS(
|
||||
"Find Bugs",
|
||||
"Find bugs in the following code",
|
||||
"Find bugs and output code with bugs fixed in the following code: {{selectedCode}}"),
|
||||
"Find bugs in the selected code",
|
||||
"Find bugs and output code with bugs fixed in the selected code: {{selectedCode}}"),
|
||||
WRITE_TESTS(
|
||||
"Write Tests",
|
||||
"Write Tests for the following code",
|
||||
"Write Tests for the following code: {{selectedCode}}"),
|
||||
"Write unit tests for the selected code",
|
||||
"Write unit tests for the selected code: {{selectedCode}}"),
|
||||
EXPLAIN(
|
||||
"Explain",
|
||||
"Explain the following code",
|
||||
"Explain the following code: {{selectedCode}}"),
|
||||
"Explain the selected code",
|
||||
"Explain the selected code: {{selectedCode}}"),
|
||||
REFACTOR(
|
||||
"Refactor",
|
||||
"Refactor the following code",
|
||||
"Refactor the following code: {{selectedCode}}"),
|
||||
"Refactor the selected code",
|
||||
"Refactor the selected code: {{selectedCode}}"),
|
||||
OPTIMIZE(
|
||||
"Optimize",
|
||||
"Optimize the following code",
|
||||
"Optimize the following code: {{selectedCode}}");
|
||||
"Optimize the selected code",
|
||||
"Optimize the selected code: {{selectedCode}}");
|
||||
|
||||
private final String label;
|
||||
private final String userMessage;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,158 @@
|
|||
package ee.carlrobert.codegpt.toolwindow.chat.standard;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.DefaultActionGroup;
|
||||
import com.intellij.openapi.actionSystem.Presentation;
|
||||
import com.intellij.openapi.actionSystem.ex.ComboBoxAction;
|
||||
import ee.carlrobert.codegpt.Icons;
|
||||
import ee.carlrobert.codegpt.completions.llama.LlamaModel;
|
||||
import ee.carlrobert.codegpt.settings.service.ServiceType;
|
||||
import ee.carlrobert.codegpt.settings.state.LlamaSettingsState;
|
||||
import ee.carlrobert.codegpt.settings.state.OpenAISettingsState;
|
||||
import ee.carlrobert.codegpt.settings.state.SettingsState;
|
||||
import ee.carlrobert.llm.client.openai.completion.chat.OpenAIChatCompletionModel;
|
||||
import java.util.List;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ModelComboBoxAction extends ComboBoxAction {
|
||||
|
||||
private final Runnable onAddNewTab;
|
||||
private final SettingsState settings;
|
||||
private final OpenAISettingsState openAISettings;
|
||||
|
||||
public ModelComboBoxAction(Runnable onAddNewTab, ServiceType selectedService) {
|
||||
this.onAddNewTab = onAddNewTab;
|
||||
settings = SettingsState.getInstance();
|
||||
openAISettings = OpenAISettingsState.getInstance();
|
||||
updateTemplatePresentation(selectedService);
|
||||
}
|
||||
|
||||
public JComponent createCustomComponent(@NotNull String place) {
|
||||
return createCustomComponent(getTemplatePresentation(), place);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JComponent createCustomComponent(
|
||||
@NotNull Presentation presentation,
|
||||
@NotNull String place) {
|
||||
ComboBoxButton button = createComboBoxButton(presentation);
|
||||
button.setBorder(null);
|
||||
return button;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull DefaultActionGroup createPopupActionGroup(JComponent button) {
|
||||
var presentation = ((ComboBoxButton) button).getPresentation();
|
||||
var actionGroup = new DefaultActionGroup();
|
||||
actionGroup.addSeparator("OpenAI");
|
||||
List.of(
|
||||
OpenAIChatCompletionModel.GPT_4_1106_128k,
|
||||
OpenAIChatCompletionModel.GPT_3_5_1106_16k,
|
||||
OpenAIChatCompletionModel.GPT_4_32k,
|
||||
OpenAIChatCompletionModel.GPT_4,
|
||||
OpenAIChatCompletionModel.GPT_3_5)
|
||||
.forEach(
|
||||
model -> actionGroup.add(createOpenAIModelAction(model, presentation)));
|
||||
actionGroup.addSeparator();
|
||||
actionGroup.add(
|
||||
createModelAction(ServiceType.AZURE, "Azure OpenAI", Icons.Azure, presentation));
|
||||
actionGroup.addSeparator();
|
||||
actionGroup.add(createModelAction(
|
||||
ServiceType.LLAMA_CPP,
|
||||
getSelectedHuggingFace(),
|
||||
Icons.Llama,
|
||||
presentation));
|
||||
actionGroup.addSeparator();
|
||||
actionGroup.add(createModelAction(ServiceType.YOU, "You.com", Icons.YouSmall, presentation));
|
||||
return actionGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldShowDisabledActions() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void updateTemplatePresentation(ServiceType selectedService) {
|
||||
var templatePresentation = getTemplatePresentation();
|
||||
switch (selectedService) {
|
||||
case OPENAI:
|
||||
templatePresentation.setIcon(Icons.OpenAI);
|
||||
templatePresentation.setText(
|
||||
OpenAIChatCompletionModel.findByCode(openAISettings.getModel()).getDescription());
|
||||
break;
|
||||
case AZURE:
|
||||
templatePresentation.setIcon(Icons.Azure);
|
||||
templatePresentation.setText("Azure OpenAI");
|
||||
break;
|
||||
case YOU:
|
||||
templatePresentation.setIcon(Icons.YouSmall);
|
||||
templatePresentation.setText("You.com");
|
||||
break;
|
||||
case LLAMA_CPP:
|
||||
templatePresentation.setText(getSelectedHuggingFace());
|
||||
templatePresentation.setIcon(Icons.Llama);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
private String getSelectedHuggingFace() {
|
||||
var huggingFaceModel = LlamaSettingsState.getInstance().getHuggingFaceModel();
|
||||
return format(
|
||||
"%s %dB (Q%d)",
|
||||
LlamaModel.findByHuggingFaceModel(huggingFaceModel).getLabel(),
|
||||
huggingFaceModel.getParameterSize(),
|
||||
huggingFaceModel.getQuantization());
|
||||
}
|
||||
|
||||
private AnAction createModelAction(
|
||||
ServiceType serviceType,
|
||||
String label,
|
||||
Icon icon,
|
||||
Presentation comboBoxPresentation) {
|
||||
return new AnAction(label, "", icon) {
|
||||
@Override
|
||||
public void update(@NotNull AnActionEvent event) {
|
||||
var presentation = event.getPresentation();
|
||||
presentation.setEnabled(!presentation.getText().equals(comboBoxPresentation.getText()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
settings.setSelectedService(serviceType);
|
||||
comboBoxPresentation.setIcon(icon);
|
||||
comboBoxPresentation.setText(label);
|
||||
onAddNewTab.run();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private AnAction createOpenAIModelAction(
|
||||
OpenAIChatCompletionModel model,
|
||||
Presentation comboBoxPresentation) {
|
||||
createModelAction(ServiceType.OPENAI, model.getDescription(), Icons.OpenAI,
|
||||
comboBoxPresentation);
|
||||
return new AnAction(model.getDescription(), "", Icons.OpenAI) {
|
||||
@Override
|
||||
public void update(@NotNull AnActionEvent event) {
|
||||
var presentation = event.getPresentation();
|
||||
presentation.setEnabled(!presentation.getText().equals(comboBoxPresentation.getText()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
settings.setSelectedService(ServiceType.OPENAI);
|
||||
openAISettings.setModel(model.getCode());
|
||||
comboBoxPresentation.setIcon(Icons.OpenAI);
|
||||
comboBoxPresentation.setText(model.getDescription());
|
||||
onAddNewTab.run();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,86 +1,70 @@
|
|||
package ee.carlrobert.codegpt.toolwindow.chat.standard;
|
||||
|
||||
import static ee.carlrobert.codegpt.util.UIUtil.getPanelBackgroundColor;
|
||||
import static java.lang.String.format;
|
||||
import static javax.swing.event.HyperlinkEvent.EventType.ACTIVATED;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.ui.components.ActionLink;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import ee.carlrobert.codegpt.Icons;
|
||||
import ee.carlrobert.codegpt.settings.state.SettingsState;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.components.ResponsePanel;
|
||||
import ee.carlrobert.codegpt.util.UIUtil;
|
||||
import java.awt.event.MouseEvent;
|
||||
import javax.swing.JTextPane;
|
||||
import javax.swing.event.HyperlinkEvent;
|
||||
import java.awt.BorderLayout;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
class StandardChatToolWindowLandingPanel extends ResponsePanel {
|
||||
|
||||
private static final Logger LOG = Logger.getInstance(StandardChatToolWindowLandingPanel.class);
|
||||
|
||||
private final EditorActionEvent onAction;
|
||||
|
||||
StandardChatToolWindowLandingPanel(EditorActionEvent onAction) {
|
||||
this.onAction = onAction;
|
||||
addContent(createContent());
|
||||
addContent(createContent(onAction));
|
||||
}
|
||||
|
||||
private JTextPane createContent() {
|
||||
var textPane = UIUtil.createTextPane(
|
||||
private ActionLink createEditorActionLink(EditorAction action, EditorActionEvent onAction) {
|
||||
var link = new ActionLink(action.getUserMessage(), event -> {
|
||||
onAction.handleAction(action, ((ActionLink) event.getSource()).getLocationOnScreen());
|
||||
});
|
||||
link.setIcon(Icons.Sparkle);
|
||||
return link;
|
||||
}
|
||||
|
||||
private JPanel createContent(EditorActionEvent onAction) {
|
||||
var panel = new JPanel(new BorderLayout());
|
||||
panel.add(UIUtil.createTextPane(
|
||||
"<html>"
|
||||
+ format(
|
||||
"<p style=\"margin-top: 4px; margin-bottom: 4px;\">"
|
||||
+ "Welcome <strong>%s</strong>, I'm your intelligent code companion, here to be"
|
||||
+ " your partner-in-crime for getting things done in a flash. Together, we'll "
|
||||
+ "tackle tasks swiftly and efficiently, making your coding experience a joy."
|
||||
+ "</p>",
|
||||
SettingsState.getInstance().getDisplayName())
|
||||
"<p style=\"margin-top: 4px; margin-bottom: 4px;\">"
|
||||
+ "Welcome <strong>%s</strong>, I'm your intelligent code companion, here to be"
|
||||
+ " your partner-in-crime for getting things done in a flash."
|
||||
+ "</p>", SettingsState.getInstance().getDisplayName())
|
||||
+ "<p style=\"margin-top: 4px; margin-bottom: 4px;\">"
|
||||
+ "Feel free to ask me anything you'd like, but my true superpower lies in assisting "
|
||||
+ "you with your code! Here are a few examples of how I can assist you:"
|
||||
+ "</p>"
|
||||
|
||||
+ "<ul style=\"margin-top: 4px; margin-bottom: 4px;\">"
|
||||
+ "<li>"
|
||||
+ "<a href=\"GENERATE_UNIT_TESTS\">Generate unit tests for the selected code</a>"
|
||||
+ "</li>"
|
||||
+ "<li>"
|
||||
+ "<a href=\"EXPLAIN_CODE\">Explain the selected code</a>"
|
||||
+ "</li>"
|
||||
+ "<li>"
|
||||
+ "<a href=\"FIND_BUGS\">Find bugs in the selected code</a>"
|
||||
+ "</li>"
|
||||
+ "</ul"
|
||||
|
||||
+ "</html>",
|
||||
false), BorderLayout.NORTH);
|
||||
panel.add(createEditorActionsListPanel(onAction), BorderLayout.CENTER);
|
||||
panel.add(UIUtil.createTextPane(
|
||||
"<html>"
|
||||
+ "<p style=\"margin-top: 4px; margin-bottom: 4px;\">"
|
||||
+ "Being an AI-powered assistant, I may occasionally have surprises or make mistakes. "
|
||||
+ "Therefore, it's wise to double-check any code or suggestions I provide."
|
||||
+ "</p>"
|
||||
+ "</html>",
|
||||
this::handleHyperlinkClicked);
|
||||
textPane.setBackground(getPanelBackgroundColor());
|
||||
return textPane;
|
||||
false), BorderLayout.SOUTH);
|
||||
return panel;
|
||||
}
|
||||
|
||||
private void handleHyperlinkClicked(HyperlinkEvent event) {
|
||||
if (ACTIVATED.equals(event.getEventType())) {
|
||||
if (event.getURL() == null) {
|
||||
var mouseLocation = ((MouseEvent) event.getInputEvent()).getLocationOnScreen();
|
||||
mouseLocation.y = mouseLocation.y - 10;
|
||||
switch (event.getDescription()) {
|
||||
case "GENERATE_UNIT_TESTS":
|
||||
onAction.handleAction(EditorAction.WRITE_TESTS, mouseLocation);
|
||||
break;
|
||||
case "EXPLAIN_CODE":
|
||||
onAction.handleAction(EditorAction.EXPLAIN, mouseLocation);
|
||||
break;
|
||||
case "FIND_BUGS":
|
||||
onAction.handleAction(EditorAction.FIND_BUGS, mouseLocation);
|
||||
break;
|
||||
default:
|
||||
LOG.error("Could not trigger action {}", event.getDescription());
|
||||
}
|
||||
} else {
|
||||
UIUtil.handleHyperlinkClicked(event);
|
||||
}
|
||||
}
|
||||
private JPanel createEditorActionsListPanel(EditorActionEvent onAction) {
|
||||
var listPanel = new JPanel();
|
||||
listPanel.setLayout(new BoxLayout(listPanel, BoxLayout.PAGE_AXIS));
|
||||
listPanel.setBorder(JBUI.Borders.emptyLeft(4));
|
||||
listPanel.add(Box.createVerticalStrut(4));
|
||||
listPanel.add(createEditorActionLink(EditorAction.WRITE_TESTS, onAction));
|
||||
listPanel.add(Box.createVerticalStrut(4));
|
||||
listPanel.add(createEditorActionLink(EditorAction.EXPLAIN, onAction));
|
||||
listPanel.add(Box.createVerticalStrut(4));
|
||||
listPanel.add(createEditorActionLink(EditorAction.FIND_BUGS, onAction));
|
||||
listPanel.add(Box.createVerticalStrut(4));
|
||||
return listPanel;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ import ee.carlrobert.codegpt.actions.toolwindow.CreateNewConversationAction;
|
|||
import ee.carlrobert.codegpt.actions.toolwindow.OpenInEditorAction;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationService;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationsState;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.BorderLayout;
|
||||
import javax.swing.JPanel;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class StandardChatToolWindowPanel extends SimpleToolWindowPanel {
|
||||
|
|
@ -29,11 +30,22 @@ public class StandardChatToolWindowPanel extends SimpleToolWindowPanel {
|
|||
if (conversation == null) {
|
||||
conversation = ConversationService.getInstance().startConversation();
|
||||
}
|
||||
|
||||
var tabPanel = new StandardChatToolWindowTabPanel(project, conversation);
|
||||
var tabbedPane = createTabbedPane(tabPanel, parentDisposable);
|
||||
var toolbarComponent = createActionToolbar(project, tabbedPane).getComponent();
|
||||
toolbarComponent.setLayout(new FlowLayout());
|
||||
setToolbar(toolbarComponent);
|
||||
Runnable onAddNewTab = () -> {
|
||||
tabbedPane.addNewTab(new StandardChatToolWindowTabPanel(
|
||||
project,
|
||||
ConversationService.getInstance().startConversation()));
|
||||
repaint();
|
||||
revalidate();
|
||||
};
|
||||
var actionToolbarPanel = new JPanel(new BorderLayout());
|
||||
actionToolbarPanel.add(
|
||||
createActionToolbar(project, tabbedPane, onAddNewTab).getComponent(),
|
||||
BorderLayout.LINE_START);
|
||||
|
||||
setToolbar(actionToolbarPanel);
|
||||
setContent(tabbedPane);
|
||||
|
||||
Disposer.register(parentDisposable, tabPanel);
|
||||
|
|
@ -41,15 +53,10 @@ public class StandardChatToolWindowPanel extends SimpleToolWindowPanel {
|
|||
|
||||
private ActionToolbar createActionToolbar(
|
||||
Project project,
|
||||
StandardChatToolWindowTabbedPane tabbedPane) {
|
||||
StandardChatToolWindowTabbedPane tabbedPane,
|
||||
Runnable onAddNewTab) {
|
||||
var actionGroup = new DefaultCompactActionGroup("TOOLBAR_ACTION_GROUP", false);
|
||||
actionGroup.add(new CreateNewConversationAction(() -> {
|
||||
tabbedPane.addNewTab(new StandardChatToolWindowTabPanel(
|
||||
project,
|
||||
ConversationService.getInstance().startConversation()));
|
||||
repaint();
|
||||
revalidate();
|
||||
}));
|
||||
actionGroup.add(new CreateNewConversationAction(onAddNewTab));
|
||||
actionGroup.add(
|
||||
new ClearChatWindowAction(() -> tabbedPane.resetCurrentlyActiveTabPanel(project)));
|
||||
actionGroup.addSeparator();
|
||||
|
|
@ -61,7 +68,8 @@ public class StandardChatToolWindowPanel extends SimpleToolWindowPanel {
|
|||
return toolbar;
|
||||
}
|
||||
|
||||
private StandardChatToolWindowTabbedPane createTabbedPane(StandardChatToolWindowTabPanel tabPanel,
|
||||
private StandardChatToolWindowTabbedPane createTabbedPane(
|
||||
StandardChatToolWindowTabPanel tabPanel,
|
||||
Disposable parentDisposable) {
|
||||
var tabbedPane = new StandardChatToolWindowTabbedPane(parentDisposable);
|
||||
tabbedPane.addNewTab(tabPanel);
|
||||
|
|
|
|||
|
|
@ -56,8 +56,8 @@ public class StandardChatToolWindowTabPanel extends BaseChatToolWindowTabPanel {
|
|||
private void displayConversation(@NotNull Conversation conversation) {
|
||||
clearWindow();
|
||||
conversation.getMessages().forEach(message -> {
|
||||
var messageResponseBody = new ChatMessageResponseBody(project, this)
|
||||
.withResponse(message.getResponse());
|
||||
var messageResponseBody =
|
||||
new ChatMessageResponseBody(project, this).withResponse(message.getResponse());
|
||||
|
||||
var serpResults = message.getSerpResults();
|
||||
if (YouSettingsState.getInstance().isDisplayWebSearchResults()
|
||||
|
|
|
|||
|
|
@ -134,11 +134,10 @@ public class StandardChatToolWindowTabbedPane extends JBTabbedPane {
|
|||
button.setToolTipText("Close Chat");
|
||||
button.setRolloverIcon(AllIcons.Actions.CloseHovered);
|
||||
|
||||
var panel = JBUI.Panels.simplePanel(4, 0)
|
||||
return JBUI.Panels.simplePanel(4, 0)
|
||||
.addToLeft(new JBLabel(title))
|
||||
.addToRight(button);
|
||||
panel.setOpaque(false);
|
||||
return panel;
|
||||
.addToRight(button)
|
||||
.andTransparent();
|
||||
}
|
||||
|
||||
class CloseActionListener implements ActionListener {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
package ee.carlrobert.codegpt.toolwindow.conversations;
|
||||
|
||||
import static ee.carlrobert.codegpt.util.UIUtil.getPanelBackgroundColor;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.ui.JBColor;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
|
|
@ -62,7 +60,6 @@ class ConversationPanel extends JPanel {
|
|||
var border = isSelected
|
||||
? JBUI.Borders.customLine(JBUI.CurrentTheme.ActionButton.focusedBorder(), 2, 2, 2, 2)
|
||||
: JBUI.Borders.customLine(JBColor.border(), 1, 0, 1, 0);
|
||||
setBackground(getPanelBackgroundColor());
|
||||
setBorder(JBUI.Borders.compound(border, JBUI.Borders.empty(8)));
|
||||
setLayout(new GridBagLayout());
|
||||
setCursor(new Cursor(Cursor.HAND_CURSOR));
|
||||
|
|
@ -85,7 +82,6 @@ class ConversationPanel extends JPanel {
|
|||
gbc.weightx = 1.0;
|
||||
gbc.gridx = 0;
|
||||
|
||||
headerPanel.setBackground(getPanelBackgroundColor());
|
||||
headerPanel.add(new JBLabel(getFirstPrompt(conversation))
|
||||
.withFont(JBFont.label().asBold()), gbc);
|
||||
|
||||
|
|
@ -94,7 +90,6 @@ class ConversationPanel extends JPanel {
|
|||
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) {
|
||||
|
|
@ -104,7 +99,6 @@ class ConversationPanel extends JPanel {
|
|||
}
|
||||
|
||||
var textPanel = new JPanel(new BorderLayout());
|
||||
textPanel.setBackground(getPanelBackgroundColor());
|
||||
textPanel.add(headerPanel, BorderLayout.NORTH);
|
||||
textPanel.add(bottomPanel, BorderLayout.SOUTH);
|
||||
return textPanel;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package ee.carlrobert.codegpt.util;
|
|||
|
||||
import static com.intellij.openapi.ui.Messages.CANCEL;
|
||||
import static com.intellij.openapi.ui.Messages.OK;
|
||||
import static ee.carlrobert.codegpt.Icons.DefaultIcon;
|
||||
import static ee.carlrobert.codegpt.Icons.Default;
|
||||
import static java.lang.String.format;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
|
|
@ -68,7 +68,7 @@ public class OverlayUtil {
|
|||
return Messages.showYesNoDialog(
|
||||
CodeGPTBundle.get("dialog.deleteConversation.description"),
|
||||
CodeGPTBundle.get("dialog.deleteConversation.title"),
|
||||
DefaultIcon);
|
||||
Default);
|
||||
}
|
||||
|
||||
public static int showTokenLimitExceededDialog() {
|
||||
|
|
@ -77,7 +77,7 @@ public class OverlayUtil {
|
|||
CodeGPTBundle.get("dialog.tokenLimitExceeded.description"))
|
||||
.yesText(CodeGPTBundle.get("dialog.continue"))
|
||||
.noText(CodeGPTBundle.get("dialog.cancel"))
|
||||
.icon(DefaultIcon)
|
||||
.icon(Default)
|
||||
.doNotAsk(new DoNotAskOption.Adapter() {
|
||||
@Override
|
||||
public void rememberChoice(boolean isSelected, int exitCode) {
|
||||
|
|
@ -106,7 +106,7 @@ public class OverlayUtil {
|
|||
format(CodeGPTBundle.get("dialog.tokenSoftLimitExceeded.description"), tokenCount))
|
||||
.yesText(CodeGPTBundle.get("dialog.continue"))
|
||||
.noText(CodeGPTBundle.get("dialog.cancel"))
|
||||
.icon(DefaultIcon)
|
||||
.icon(Default)
|
||||
.doNotAsk(new DoNotAskOption.Adapter() {
|
||||
@Override
|
||||
public void rememberChoice(boolean isSelected, int exitCode) {
|
||||
|
|
@ -132,9 +132,14 @@ public class OverlayUtil {
|
|||
public static void showSelectedEditorSelectionWarning(AnActionEvent event) {
|
||||
var locationOnScreen = ((MouseEvent) event.getInputEvent()).getLocationOnScreen();
|
||||
locationOnScreen.y = locationOnScreen.y - 16;
|
||||
showSelectedEditorSelectionWarning(requireNonNull(event.getProject()), locationOnScreen);
|
||||
}
|
||||
|
||||
public static void showSelectedEditorSelectionWarning(
|
||||
@NotNull Project project,
|
||||
Point locationOnScreen) {
|
||||
showWarningBalloon(
|
||||
EditorUtil.getSelectedEditor(requireNonNull(event.getProject())) == null
|
||||
EditorUtil.getSelectedEditor(project) == null
|
||||
? "Unable to locate a selected editor"
|
||||
: "Please select a target code before proceeding",
|
||||
locationOnScreen);
|
||||
|
|
|
|||
|
|
@ -31,16 +31,21 @@ import javax.swing.event.HyperlinkListener;
|
|||
public class UIUtil {
|
||||
|
||||
public static JTextPane createTextPane(String text) {
|
||||
return createTextPane(text, UIUtil::handleHyperlinkClicked);
|
||||
return createTextPane(text, true);
|
||||
}
|
||||
|
||||
public static JTextPane createTextPane(String text, HyperlinkListener listener) {
|
||||
public static JTextPane createTextPane(String text, boolean opaque) {
|
||||
return createTextPane(text, opaque, UIUtil::handleHyperlinkClicked);
|
||||
}
|
||||
|
||||
public static JTextPane createTextPane(String text, boolean opaque, HyperlinkListener listener) {
|
||||
var textPane = new JTextPane();
|
||||
textPane.putClientProperty(JTextPane.HONOR_DISPLAY_PROPERTIES, true);
|
||||
textPane.addHyperlinkListener(listener);
|
||||
textPane.setContentType("text/html");
|
||||
textPane.setEditable(false);
|
||||
textPane.setText(text);
|
||||
textPane.setOpaque(opaque);
|
||||
return textPane;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue