Skip to content

Commit

Permalink
feat: support multi-line code completions
Browse files Browse the repository at this point in the history
  • Loading branch information
carlrobertoh committed Nov 30, 2024
1 parent 6fef9c2 commit f84a659
Show file tree
Hide file tree
Showing 23 changed files with 650 additions and 347 deletions.
28 changes: 14 additions & 14 deletions codegpt-treesitter/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,33 @@ dependencies {
implementation("io.github.bonede:tree-sitter-elixir:0.2.0")
implementation("io.github.bonede:tree-sitter-dockerfile:0.2.0")
implementation("io.github.bonede:tree-sitter-dart:master-a")
implementation("io.github.bonede:tree-sitter-css:0.21.0")
implementation("io.github.bonede:tree-sitter-cpp:0.22.0a")
implementation("io.github.bonede:tree-sitter-c-sharp:0.20.0a")
implementation("io.github.bonede:tree-sitter-css:0.23.1")
implementation("io.github.bonede:tree-sitter-cpp:0.23.4")
implementation("io.github.bonede:tree-sitter-c-sharp:0.23.1")
implementation("io.github.bonede:tree-sitter-fortran:master-a")
implementation("io.github.bonede:tree-sitter-gitattributes:0.1.6")
implementation("io.github.bonede:tree-sitter-go:0.21.0a")
implementation("io.github.bonede:tree-sitter-go:0.23.3")
implementation("io.github.bonede:tree-sitter-graphql:master-a")
implementation("io.github.bonede:tree-sitter-html:0.20.3")
implementation("io.github.bonede:tree-sitter-javascript:0.21.2")
implementation("io.github.bonede:tree-sitter-json:0.21.0a")
implementation("io.github.bonede:tree-sitter-kotlin:0.3.6")
implementation("io.github.bonede:tree-sitter-html:0.23.2")
implementation("io.github.bonede:tree-sitter-javascript:0.23.1")
implementation("io.github.bonede:tree-sitter-json:0.23.0")
implementation("io.github.bonede:tree-sitter-kotlin:0.3.8.1")
implementation("io.github.bonede:tree-sitter-latex:0.3.0a")
implementation("io.github.bonede:tree-sitter-lua:2.1.3a")
implementation("io.github.bonede:tree-sitter-m68k:0.2.7a")
implementation("io.github.bonede:tree-sitter-markdown:0.7.1a")
implementation("io.github.bonede:tree-sitter-objc:main-a")
implementation("io.github.bonede:tree-sitter-perl:1.1.0")
implementation("io.github.bonede:tree-sitter-ruby:0.21.0")
implementation("io.github.bonede:tree-sitter-rust:0.21.2")
implementation("io.github.bonede:tree-sitter-scala:0.21.0a")
implementation("io.github.bonede:tree-sitter-ruby:0.23.1")
implementation("io.github.bonede:tree-sitter-rust:0.23.1")
implementation("io.github.bonede:tree-sitter-scala:0.23.3")
implementation("io.github.bonede:tree-sitter-scss:1.0.0a")
implementation("io.github.bonede:tree-sitter-svelte:0.11.0a")
implementation("io.github.bonede:tree-sitter-swift:0.5.0")
implementation("io.github.bonede:tree-sitter-yaml:0.5.0a")
implementation("io.github.bonede:tree-sitter-java:0.21.0a")
implementation("io.github.bonede:tree-sitter-python:0.21.0a")
implementation("io.github.bonede:tree-sitter-php:0.22.4")
implementation("io.github.bonede:tree-sitter-java:0.23.4")
implementation("io.github.bonede:tree-sitter-python:0.23.4")
implementation("io.github.bonede:tree-sitter-php:0.23.11")
implementation("io.github.bonede:tree-sitter-typescript:0.21.1")
implementation("io.github.bonede:tree-sitter-query:0.3.0")
}
Original file line number Diff line number Diff line change
@@ -1,44 +1,116 @@
package ee.carlrobert.codegpt.treesitter;

import java.nio.charset.StandardCharsets;
import org.treesitter.TSInputEdit;
import org.treesitter.TSLanguage;
import org.treesitter.TSParser;
import org.treesitter.TSPoint;
import org.treesitter.TSTree;

