mirror of
https://github.com/carlrobertoh/ProxyAI.git
synced 2026-05-13 23:53:02 +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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
<applicationService serviceImplementation="ee.carlrobert.codegpt.settings.configuration.ConfigurationState"/>
|
||||
<applicationService serviceImplementation="ee.carlrobert.codegpt.settings.advanced.AdvancedSettingsState"/>
|
||||
<applicationService serviceImplementation="ee.carlrobert.codegpt.conversations.ConversationsState"/>
|
||||
<toolWindow id="CodeGPT" icon="ee.carlrobert.codegpt.Icons.DefaultSmallIcon" anchor="right"
|
||||
<toolWindow id="CodeGPT" icon="ee.carlrobert.codegpt.Icons.DefaultSmall" anchor="right"
|
||||
factoryClass="ee.carlrobert.codegpt.toolwindow.ProjectToolWindowFactory"/>
|
||||
<notificationGroup id="CodeGPT Notification Group" displayType="BALLOON" key="notification.group.name"/>
|
||||
</extensions>
|
||||
|
|
@ -45,7 +45,7 @@
|
|||
text="CodeGPT"
|
||||
class="com.intellij.openapi.actionSystem.DefaultActionGroup"
|
||||
popup="true"
|
||||
icon="ee.carlrobert.codegpt.Icons.DefaultSmallIcon">
|
||||
icon="ee.carlrobert.codegpt.Icons.DefaultSmall">
|
||||
</group>
|
||||
<add-to-group group-id="EditorPopupMenu1" anchor="first"/>
|
||||
<separator/>
|
||||
|
|
|
|||
7
src/main/resources/icons/user.svg
Normal file
7
src/main/resources/icons/user.svg
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="24px" height="24px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12Z" fill="#ffffff" fill-opacity="1" stroke="white" stroke-width="1"/>
|
||||
<circle cx="12" cy="10" r="4" fill="#000000" stroke="none"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M18.2209 18.2462C18.2791 18.3426 18.2613 18.466 18.1795 18.5432C16.5674 20.0662 14.3928 21 12 21C9.60728 21 7.43264 20.0663 5.82057 18.5433C5.73877 18.466 5.72101 18.3427 5.77918 18.2463C6.94337 16.318 9.29215 15 12.0001 15C14.7079 15 17.0567 16.3179 18.2209 18.2462Z" fill="#000000" stroke="none"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 838 B |
7
src/main/resources/icons/user_dark.svg
Normal file
7
src/main/resources/icons/user_dark.svg
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="24px" height="24px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12Z" fill="#000000" fill-opacity="1" stroke="white" stroke-width="1"/>
|
||||
<circle cx="12" cy="10" r="4" fill="#FFFFFF" stroke="none"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M18.2209 18.2462C18.2791 18.3426 18.2613 18.466 18.1795 18.5432C16.5674 20.0662 14.3928 21 12 21C9.60728 21 7.43264 20.0663 5.82057 18.5433C5.73877 18.466 5.72101 18.3427 5.77918 18.2463C6.94337 16.318 9.29215 15 12.0001 15C14.7079 15 17.0567 16.3179 18.2209 18.2462Z" fill="#FFFFFF" stroke="none"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 832 B |
BIN
src/main/resources/icons/you_small.png
Normal file
BIN
src/main/resources/icons/you_small.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
|
|
@ -39,7 +39,7 @@ settingsConfigurable.service.llama.customModelPath.comment=Only .gguf files are
|
|||
settingsConfigurable.service.llama.downloadModelLink.label=Download Model
|
||||
settingsConfigurable.service.llama.cancelDownloadLink.label=Cancel Downloading
|
||||
settingsConfigurable.service.llama.linkToModel.label=Link to model
|
||||
settingsConfigurable.service.llama.contextSize.label=Context size:
|
||||
settingsConfigurable.service.llama.contextSize.label=Prompt context size:
|
||||
settingsConfigurable.service.llama.contextSize.comment=The size of the prompt context. LLaMA models were built with a context of 2048, which will provide better results for longer input/inference
|
||||
settingsConfigurable.service.llama.threads.label=Threads:
|
||||
settingsConfigurable.service.llama.threads.comment=The number of threads available to execute the model. It is not recommended to specify a number greater than the number of processor cores.
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import ee.carlrobert.codegpt.CodeGPTPlugin;
|
|||
import ee.carlrobert.codegpt.conversations.Conversation;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationService;
|
||||
import ee.carlrobert.codegpt.conversations.message.Message;
|
||||
import ee.carlrobert.codegpt.settings.configuration.ConfigurationState;
|
||||
import ee.carlrobert.llm.client.http.exchange.StreamHttpExchange;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
|
@ -142,6 +143,7 @@ public class DefaultCompletionRequestHandlerTest extends IntegrationTest {
|
|||
|
||||
public void testLlamaChatCompletionCall() {
|
||||
useLlamaService();
|
||||
ConfigurationState.getInstance().setMaxTokens(99);
|
||||
var message = new Message("TEST_PROMPT");
|
||||
var conversation = ConversationService.getInstance().startConversation();
|
||||
conversation.addMessage(new Message("Ping", "Pong"));
|
||||
|
|
@ -158,7 +160,7 @@ public class DefaultCompletionRequestHandlerTest extends IntegrationTest {
|
|||
COMPLETION_SYSTEM_PROMPT,
|
||||
"TEST_PROMPT",
|
||||
conversation.getMessages()),
|
||||
512,
|
||||
99,
|
||||
true);
|
||||
return List.of(
|
||||
jsonMapResponse("content", "Hel"),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue