Skip to content

Commit

Permalink
Feat #87: Autocomplete commands
Browse files Browse the repository at this point in the history
  • Loading branch information
stephanj committed Jun 25, 2024
1 parent be0cc54 commit 782759a
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 25 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package com.devoxx.genie.ui.component;

import com.devoxx.genie.service.PromptExecutionService;
import com.intellij.openapi.diagnostic.Logger;

import javax.swing.*;
import javax.swing.text.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;

public class CommandAutoCompleteTextField extends PlaceholderTextArea {

private static final Logger LOG = Logger.getInstance(CommandAutoCompleteTextField.class);

private final List<String> commands = new ArrayList<>();
private boolean isAutoCompleting = false;

public CommandAutoCompleteTextField() {
super();
initializeCommands();
setDocument(new CommandDocument());
addKeyListener(new CommandKeyListener());
}

private void initializeCommands() {
commands.add("/test");
commands.add("/explain");
commands.add("/review");
commands.add("/custom");
// Add more commands as needed
}

private class CommandKeyListener extends KeyAdapter {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SPACE && e.isControlDown()) {
autoComplete();
e.consume();
}
}
}

private void autoComplete() {
String text = getText();
if (text.startsWith("/")) {
String prefix = text.substring(1);
for (String command : commands) {
if (command.startsWith(prefix)) {
isAutoCompleting = true;
setText(command);
setCaretPosition(command.length());
isAutoCompleting = false;
break;
}
}
}
}

private class CommandDocument extends PlainDocument {
@Override
public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
if (isAutoCompleting) {
super.insertString(offs, str, a);
return;
}

if (offs == 0 && !str.startsWith("/")) {
str = "/" + str;
}
super.insertString(offs, str, a);

SwingUtilities.invokeLater(() -> {
try {
String text = getText(0, getLength());
if (text.startsWith("/") && text.length() > 1) {
for (String command : commands) {
if (command.startsWith(text) && !command.equals(text)) {
int currentLength = text.length();
String completion = command.substring(currentLength);
isAutoCompleting = true;
insertString(currentLength, completion, null);
setCaretPosition(getLength());
moveCaretPosition(currentLength);
isAutoCompleting = false;
break;
}
}
}
} catch (BadLocationException e) {
LOG.debug("Error while auto-completing command", e);
}
});
}
}

// Placeholder functionality
private String placeholder = "";

public void setPlaceholder(String placeholder) {
this.placeholder = placeholder;
repaint();
}

@Override
protected void paintComponent(java.awt.Graphics g) {
super.paintComponent(g);
if (getText().isEmpty() && !placeholder.isEmpty()) {
g.setColor(java.awt.Color.GRAY);
g.drawString(placeholder, getInsets().left, g.getFontMetrics().getMaxAscent() + getInsets().top);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.devoxx.genie.ui.component;

import com.intellij.ui.components.JBTextArea;
import lombok.Getter;
import lombok.Setter;

Expand All @@ -10,7 +11,7 @@

@Setter
@Getter
public class PlaceholderTextArea extends JTextArea {
public class PlaceholderTextArea extends JBTextArea {

private String placeholder;

Expand All @@ -23,7 +24,7 @@ public PlaceholderTextArea() {
protected void paintComponent(final Graphics g) {
super.paintComponent(g);

if (placeholder.isEmpty() || !getText().isEmpty()) {
if (placeholder == null || placeholder.isEmpty() || !getText().isEmpty()) {
return;
}

Expand Down
65 changes: 42 additions & 23 deletions src/main/java/com/devoxx/genie/ui/component/PromptInputArea.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,52 @@
import java.awt.*;
import java.util.ResourceBundle;

public class PromptInputArea extends PlaceholderTextArea {
public class PromptInputArea extends JPanel {

private final CommandAutoCompleteTextField inputField;

/**
* The prompt input component
*
* @param resourceBundle the resource bundle
*/
public PromptInputArea(ResourceBundle resourceBundle) {
super();

setLayout(new BorderLayout());
setMaximumSize(new Dimension(0, getPreferredSize().height));

setLineWrap(true);
setWrapStyleWord(true);
setRows(3);
setAutoscrolls(false);
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
setMinimumSize(new Dimension(0, 75));
addFocusListener(new PromptInputFocusListener(this));
setPlaceholder(resourceBundle.getString("prompt.placeholder"));
super(new BorderLayout());

inputField = new CommandAutoCompleteTextField();
inputField.setRows(3);
inputField.setLineWrap(true);
inputField.setWrapStyleWord(true);
inputField.setAutoscrolls(false);
inputField.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
inputField.setMinimumSize(new Dimension(0, 75));
inputField.addFocusListener(new PromptInputFocusListener(inputField));
inputField.setPlaceholder(resourceBundle.getString("prompt.placeholder"));

JScrollPane scrollPane = new JScrollPane(inputField);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
scrollPane.setBorder(null);

add(scrollPane, BorderLayout.CENTER);
setMaximumSize(new Dimension(Integer.MAX_VALUE, getPreferredSize().height));
}

public String getText() {
return inputField.getText();
}

public void setText(String text) {
inputField.setText(text);
}

/**
* Clear the text
*/
public void clear() {
setText("");
inputField.setText("");
}

public void setEnabled(boolean enabled) {
inputField.setEnabled(enabled);
}

public boolean requestFocusInWindow() {
return inputField.requestFocusInWindow();
}

public void setPlaceholder(String placeholder) {
inputField.setPlaceholder(placeholder);
}
}

0 comments on commit 782759a

Please sign in to comment.