@@ -3,6 +3,7 @@ package com.github.teahousestudios.akaribotdevplugin.completion
33import com.github.teahousestudios.akaribotdevplugin.services.JsonLookupService
44import com.intellij.codeInsight.completion.*
55import com.intellij.codeInsight.lookup.LookupElementBuilder
6+ import com.intellij.openapi.util.TextRange
67import com.intellij.util.ProcessingContext
78
89class JsonCompletionProvider : CompletionProvider <CompletionParameters >() {
@@ -14,32 +15,68 @@ class JsonCompletionProvider : CompletionProvider<CompletionParameters>() {
1415 val project = parameters.position.project
1516 val items = JsonLookupService .getInstance(project).getLocaleData()
1617
18+ // find the string literal element ancestor to compute a prefix relative to the string start
19+ val stringElem = findStringLiteralElement(parameters)
20+ val doc = parameters.editor.document
21+ val caret = parameters.offset
22+ val prefix = if (stringElem != null ) {
23+ try {
24+ val start = stringElem.textRange.startOffset
25+ val raw = doc.getText(TextRange (start, caret))
26+ // take substring after last space within the string literal
27+ val lastSpace = raw.lastIndexOf(' ' )
28+ val token = if (lastSpace >= 0 ) raw.substring(lastSpace + 1 ) else raw
29+ // strip leading quote characters and non-alphanumeric chars so matching focuses on the token
30+ val cleaned = token.trimStart { ch -> ch == ' \' ' || ch == ' "' || ! ch.isLetterOrDigit() }
31+ cleaned
32+ } catch (_: Exception ) {
33+ " "
34+ }
35+ } else {
36+ " "
37+ }
38+
39+ val localResult = result.withPrefixMatcher(prefix)
40+
1741 for (item in items) {
18- result .addElement(LookupElementBuilder .create(item.key).withTypeText(item.value))
42+ localResult .addElement(LookupElementBuilder .create(item.key).withTypeText(item.value))
1943
2044 // I18N form with InsertHandler to avoid duplicate '{' when user already typed it
2145 val i18n = " {I18N:${item.key} }"
2246 val i18nElement = LookupElementBuilder .create(i18n).withTypeText(item.value)
2347 .withInsertHandler { ctx, _ ->
24- val doc = ctx.document
25- val start = ctx.startOffset
26- if (start > 0 ) {
48+ val d = ctx.document
49+ val startOff = ctx.startOffset
50+ if (startOff > 0 ) {
2751 try {
28- // look backwards skipping whitespace to find a previous non-space character
29- var i = start - 1
30- val seq = doc.charsSequence
52+ var i = startOff - 1
53+ val seq = d.charsSequence
54+ // skip whitespace backwards
3155 while (i >= 0 && seq[i].isWhitespace()) i--
3256 if (i >= 0 && seq[i] == ' {' ) {
33- // delete from the '{' up to the insertion start (removes brace and any spaces)
34- doc.deleteString(i, start)
57+ d.deleteString(i, startOff)
3558 }
3659 } catch (_: Exception ) {
3760 // ignore
3861 }
3962 }
4063 }
4164
42- result.addElement(i18nElement)
65+ localResult.addElement(i18nElement)
66+ }
67+ }
68+
69+ private fun findStringLiteralElement (parameters : CompletionParameters ): com.intellij.psi.PsiElement ? {
70+ var element = parameters.position
71+ var depth = 0
72+ while (element != null && depth < 40 ) {
73+ val name = element::class .java.simpleName
74+ if (name.contains(" PyStringLiteralExpression" ) || name.contains(" StringTemplateExpression" ) || name.contains(" LiteralExpression" ) || name.contains(" StringLiteralExpression" ) || name.contains(" KtLiteralStringTemplateEntry" )) {
75+ return element
76+ }
77+ element = element.parent
78+ depth++
4379 }
80+ return null
4481 }
4582}
0 commit comments