public class CodeCompletionParser {

protected final TSLanguage language;
private final TSParser parser;

public CodeCompletionParser(TSLanguage language) {
this.language = language;
parser = new TSParser();
parser.setLanguage(language);
}

public String parse(String prefix, String suffix, String output) {
var result = new StringBuilder(output);
String input = prefix + result + suffix;
TSTree currentTree = parser.parseString(null, input);

while (!result.isEmpty()) {
if (containsError(prefix + result + suffix)) {
if (containsError(currentTree)) {
int deletionIndex = prefix.length() + result.length() - 1;
Position pos = getPosition(input, deletionIndex);

int startByte = pos.byteOffset;
int oldEndByte = startByte + getByteLength(result.substring(result.length() - 1));

TSPoint startPoint = pos.point;
TSPoint oldEndPoint = computeOldEndPoint(startPoint, result.charAt(result.length() - 1));

currentTree.edit(
new TSInputEdit(startByte, oldEndByte, startByte, startPoint, oldEndPoint, startPoint));

result.deleteCharAt(result.length() - 1);

if (result.length() > 1 && result.charAt(result.length() - 1) == '{') {
long bracketCount = result.chars().filter(ch -> ch == '{').count();
if (bracketCount == 1) {
var newTree = parser.parseString(currentTree, prefix + result + "}" + suffix);
var treeString = newTree.getRootNode().toString();
if (!treeString.contains("ERROR")) {
return result + "}";
}
}
}

input = prefix + result + suffix;

currentTree = parser.parseString(currentTree, input);
} else {
return result.toString();
}
}

if (output.contains("\n")) {
return parse(prefix, suffix, output.substring(0, output.indexOf("\n")));
var finalResult = output.substring(0, output.indexOf("\n"));
if (finalResult.charAt(finalResult.length() - 1) == '{') {
return finalResult + "}";
}
return finalResult;
}

return output;
}

private boolean containsError(String input) {
var treeString = getTree(input).getRootNode().toString();
private boolean containsError(TSTree tree) {
var treeString = tree.getRootNode().toString();
return treeString.contains("ERROR")
|| treeString.contains("MISSING \"}\"")
|| treeString.contains("MISSING \")\"");
}

private TSTree getTree(String input) {
var parser = new TSParser();
parser.setLanguage(language);
return parser.parseString(null, input);
private Position getPosition(String input, int index) {
int row = 0;
int col = 0;
int byteOffset = 0;
for (int i = 0; i < index; i++) {
char c = input.charAt(i);
int charByteLength = getByteLength(String.valueOf(c));
byteOffset += charByteLength;

if (c == '\n') {
row++;
col = 0;
} else {
col++;
}
}
return new Position(new TSPoint(row, col), byteOffset);
}

private int getByteLength(String str) {
return str.getBytes(StandardCharsets.UTF_8).length;
}

private TSPoint computeOldEndPoint(TSPoint startPoint, char deletedChar) {
int row = startPoint.getRow();
int col = startPoint.getColumn();

if (deletedChar == '\n') {
row++;
col = 0;
} else {
col++;
}
return new TSPoint(row, col);
}

private record Position(TSPoint point, int byteOffset) {

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,7 @@ class Main {
return 10;
}
}""";
var output = """
prevNumber) {
if() {""";
var output = "prevNumber);";

var parsedResponse = CodeCompletionParserFactory
.getParserForFileExtension("java")
Expand Down
4 changes: 2 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ jsoup = "1.17.2"
jtokkit = "1.1.0"
junit = "5.11.0"
kotlin = "2.0.0"
llm-client = "0.8.28"
llm-client = "0.8.29"
okio = "3.9.0"
tree-sitter = "0.22.6a"
tree-sitter = "0.24.4"

[libraries]
analytics = { module = "com.rudderstack.sdk.java.analytics:analytics", version.ref = "analytics" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,9 @@ public class ConfigurationComponent {
private final JBCheckBox checkForNewScreenshotsCheckBox;
private final JBCheckBox methodNameGenerationCheckBox;
private final JBCheckBox autoFormattingCheckBox;
private final JBCheckBox autocompletionPostProcessingCheckBox;
private final JBCheckBox autocompletionContextAwareCheckBox;
private final JBCheckBox autocompletionGitContextCheckBox;
private final IntegerField maxTokensField;
private final JBTextField temperatureField;
private final CodeCompletionConfigurationForm codeCompletionForm;

public ConfigurationComponent(
Disposable parentDisposable,
Expand Down Expand Up @@ -72,31 +70,21 @@ public void changedUpdate(DocumentEvent e) {
autoFormattingCheckBox = new JBCheckBox(
CodeGPTBundle.get("configurationConfigurable.autoFormatting.label"),
configuration.getAutoFormattingEnabled());
autocompletionPostProcessingCheckBox = new JBCheckBox(
CodeGPTBundle.get("configurationConfigurable.autocompletionPostProcessing.label"),
configuration.getAutocompletionPostProcessingEnabled()
);
autocompletionContextAwareCheckBox = new JBCheckBox(
CodeGPTBundle.get("configurationConfigurable.autocompletionContextAwareCheckBox.label"),
configuration.getAutocompletionContextAwareEnabled()
);
autocompletionGitContextCheckBox = new JBCheckBox(
CodeGPTBundle.get("configurationConfigurable.autocompletionGitContextCheckBox.label"),
configuration.getAutocompletionGitContextEnabled()
);

codeCompletionForm = new CodeCompletionConfigurationForm();

mainPanel = FormBuilder.createFormBuilder()
.addComponent(checkForPluginUpdatesCheckBox)
.addComponent(checkForNewScreenshotsCheckBox)
.addComponent(methodNameGenerationCheckBox)
.addComponent(autoFormattingCheckBox)
.addComponent(autocompletionPostProcessingCheckBox)
.addComponent(autocompletionContextAwareCheckBox)
.addComponent(autocompletionGitContextCheckBox)
.addVerticalGap(4)
.addComponent(new TitledSeparator(
CodeGPTBundle.get("configurationConfigurable.section.assistant.title")))
.addComponent(createAssistantConfigurationForm())
.addComponent(new TitledSeparator(
CodeGPTBundle.get("configurationConfigurable.section.codeCompletion.title")))
.addComponent(codeCompletionForm.createPanel())
.addComponentFillVertically(new JPanel(), 0)
.getPanel();
}
Expand All @@ -113,9 +101,7 @@ public ConfigurationSettingsState getCurrentFormState() {
state.setCheckForNewScreenshots(checkForNewScreenshotsCheckBox.isSelected());
state.setMethodNameGenerationEnabled(methodNameGenerationCheckBox.isSelected());
state.setAutoFormattingEnabled(autoFormattingCheckBox.isSelected());
state.setAutocompletionPostProcessingEnabled(autocompletionPostProcessingCheckBox.isSelected());
state.setAutocompletionContextAwareEnabled(autocompletionContextAwareCheckBox.isSelected());
state.setAutocompletionGitContextEnabled(autocompletionGitContextCheckBox.isSelected());
state.setCodeCompletionSettings(codeCompletionForm.getFormState());
return state;
}

Expand All @@ -127,13 +113,7 @@ public void resetForm() {
checkForNewScreenshotsCheckBox.setSelected(configuration.getCheckForNewScreenshots());
methodNameGenerationCheckBox.setSelected(configuration.getMethodNameGenerationEnabled());
autoFormattingCheckBox.setSelected(configuration.getAutoFormattingEnabled());
autocompletionPostProcessingCheckBox.setSelected(
configuration.getAutocompletionPostProcessingEnabled());
autocompletionContextAwareCheckBox.setSelected(
configuration.getAutocompletionContextAwareEnabled());
autocompletionGitContextCheckBox.setSelected(
configuration.getAutocompletionGitContextEnabled()
);
codeCompletionForm.resetForm(configuration.getCodeCompletionSettings());
}

// Formatted keys are not referenced in the messages bundle file
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package ee.carlrobert.codegpt.settings.service.llama.form;

import ee.carlrobert.codegpt.codecompletions.CompletionType;
import ee.carlrobert.codegpt.codecompletions.InfillPromptTemplate;
import ee.carlrobert.codegpt.codecompletions.InfillRequest;

Expand All @@ -17,6 +18,8 @@ public InfillPromptTemplatePanel(

@Override
protected String buildPromptDescription(InfillPromptTemplate template) {
return template.buildPrompt(new InfillRequest.Builder("PREFIX", "SUFFIX", 0).build());
return template.buildPrompt(new InfillRequest
.Builder("PREFIX", "SUFFIX", 0, CompletionType.MULTI_LINE)
.build());
}
}
Loading

0 comments on commit f84a659

Please sign in to comment.