Inline Autocompletion Pt.2 (#333)

* Add first draft of inline code completion with mock text

* Adds InsertInlineTextAction for inserting autocomplete suggestion with tab

- Changed to disable suggestions when text is selected
- Adds and removes the insert action based on when it shows the inlay hint

* Request inline code completion

* Move inline completion prompt into txt file

* Add inline completion settings to ConfigurationState

* Fix code style

* Use EditorTrackerListener instead of EditorFactoryListener to enable inline completion

* Code completion requests synchronously without SSE

* Use LlamaClient.getInfill() for inline code completion

* support inlay block element rendering, clean up code

* Use only enclosed Method or Class contents for code completion if possible

* Refactor extracting PsiElement contents in code completion

* bump llm-client

* fix completion call from triggering on EDT, force method params to be nonnull by default

* refactor request building, decrease delay value

* Trigger code completion if cursor is not inside a word

* Improve inlay rendering

* Support cancellable infill requests

* add statusbar widget, disable completions by default

* Show error notification if code completion failed

* Truely disable/enable EditorInlayHandler when completion is turned off/on

* Add CodeCompletionEnabledListener Topic to control enabling/disabling code-completion

* Add progress indicator for code-completion with option to cancel

* Add CodeCompletionServiceTest + refactor inlay ElementRenderers

* several improvements

- replace timer implementation with call debouncing
- use OpenAI /v1/completions API for completions
- code refactoring

* trigger progress indicator only for llama completions

* fix tests

---------

Co-authored-by: James Higgins <james.isaac.higgins@gmail.com>
Co-authored-by: Carl-Robert Linnupuu <carlrobertoh@gmail.com>
This commit is contained in:
Phil 2024-01-31 00:05:31 +01:00 committed by GitHub
parent 390d8cdd5e
commit 7387cf4536
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
41 changed files with 1461 additions and 21 deletions

View file

@ -48,8 +48,10 @@ public class ConfigurationComponent {
private final JBCheckBox autoFormattingCheckBox;
private final JTextArea systemPromptTextArea;
private final JTextArea commitMessagePromptTextArea;
private final JTextArea inlineCompletionPromptTextArea;
private final IntegerField maxTokensField;
private final JBTextField temperatureField;
private final JBTextField inlineDelayField;
public ConfigurationComponent(Disposable parentDisposable, ConfigurationState configuration) {
table = new JBTable(new DefaultTableModel(
@ -68,7 +70,8 @@ public class ConfigurationComponent {
temperatureField = new JBTextField(12);
temperatureField.setText(String.valueOf(configuration.getTemperature()));
var temperatureFieldValidator = createInputValidator(parentDisposable, temperatureField);
var temperatureFieldValidator = createTemperatureInputValidator(parentDisposable,
temperatureField);
temperatureField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
@ -106,6 +109,33 @@ public class ConfigurationComponent {
commitMessagePromptTextArea.setLineWrap(true);
commitMessagePromptTextArea.setBorder(JBUI.Borders.empty(8, 4));
inlineCompletionPromptTextArea = new JTextArea(configuration.getInlineCompletionPrompt(), 3,
60);
inlineCompletionPromptTextArea.setLineWrap(true);
inlineCompletionPromptTextArea.setBorder(JBUI.Borders.empty(8, 4));
inlineDelayField = new JBTextField(12);
inlineDelayField.setText(String.valueOf(configuration.getTemperature()));
var inlineDelayFieldValidator = createInlineDelayInputValidator(parentDisposable,
inlineDelayField);
inlineDelayField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
inlineDelayFieldValidator.revalidate();
}
@Override
public void removeUpdate(DocumentEvent e) {
inlineDelayFieldValidator.revalidate();
}
@Override
public void changedUpdate(DocumentEvent e) {
inlineDelayFieldValidator.revalidate();
}
});
checkForPluginUpdatesCheckBox = new JBCheckBox(
CodeGPTBundle.get("configurationConfigurable.checkForPluginUpdates.label"),
configuration.isCheckForPluginUpdates());
@ -135,6 +165,10 @@ public class ConfigurationComponent {
CodeGPTBundle.get("configurationConfigurable.section.commitMessage.title")))
.addComponent(createCommitMessageConfigurationForm())
.addComponentFillVertically(new JPanel(), 0)
.addComponent(new TitledSeparator(
CodeGPTBundle.get("configurationConfigurable.section.inlineCompletion.title")))
.addComponent(createInlineCompletionConfigurationForm())
.addComponentFillVertically(new JPanel(), 0)
.getPanel();
}
@ -227,7 +261,28 @@ public class ConfigurationComponent {
return form;
}
private ComponentValidator createInputValidator(
private JPanel createInlineCompletionConfigurationForm() {
var formBuilder = FormBuilder.createFormBuilder();
addAssistantFormLabeledComponent(
formBuilder,
"configurationConfigurable.section.inlineCompletion.systemPromptField.label",
"configurationConfigurable.section.inlineCompletion.systemPromptField.comment",
JBUI.Panels
.simplePanel(inlineCompletionPromptTextArea)
.withBorder(JBUI.Borders.customLine(
JBUI.CurrentTheme.CustomFrameDecorations.separatorForeground())));
formBuilder.addVerticalGap(8);
addAssistantFormLabeledComponent(
formBuilder,
"configurationConfigurable.section.inlineCompletion.delay.label",
"configurationConfigurable.section.inlineCompletion.delay.comment",
inlineDelayField);
var form = formBuilder.getPanel();
form.setBorder(JBUI.Borders.emptyLeft(16));
return form;
}
private ComponentValidator createTemperatureInputValidator(
Disposable parentDisposable,
JBTextField component) {
var validator = new ComponentValidator(parentDisposable)
@ -254,6 +309,33 @@ public class ConfigurationComponent {
return validator;
}
private ComponentValidator createInlineDelayInputValidator(
Disposable parentDisposable,
JBTextField component) {
var validator = new ComponentValidator(parentDisposable)
.withValidator(() -> {
var valueText = component.getText();
try {
var value = Integer.parseInt(valueText);
if (value <= 0) {
return new ValidationInfo(
CodeGPTBundle.get("validation.error.mustBeGreaterThanZero"),
component);
}
} catch (NumberFormatException e) {
return new ValidationInfo(
CodeGPTBundle.get("validation.error.mustBeNumber"),
component);
}
return null;
})
.andStartOnFocusLost()
.installOn(component);
validator.enableValidation();
return validator;
}
private DefaultTableModel getModel() {
return (DefaultTableModel) table.getModel();
}
@ -280,6 +362,23 @@ public class ConfigurationComponent {
return commitMessagePromptTextArea.getText();
}
public void setInlineCompletionPrompt(String inlineCompletionPrompt) {
inlineCompletionPromptTextArea.setText(inlineCompletionPrompt);
}
public String getInlineCompletionPrompt() {
return inlineCompletionPromptTextArea.getText();
}
public int getInlineDelay() {
return Integer.parseInt(inlineDelayField.getText());
}
public void setInlineDelay(int inlineDelay) {
inlineDelayField.setText(String.valueOf(inlineDelay));
}
public double getTemperature() {
return Double.parseDouble(temperatureField.getText());
}