mirror of
https://github.com/carlrobertoh/ProxyAI.git
synced 2026-05-10 03:59:43 +00:00
refactor: rewrite method lookup listener and improve error handling
This commit is contained in:
parent
808fdfaf7e
commit
755791aea8
3 changed files with 104 additions and 103 deletions
|
|
@ -1,102 +0,0 @@
|
|||
package ee.carlrobert.codegpt.completions;
|
||||
|
||||
import static ee.carlrobert.codegpt.CodeGPTKeys.IS_PROMPT_TEXT_FIELD_DOCUMENT;
|
||||
|
||||
import com.intellij.codeInsight.completion.PrefixMatcher;
|
||||
import com.intellij.codeInsight.lookup.Lookup;
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder;
|
||||
import com.intellij.codeInsight.lookup.LookupManagerListener;
|
||||
import com.intellij.codeInsight.lookup.impl.LookupImpl;
|
||||
import com.intellij.openapi.application.Application;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import ee.carlrobert.codegpt.Icons;
|
||||
import ee.carlrobert.codegpt.settings.configuration.ConfigurationSettings;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class MethodNameLookupListener implements LookupManagerListener {
|
||||
|
||||
private static final Logger LOG = Logger.getInstance(MethodNameLookupListener.class);
|
||||
|
||||
@Override
|
||||
public void activeLookupChanged(@Nullable Lookup oldLookup, @Nullable Lookup newLookup) {
|
||||
if (!(newLookup instanceof LookupImpl lookup)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Boolean isPromptTextFieldDocument = IS_PROMPT_TEXT_FIELD_DOCUMENT.get(
|
||||
lookup.getEditor().getDocument());
|
||||
if ((isPromptTextFieldDocument != null && isPromptTextFieldDocument)
|
||||
|| !ConfigurationSettings.getState().getMethodNameGenerationEnabled()
|
||||
|| !CompletionRequestService.isRequestAllowed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var application = ApplicationManager.getApplication();
|
||||
Optional.ofNullable(lookup.getPsiElement())
|
||||
.map(PsiElement::getContext)
|
||||
.ifPresent(context ->
|
||||
application.runReadAction(() -> {
|
||||
var type = PsiUtilCore.getElementType(context);
|
||||
if (PSIMethodMapping.contains(type)) {
|
||||
var selection = context.getText();
|
||||
application.executeOnPooledThread(() ->
|
||||
addCompletionLookupValues(lookup, application, selection));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private void addCompletionLookupValues(
|
||||
LookupImpl lookup,
|
||||
Application application,
|
||||
String prompt) {
|
||||
try {
|
||||
var response = CompletionRequestService.getInstance()
|
||||
.getLookupCompletion(new LookupCompletionParameters(prompt));
|
||||
if (!response.isEmpty()) {
|
||||
for (var value : response.split(",")) {
|
||||
application.invokeLater(() -> application.runReadAction(() -> {
|
||||
lookup.addItem(
|
||||
LookupElementBuilder.create(value.trim()).withIcon(Icons.Sparkle),
|
||||
PrefixMatcher.ALWAYS_TRUE);
|
||||
lookup.refreshUi(true, true);
|
||||
}));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to add completion lookup values", e);
|
||||
}
|
||||
}
|
||||
|
||||
private enum PSIMethodMapping {
|
||||
GO(List.of("FILE", "METHOD_DECLARATION|FUNCTION_DECLARATION")),
|
||||
JAVA(List.of("java.FILE", "METHOD")),
|
||||
PY(List.of("FILE", "Py:FUNCTION_DECLARATION")),
|
||||
JAVASCRIPT(List.of("JS:FUNCTION_DECLARATION", "JS:TYPESCRIPT_FUNCTION")),
|
||||
CS(List.of("FILE", "DUMMY_TYPE_DECLARATION", "DUMMY_BLOCK")),
|
||||
PHP(List.of("FILE", "Class method|function|Function")),
|
||||
KOTLIN(List.of("FUN")),
|
||||
DEFAULT(List.of("FILE", "METHOD_DECLARATION"));
|
||||
|
||||
private final List<String> types;
|
||||
|
||||
PSIMethodMapping(List<String> codes) {
|
||||
this.types = codes;
|
||||
}
|
||||
|
||||
public static boolean contains(IElementType type) {
|
||||
LOG.info("Trying to find method mapping for type: " + type.toString());
|
||||
for (var value : PSIMethodMapping.values()) {
|
||||
if (value.types.contains(type.toString())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
package ee.carlrobert.codegpt.completions
|
||||
|
||||
import com.intellij.codeInsight.completion.PrefixMatcher
|
||||
import com.intellij.codeInsight.lookup.Lookup
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder
|
||||
import com.intellij.codeInsight.lookup.LookupManagerListener
|
||||
import com.intellij.codeInsight.lookup.impl.LookupImpl
|
||||
import com.intellij.notification.NotificationType
|
||||
import com.intellij.openapi.application.runInEdt
|
||||
import com.intellij.openapi.application.runReadAction
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.diagnostic.thisLogger
|
||||
import com.intellij.psi.tree.IElementType
|
||||
import com.intellij.psi.util.PsiUtilCore
|
||||
import ee.carlrobert.codegpt.CodeGPTKeys.IS_PROMPT_TEXT_FIELD_DOCUMENT
|
||||
import ee.carlrobert.codegpt.Icons
|
||||
import ee.carlrobert.codegpt.settings.configuration.ConfigurationSettings
|
||||
import ee.carlrobert.codegpt.ui.OverlayUtil
|
||||
import ee.carlrobert.llm.client.codegpt.response.CodeGPTException
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class MethodNameCompletionLookupListener : LookupManagerListener {
|
||||
|
||||
companion object {
|
||||
private val logger = thisLogger()
|
||||
}
|
||||
|
||||
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
|
||||
|
||||
override fun activeLookupChanged(oldLookup: Lookup?, newLookup: Lookup?) {
|
||||
if (newLookup !is LookupImpl) {
|
||||
return
|
||||
}
|
||||
|
||||
val isPromptTextFieldDocument =
|
||||
IS_PROMPT_TEXT_FIELD_DOCUMENT[newLookup.editor.document] ?: false
|
||||
val featureEnabled = service<ConfigurationSettings>().state.methodNameGenerationEnabled
|
||||
if (isPromptTextFieldDocument || !featureEnabled || !CompletionRequestService.isRequestAllowed()) {
|
||||
return
|
||||
}
|
||||
|
||||
newLookup.psiElement?.context?.let { context ->
|
||||
val elementType = PsiUtilCore.getElementType(context)
|
||||
if (PSIMethodMapping.contains(elementType)) {
|
||||
val selection = runReadAction { context.text }
|
||||
scope.launch {
|
||||
try {
|
||||
val lookupCompletion = service<CompletionRequestService>()
|
||||
.getLookupCompletion(LookupCompletionParameters(selection))
|
||||
if (lookupCompletion.isNotEmpty()) {
|
||||
addCompletionLookupValues(newLookup, lookupCompletion)
|
||||
}
|
||||
} catch (ex: CodeGPTException) {
|
||||
OverlayUtil.showNotification(ex.detail, NotificationType.ERROR)
|
||||
} catch (ex: Exception) {
|
||||
logger.error(
|
||||
"Something went wrong while requesting completion lookup values.",
|
||||
ex
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun addCompletionLookupValues(lookup: LookupImpl, response: String) {
|
||||
val values = response.split(",".toRegex())
|
||||
.dropLastWhile { it.isEmpty() }
|
||||
.toTypedArray()
|
||||
for (value in values) {
|
||||
runInEdt {
|
||||
lookup.addItem(
|
||||
LookupElementBuilder
|
||||
.create(value.trim { it <= ' ' })
|
||||
.withIcon(Icons.DefaultSmall),
|
||||
PrefixMatcher.ALWAYS_TRUE
|
||||
)
|
||||
lookup.refreshUi(true, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private enum class PSIMethodMapping(val types: List<String>) {
|
||||
GO(listOf("FILE", "METHOD_DECLARATION|FUNCTION_DECLARATION")),
|
||||
JAVA(listOf("java.FILE", "METHOD")),
|
||||
PY(listOf("FILE", "Py:FUNCTION_DECLARATION")),
|
||||
JAVASCRIPT(listOf("JS:FUNCTION_DECLARATION", "JS:TYPESCRIPT_FUNCTION")),
|
||||
CS(listOf("FILE", "DUMMY_TYPE_DECLARATION", "DUMMY_BLOCK")),
|
||||
PHP(listOf("FILE", "Class method|function|Function")),
|
||||
KOTLIN(listOf("FUN")),
|
||||
DEFAULT(listOf("FILE", "METHOD_DECLARATION"));
|
||||
|
||||
|
||||
companion object {
|
||||
fun contains(type: IElementType): Boolean {
|
||||
return entries.any { it.types.contains(type.toString()) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
<projectListeners>
|
||||
<listener topic="com.intellij.codeInsight.lookup.LookupManagerListener"
|
||||
class="ee.carlrobert.codegpt.completions.MethodNameLookupListener"/>
|
||||
class="ee.carlrobert.codegpt.completions.MethodNameCompletionLookupListener"/>
|
||||
<listener topic="com.intellij.openapi.wm.ex.ToolWindowManagerListener"
|
||||
class="ee.carlrobert.codegpt.toolwindow.chat.ChatToolWindowListener"/>
|
||||
</projectListeners>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue