1
1
package com.github.oldmegit.goframehelper.provider
2
2
3
+ import com.github.oldmegit.goframehelper.apiTagValueUtil.*
4
+ import com.github.oldmegit.goframehelper.apiTagValueUtil.TagValue
3
5
import com.github.oldmegit.goframehelper.gf.Gf
4
6
import com.goide.psi.GoAnonymousFieldDefinition
5
7
import com.goide.psi.GoFieldDefinition
6
8
import com.goide.psi.GoStructType
9
+ import com.intellij.codeInsight.completion.CompletionUtilCore
7
10
import com.intellij.codeInsight.lookup.LookupElementBuilder
8
- import com.intellij.openapi.util.TextRange
9
11
import com.intellij.psi.PsiElement
10
12
11
13
class ApiTagProvider : GfProvider () {
14
+ private val valueObject = mapOf<String , TagValue >(
15
+ " method" to Method ,
16
+ " v" to Validation ,
17
+ " mime" to Mime ,
18
+ )
19
+
12
20
override fun addCompletionsEvent () {
13
21
// only struct name containing "Req" or "Res" can need code completion
14
22
if (! isValidStruct()) {
15
23
return
16
24
}
17
25
18
26
if (positionIsTagKey()) {
19
- codeCompletionTagKey()
27
+ keyCodeCompletion()
28
+ } else {
29
+ valueCodeCompletion()
20
30
}
21
31
}
22
32
23
33
override fun isValidFolder (): Boolean {
24
34
return Gf .isApiFile(position.project, parameters.originalFile.virtualFile)
25
35
}
26
36
37
+ private fun getStructType (): PsiElement ? {
38
+ val structType = position.parent.parent.parent.parent
39
+ if (structType is GoStructType ) {
40
+ return structType
41
+ }
42
+ return null
43
+ }
44
+
27
45
private fun isValidStruct (): Boolean {
28
46
val structType = getStructType()
29
47
if (structType == null ) {
@@ -35,97 +53,113 @@ class ApiTagProvider: GfProvider() {
35
53
return lastStr == " Req" || lastStr == " Res"
36
54
}
37
55
38
- private fun codeCompletionTagKey (text : String , tailText : String ) {
39
- result.addElement(
40
- LookupElementBuilder .create(text)
41
- .withInsertHandler { ctx, _ ->
42
- ctx.document.insertString(ctx.tailOffset, " :\"\" " )
43
- ctx.editor.caretModel.moveToOffset(ctx.editor.caretModel.offset + 2 )
44
- }
45
- .withIcon(Gf .icon)
46
- .withTailText(" $tailText " , true )
47
- )
56
+ private fun getFiledPsiElement (): PsiElement ? {
57
+ val fieldDefinition = position.parent.parent.parent.firstChild
58
+ if (fieldDefinition is GoFieldDefinition || fieldDefinition is GoAnonymousFieldDefinition ) {
59
+ return fieldDefinition
60
+ }
61
+ return null
48
62
}
49
63
50
- // check position is tag key
51
- private fun positionIsTagKey (): Boolean {
52
- val rawText = position.text
53
- if (! rawText.contains(" \" " )) {
54
- return true
55
- }
56
- val offset = parameters.offset
57
- var textRange = TextRange (offset - 2 , offset)
58
- var text = parameters.editor.document.getText(textRange)
59
- if (text != " \" " ) {
60
- return false
64
+ private fun getFieldName (): String {
65
+ val name = getFiledPsiElement()?.text
66
+ if (name != null ) {
67
+ return name
61
68
}
62
- textRange = TextRange (offset - 3 , offset)
63
- text = parameters.editor.document.getText(textRange)
64
- return text != " :\" "
69
+ return " "
65
70
}
66
71
67
- private fun codeCompletionTagKey () {
72
+ private fun getFieldNameTag () : Map < String , String > {
68
73
// get filed name
69
74
val filedName = getFieldName()
75
+ val m = hashMapOf<String , String >()
76
+ m.putAll(Gf .openApiTag)
70
77
71
78
if (filedName == " g.Meta" ) {
72
- for ((text, tailText) in Gf .openApiTagGMeta) {
73
- codeCompletionTagKey(text, tailText)
74
- }
79
+ m.putAll(Gf .openApiTagGMeta)
75
80
} else {
76
- for ((text, tailText) in Gf .openApiTagNormal) {
77
- codeCompletionTagKey(text, tailText)
78
- }
81
+ m.putAll(Gf .openApiTagNormal)
79
82
}
80
83
81
- for ((text, tailText) in Gf .openApiTag) {
82
- codeCompletionTagKey(text, tailText)
83
- }
84
+ return m
85
+ }
86
+
87
+ // check position is tag key
88
+ private fun positionIsTagKey (): Boolean {
89
+ val rawText = position.text
90
+ val tagValuePattern = String .format(" \\ w+:\" [^\" ]*?%s.*?\" " , CompletionUtilCore .DUMMY_IDENTIFIER_TRIMMED )
91
+ val regex = Regex (tagValuePattern)
92
+ return ! rawText.contains(regex)
84
93
}
85
94
86
- // check position is tag value
87
- // private fun positionIsTagValue(tagKey: String): Boolean {
88
- // val text = position.text
89
- // val tagKeyMark = "$tagKey:\""
90
- // val tagStart = text.indexOf(tagKeyMark)
91
- // val tagEnd = text.indexOf("\"", tagStart + tagKeyMark.length)
92
- // val offset = parameters.offset
93
- // val textRange = position.textRange
94
- // val stringOffset = offset - textRange.startOffset
95
- //
96
- // val vTextRange = TextRange(tagStart, tagEnd)
97
- // return textRange.contains(offset) && vTextRange.contains(stringOffset)
98
- // }
99
- //
100
- // private fun codeCompletionTagValue(text: String, tailText: String) {
101
- // result.addElement(
102
- // LookupElementBuilder.create(text)
103
- // .withIcon(Gf.icon)
104
- // .withTailText(" $tailText", true)
105
- // )
106
- // }
95
+ // tag key code completion
96
+ private fun keyCodeCompletion () {
97
+ val text = position.text.replace(" `" , " " )
98
+ val textArr = text.split(CompletionUtilCore .DUMMY_IDENTIFIER )
99
+ var prefix = textArr[0 ]
107
100
108
- private fun getStructType (): PsiElement ? {
109
- val structType = position.parent.parent.parent.parent
110
- if (structType is GoStructType ) {
111
- return structType
101
+ if (prefix.endsWith(" " )) {
102
+ prefix = " "
112
103
}
113
- return null
114
- }
115
104
116
- private fun getFiledPsiElement (): PsiElement ? {
117
- val fieldDefinition = position.parent.parent.parent.firstChild
118
- if (fieldDefinition is GoFieldDefinition || fieldDefinition is GoAnonymousFieldDefinition ) {
119
- return fieldDefinition
105
+ val lastSpaceIndex = prefix.lastIndexOf(" " )
106
+ val lastPrefixOfTag = prefix.substring(lastSpaceIndex + 1 )
107
+ val tagList = getFieldNameTag()
108
+
109
+ for ((k, v) in tagList) {
110
+ if (k.startsWith(lastPrefixOfTag)) {
111
+ keyAddElement(prefix + k.removePrefix(lastPrefixOfTag), k , v)
112
+ }
120
113
}
121
- return null
122
114
}
123
115
124
- private fun getFieldName (): String {
125
- val name = getFiledPsiElement()?.text
126
- if (name != null ) {
127
- return name
116
+ // add tag key element
117
+ private fun keyAddElement (lookupString : String , text : String , tail : String = "") {
118
+ result.addElement(
119
+ LookupElementBuilder .create(lookupString)
120
+ .withInsertHandler { ctx, _ ->
121
+ ctx.document.insertString(ctx.tailOffset, " :\"\" " )
122
+ ctx.editor.caretModel.moveToOffset(ctx.editor.caretModel.offset + 2 )
123
+ }
124
+ .withIcon(Gf .icon)
125
+ .withTailText(" $tail " , true )
126
+ .withPresentableText(text)
127
+ )
128
+ }
129
+
130
+ private fun valueCodeCompletion () {
131
+ val text = position.text.replace(" `" , " " )
132
+ val textArr = text.split(CompletionUtilCore .DUMMY_IDENTIFIER )
133
+ val prefix = textArr[0 ]
134
+
135
+ val patten = " \\ w+(?=:\" )"
136
+ val regex = patten.toRegex()
137
+ val keyList = regex.findAll(prefix)
138
+ val current = keyList.last().value
139
+ val tagValue = valueObject[current] ? : return
140
+ val list = tagValue.list
141
+ val separator = tagValue.separator
142
+
143
+ var valueStartIndex = prefix.lastIndexOf(separator)
144
+ if (valueStartIndex == - 1 ) {
145
+ valueStartIndex = prefix.lastIndexOf(" \" " )
128
146
}
129
- return " "
147
+ val valuePrefixOfTag = prefix.substring(valueStartIndex + 1 ).lowercase()
148
+
149
+ for ((k, v) in list) {
150
+ if (k.startsWith(valuePrefixOfTag)) {
151
+ valueAddElement(prefix + k.removePrefix(valuePrefixOfTag), k, v)
152
+ }
153
+ }
154
+ }
155
+
156
+ // add tag value element
157
+ private fun valueAddElement (lookupString : String , text : String , tail : String = "") {
158
+ result.addElement(
159
+ LookupElementBuilder .create(lookupString)
160
+ .withIcon(Gf .icon)
161
+ .withTailText(" $tail " , true )
162
+ .withPresentableText(text)
163
+ )
130
164
}
131
165
}
0 commit comments