11package dev.koding.copilot.completion
22
3- import com.intellij.codeInsight.completion.*
3+ import com.intellij.codeInsight.completion.CompletionContributor
4+ import com.intellij.codeInsight.completion.CompletionParameters
5+ import com.intellij.codeInsight.completion.CompletionResultSet
6+ import com.intellij.codeInsight.completion.CompletionSorter
47import com.intellij.codeInsight.lookup.LookupElementBuilder
5- import com.intellij.notification.Notification
68import com.intellij.notification.NotificationType
79import com.intellij.openapi.progress.ProcessCanceledException
810import com.intellij.openapi.progress.ProgressManager
911import com.intellij.openapi.util.TextRange
12+ import dev.koding.copilot.auth.handleLogin
1013import dev.koding.copilot.completion.api.CompletionRequest
1114import dev.koding.copilot.completion.api.CompletionResponse
1215import dev.koding.copilot.config.settings
1316import dev.koding.copilot.copilotIcon
17+ import dev.koding.copilot.util.Notifications
1418import io.ktor.client.features.*
1519import kotlinx.coroutines.GlobalScope
1620import kotlinx.coroutines.launch
@@ -19,95 +23,79 @@ import kotlin.math.max
1923
2024class CopilotCompletionContributor : CompletionContributor () {
2125
22- private var notified = false
23-
2426 override fun fillCompletionVariants (parameters : CompletionParameters , result : CompletionResultSet ) {
2527 if (parameters.isAutoPopup) return
2628
27- if (settings.token == null ) {
28- if (notified) return
29- @Suppress(" DialogTitleCapitalization" )
30- Notification (
31- " Error Report" ,
32- " GitHub Copilot" ,
33- " You have not set a token for GitHub Copilot." ,
34- NotificationType .ERROR
35- ).notify(parameters.editor.project)
36- return run { notified = true }
37- }
29+ if (settings.token?.isBlank() == true ) return Notifications .send(
30+ " You have not set a token for GitHub Copilot." ,
31+ type = NotificationType .ERROR ,
32+ once = true ,
33+ Notifications .NotificationAction (" Login" ) { handleLogin() })
3834
35+ val (prefix, suffix) = parameters.prefixSuffix
3936 val prompt = """
4037 // Language: ${parameters.originalFile.language.displayName}
4138 // Path: ${parameters.originalFile.name}
4239 ${parameters.prompt}
4340 """ .trimIndent()
4441
45- val (prefix, suffix) = parameters.prefixSuffix
42+ val matcher = result.prefixMatcher
43+ val set = result
44+ .withPrefixMatcher(CopilotPrefixMatcher (matcher.cloneWithPrefix(matcher.prefix)))
45+ .withRelevanceSorter(CompletionSorter .defaultSorter(parameters, matcher).weigh(CopilotWeigher ()))
4646
47+ // TODO: Fix freeze
4748 var response: CompletionResponse ? = null
49+ var errored = false
50+
4851 val job = GlobalScope .launch {
4952 try {
5053 response = CompletionRequest (prompt).send(settings.token!! )
5154 } catch (e: ClientRequestException ) {
52- if (! notified) {
53- @Suppress(" DialogTitleCapitalization" )
54- Notification (
55- " Error Report" ,
56- " GitHub Copilot" ,
57- " Failed to fetch response. Is your copilot token valid?" ,
58- NotificationType .ERROR
59- ).notify(parameters.editor.project)
60- notified = true
61- }
62-
63- return @launch result.stopHere()
55+ errored = true
56+ return @launch Notifications .send(
57+ " Failed to fetch response. Is your copilot token valid?" ,
58+ type = NotificationType .ERROR ,
59+ once = true ,
60+ Notifications .NotificationAction (" Login" ) { handleLogin() })
6461 }
6562 }
6663
67- if (result.isStopped) return
6864 while (response == null ) {
65+ if (errored) return
6966 try {
7067 ProgressManager .getInstance().progressIndicator.checkCanceled()
7168 Thread .sleep(10 )
7269 } catch (e: ProcessCanceledException ) {
7370 job.cancel()
74- return result.stopHere()
71+ return
7572 }
7673 }
7774
7875 val choices = response!! .choices.filter { it.text.isNotBlank() }
7976 if (choices.isEmpty()) return
8077
81- val originalMatcher = result.prefixMatcher
82- val set =
83- result.withPrefixMatcher(CopilotPrefixMatcher (originalMatcher.cloneWithPrefix(originalMatcher.prefix)))
84- .withRelevanceSorter(
85- CompletionSorter .defaultSorter(parameters, originalMatcher)
86- .weigh(CopilotWeigher ())
87- )
88-
8978 set.restartCompletionOnAnyPrefixChange()
9079 set.addAllElements(choices.map { choice ->
9180 val completion = choice.text.removePrefix(prefix.trim()).removeSuffix(suffix.trim())
9281 val insert = " $prefix${completion.trim()} \n "
9382
94- PrioritizedLookupElement .withPriority(
95- LookupElementBuilder .create(choice, " " )
96- .withInsertHandler { context, _ ->
97- val caret = context.editor.caretModel
98- val startOffset = caret.visualLineStart
99- val endOffset = caret.visualLineEnd
100-
101- context.document.deleteString(startOffset, endOffset)
102- context.document.insertString(startOffset, insert)
103- caret.moveToOffset(startOffset + insert.length - 1 )
104- }
105- .withPresentableText(prefix.split(" ." ).last())
106- .withTailText(completion, true )
107- .withTypeText(" GitHub Copilot" )
108- .withIcon(copilotIcon)
109- .bold(), Double .MAX_VALUE
110- )
83+ LookupElementBuilder .create(choice, " " )
84+ .withInsertHandler { context, _ ->
85+ val caret = context.editor.caretModel
86+ val startOffset = caret.visualLineStart
87+ val endOffset = caret.visualLineEnd
88+
89+ context.document.deleteString(startOffset, endOffset)
90+ context.document.insertString(startOffset, insert)
91+ caret.moveToOffset(startOffset + insert.length - 1 )
92+ }
93+ .withPresentableText(prefix.split(" ." ).last().trim())
94+ .withTailText(completion, true )
95+ .withCaseSensitivity(false )
96+ .withTypeText(" GitHub Copilot" )
97+ .withIcon(copilotIcon)
98+ .bold()
11199 })
112100 }
113101
0 commit comments