-
Notifications
You must be signed in to change notification settings - Fork 5.2k
/
InlineCompletionOvertyper.kt
139 lines (125 loc) · 6.39 KB
/
InlineCompletionOvertyper.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.codeInsight.inline.completion
import com.intellij.codeInsight.inline.completion.InlineCompletionOvertyper.UpdatedElements
import com.intellij.codeInsight.inline.completion.elements.InlineCompletionElement
import com.intellij.codeInsight.inline.completion.elements.InlineCompletionElementManipulator
import com.intellij.codeInsight.inline.completion.session.InlineCompletionContext
import com.intellij.codeInsight.inline.completion.session.InlineCompletionSession
import com.intellij.codeInsight.inline.completion.suggestion.InlineCompletionSuggestionUpdateManager
import com.intellij.codeInsight.inline.completion.suggestion.InlineCompletionSuggestionUpdateManager.UpdateResult
import com.intellij.codeInsight.inline.completion.suggestion.InlineCompletionVariant
import com.intellij.util.concurrency.annotations.RequiresBlockingContext
import com.intellij.util.concurrency.annotations.RequiresEdt
import org.jetbrains.annotations.ApiStatus.ScheduledForRemoval
/**
* Responsible for updating currently rendered [InlineCompletionElement] when a user types a new fragment.
*
* Note that your [InlineCompletionOvertyper] will be called only for elements your provider generated.
* You may rely on the fact, that you will not receive [InlineCompletionElement] of other providers.
*
* Cycle of updating currently rendered elements:
* * [overtype] is called for the current context and 'new elements' are returned.
* * **All current elements are disposed**.
* * If `new_elements` are `not null`, they are rendered.
* * If `new_elements` are `null`, the provided event is used to start a new session.
*
* @see TypingEvent
* @see InlineCompletionProvider.overtyper
* @see InlineCompletionElementManipulator
*/
@Deprecated(message = "Directly use InlineCompletionSuggestionUpdateManager")
@ScheduledForRemoval
interface InlineCompletionOvertyper : InlineCompletionSuggestionUpdateManager.Adapter {
// Back compatibility
override fun onDocumentChange(
event: InlineCompletionEvent.DocumentChange,
variant: InlineCompletionVariant.Snapshot
): UpdateResult {
return when {
variant.isActive -> {
val context = InlineCompletionContext.getOrNull(event.editor) ?: return UpdateResult.Invalidated
if (variant.elements != context.state.elements.map { it.element }) {
return UpdateResult.Invalidated // Unexpected case
}
return when (val overtyped = overtype(context, event.typing)) {
null -> UpdateResult.Invalidated
else -> UpdateResult.Changed(variant.copy(overtyped.elements))
}
}
else -> UpdateResult.Invalidated
}
}
/**
* Updates [context] with respect to new typing [typing]. If [context] can be updated,
* then [UpdatedElements] with new elements is returned and new elements will be rendered right away.
* Otherwise, `null` is returned, as the result the current session will be invalidated
* and [typing] will be considered as an event to start a new session.
*
* If there is no elements after over typing, this method should return `null`.
*
* Note that before rendering new elements, all current elements from [context] are disposed.
*/
@RequiresEdt
@RequiresBlockingContext
fun overtype(context: InlineCompletionContext, typing: TypingEvent): UpdatedElements?
/**
* @param elements represent elements that will be rendered after over typing.
* @param overtypedLength represents a number of symbols that were over typed during this update.
* This number is for logs only, it does not influence on the execution.
*/
class UpdatedElements(val elements: List<InlineCompletionElement>, val overtypedLength: Int)
@Deprecated(message = "Use InlineCompletionSuggestionUpdateManager.Adapter")
@ScheduledForRemoval
abstract class Adapter : InlineCompletionOvertyper {
override fun overtype(context: InlineCompletionContext, typing: TypingEvent): UpdatedElements? {
return when (typing) {
is TypingEvent.OneSymbol -> onOneSymbol(context, typing)
is TypingEvent.NewLine -> onNewLine(context, typing)
is TypingEvent.PairedEnclosureInsertion -> onPairedEnclosureInsertion(context, typing)
}
}
protected open fun onOneSymbol(context: InlineCompletionContext, typing: TypingEvent.OneSymbol): UpdatedElements? {
return null
}
protected open fun onNewLine(context: InlineCompletionContext, typing: TypingEvent.NewLine): UpdatedElements? {
return null
}
protected open fun onPairedEnclosureInsertion(
context: InlineCompletionContext,
typing: TypingEvent.PairedEnclosureInsertion
): UpdatedElements? {
return null
}
}
}
/**
* Default variant of [InlineCompletionOvertyper] that takes into account only [TypingEvent.OneSymbol].
* Other typings cause clearing currently displayed elements and a new session is started.
*
* If a new typed symbol matches the first rendered symbol in the current [InlineCompletionContext],
* then the first non-empty element is truncated by one character using [InlineCompletionElementManipulator.truncateFirstSymbol].
* Subsequent elements are rendered again.
*
* If no [InlineCompletionElementManipulator] for an element is found, then an update is considered as failed,
* and a new session is started.
*
* Note: all empty elements ([InlineCompletionElement.text] is empty) at the start are truncated as well.
*
* @see InlineCompletionElementManipulator
*/
@Deprecated(message = "Use InlineCompletionSuggestionUpdateManager.Default")
@ScheduledForRemoval
open class DefaultInlineCompletionOvertyper : InlineCompletionOvertyper.Adapter() {
private val suggestionUpdateManager
get() = InlineCompletionSuggestionUpdateManager.Default.INSTANCE
override fun onOneSymbol(context: InlineCompletionContext, typing: TypingEvent.OneSymbol): UpdatedElements? {
val event = InlineCompletionEvent.DocumentChange(typing, context.editor)
val elements = context.state.elements.map { it.element }
val variant = checkNotNull(InlineCompletionSession.getOrNull(context.editor)?.capture()).variants.first { it.isActive }
return when (val result = suggestionUpdateManager.update(event, variant)) {
is UpdateResult.Changed -> UpdatedElements(result.snapshot.elements, 0)
UpdateResult.Invalidated -> null
UpdateResult.Same -> UpdatedElements(elements, 0)
}
}
}