Skip to content

Commit 58cae3f

Browse files
author
lilei
committed
add search
1 parent e1fd437 commit 58cae3f

16 files changed

+605
-138
lines changed

build.gradle

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,20 @@
1+
buildscript {
2+
repositories {
3+
mavenCentral()
4+
}
5+
dependencies {
6+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.70"
7+
}
8+
}
9+
110
plugins {
211
id 'java'
312
id 'org.jetbrains.intellij' version '0.4.8'
413
}
514

15+
apply plugin: 'java'
16+
apply plugin: "kotlin"
17+
618
group 'me.hiten'
719
version '1.0-SNAPSHOT'
820

@@ -19,6 +31,7 @@ dependencies {
1931
// See https://github.com/JetBrains/gradle-intellij-plugin/
2032
intellij {
2133
version '2019.1.2'
34+
plugins = ['Groovy', 'gradle']
2235
}
2336
patchPluginXml {
2437
changeNotes """

settings.gradle

Lines changed: 0 additions & 2 deletions
This file was deleted.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package me.hiten.completion
2+
3+
import com.intellij.util.net.IdeHttpClientHelpers
4+
import org.apache.http.client.config.RequestConfig
5+
import org.apache.http.client.methods.CloseableHttpResponse
6+
import org.apache.http.client.methods.HttpGet
7+
import org.apache.http.impl.client.HttpClients
8+
import java.util.concurrent.TimeUnit
9+
10+
object Client {
11+
12+
fun get(uri: String): String {
13+
println("get request:$uri")
14+
val clientBuilder = RequestConfig.custom()
15+
IdeHttpClientHelpers.ApacheHttpClient4.setProxyForUrlIfEnabled(clientBuilder, uri)
16+
17+
val response: CloseableHttpResponse = try {
18+
HttpClients.custom()
19+
.setDefaultRequestConfig(clientBuilder.build())
20+
.setConnectionTimeToLive(1, TimeUnit.SECONDS)
21+
.build()
22+
.execute(HttpGet(uri))
23+
} catch (e: Exception) {
24+
return ""
25+
}
26+
27+
return when (response.statusLine.statusCode) {
28+
200 -> response.entity.content.reader().readText()
29+
else -> ""
30+
}
31+
}
32+
}
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package me.hiten.completion
2+
3+
import com.intellij.codeInsight.completion.CompletionResultSet
4+
import com.intellij.codeInsight.lookup.LookupElement
5+
import com.intellij.codeInsight.lookup.LookupElementBuilder
6+
import com.intellij.codeInsight.lookup.LookupElementPresentation
7+
import com.intellij.codeInsight.lookup.LookupElementRenderer
8+
import com.intellij.util.containers.isNullOrEmpty
9+
import me.hiten.completion.androidsearch.AndroidDependencySearcher
10+
import me.hiten.completion.mavensearch.MavenDependencySearcher
11+
12+
class DependencySearchManager(private val dependencyText: DependencyText) {
13+
14+
15+
fun search(result: CompletionResultSet) {
16+
if (dependencyText.isShort) {
17+
return
18+
}
19+
val size = dependencyText.splitText.size
20+
when (size) {
21+
3 -> searchVersion(result)
22+
2 -> searchArtifact(result)
23+
else -> searchDefault(result)
24+
}
25+
}
26+
27+
private fun searchDefault(result: CompletionResultSet) {
28+
var searchDefault = AndroidDependencySearcher().searchDefault(dependencyText.text)
29+
if (needNextSearch(searchDefault)) {
30+
searchDefault = MavenDependencySearcher().searchDefault(dependencyText.text)
31+
}
32+
val list = searchDefault?.map { createLookupElement(it, dependencyText.text + it.groupId) }?.toList()
33+
list?.let {
34+
result.addAllElements(list)
35+
}
36+
}
37+
38+
39+
private fun searchArtifact(result: CompletionResultSet) {
40+
var searchArtifact = AndroidDependencySearcher().searchArtifact(dependencyText.groupId)
41+
if (needNextSearch(searchArtifact)) {
42+
searchArtifact = MavenDependencySearcher().searchArtifact(dependencyText.groupId)
43+
}
44+
val list = searchArtifact?.map { createLookupElement(it, dependencyText.text + it.artifact) }?.toList()
45+
list?.let {
46+
result.addAllElements(list)
47+
}
48+
}
49+
50+
private fun searchVersion(result: CompletionResultSet) {
51+
var searchVersion = AndroidDependencySearcher().searchVersion(dependencyText.groupId, dependencyText.artifactId)
52+
if (needNextSearch(searchVersion)) {
53+
searchVersion = MavenDependencySearcher().searchVersion(dependencyText.groupId, dependencyText.artifactId)
54+
}
55+
val list = searchVersion?.map { createLookupElement(it, dependencyText.text + it.version) }?.toList()
56+
list?.let {
57+
result.addAllElements(list)
58+
}
59+
}
60+
61+
private fun needNextSearch(before: List<DependencySearcher.Result>?): Boolean {
62+
if (before.isNullOrEmpty()) {
63+
return true
64+
}
65+
return false
66+
}
67+
68+
69+
private fun createLookupElement(result: DependencySearcher.Result, cheatString: String): LookupElement {
70+
return LookupElementBuilder.create(result, cheatString).withRenderer(CustomLookupElementRenderer(dependencyText)).withInsertHandler { context, item ->
71+
val quoteArg = dependencyText.quoteArg
72+
val text: String
73+
var insertArg: String? = null
74+
if (quoteArg.isNullOrEmpty()) {
75+
text = result.getFullText()
76+
} else {
77+
if (result.version.isNullOrEmpty() || result.artifact.isNullOrEmpty()) {
78+
text = result.getFullText() + "$$quoteArg"
79+
} else {
80+
text = "${result.groupId}:${result.artifact}:$$quoteArg"
81+
insertArg = "//{ext.$quoteArg = '${result.version}'}"
82+
}
83+
}
84+
val editor = context.editor
85+
val document = context.document
86+
val offset = editor.caretModel.offset
87+
val lineNumber = document.getLineNumber(offset)
88+
val lineStartOffset = document.getLineStartOffset(lineNumber)
89+
val lineEndOffset = document.getLineEndOffset(lineNumber)
90+
val allText = document.text
91+
var lineText = allText.substring(lineStartOffset, lineEndOffset)
92+
lineText = lineText.replace(cheatString, text)
93+
94+
95+
insertArg?.let {
96+
if (lineText.contains("'")) {
97+
lineText = lineText.replace("'", "\"")
98+
}
99+
if (!lineText.contains(insertArg)) {
100+
lineText += insertArg
101+
}
102+
}
103+
document.replaceString(lineStartOffset, lineEndOffset, lineText)
104+
}
105+
}
106+
107+
108+
class CustomLookupElementRenderer(private val dependencyText: DependencyText) : LookupElementRenderer<LookupElement>() {
109+
110+
override fun renderElement(element: LookupElement?, presentation: LookupElementPresentation?) {
111+
element?.let {
112+
val result = (element as LookupElementBuilder).`object` as DependencySearcher.Result
113+
presentation?.typeText = result.source
114+
val quoteArg = dependencyText.quoteArg
115+
if (quoteArg.isNullOrEmpty()) {
116+
presentation?.itemText = result.getFullText()
117+
} else {
118+
if (result.version.isNullOrEmpty() || result.artifact.isNullOrEmpty()) {
119+
presentation?.itemText = result.getFullText() + "$$quoteArg"
120+
} else {
121+
presentation?.itemText = "${result.groupId}:${result.artifact}:$$quoteArg=${result.version}"
122+
}
123+
}
124+
}
125+
126+
}
127+
}
128+
129+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package me.hiten.completion
2+
3+
4+
interface DependencySearcher {
5+
6+
fun searchDefault(keyword: String): List<Result>?
7+
8+
fun searchArtifact(groupId: String): List<Result>?
9+
10+
fun searchVersion(groupId: String, artifact: String): List<Result>?
11+
12+
13+
class Result(var source: String) {
14+
var groupId: String? = null
15+
var artifact: String? = null
16+
var version: String? = null
17+
18+
fun getFullText(): String {
19+
var fullText = groupId
20+
if (!groupId.isNullOrEmpty() && !artifact.isNullOrEmpty()) {
21+
fullText += ":$artifact"
22+
}
23+
if (!artifact.isNullOrEmpty() && !version.isNullOrEmpty()) {
24+
fullText += ":$version"
25+
}
26+
if (fullText.isNullOrEmpty()) {
27+
return ""
28+
}
29+
return fullText!!
30+
}
31+
32+
}
33+
34+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package me.hiten.completion
2+
3+
4+
class DependencyText(val text: String) {
5+
6+
val isShort: Boolean = text.length < 2
7+
8+
val quoteArg: String? = text.split("$").getOrNull(1)
9+
10+
val splitText = text.split("$").getOrElse(0) { text }.split(":")
11+
val groupId = splitText.getOrElse(0) { "" }
12+
val artifactId = splitText.getOrElse(1) { "" }
13+
14+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package me.hiten.completion
2+
3+
import com.intellij.codeInsight.completion.*
4+
import com.intellij.patterns.PlatformPatterns
5+
import com.intellij.util.ProcessingContext
6+
import org.apache.http.util.TextUtils
7+
import org.jetbrains.plugins.gradle.util.GradleConstants
8+
9+
10+
class GradleDependenciesCompletionContributor : CompletionContributor() {
11+
init {
12+
extend(CompletionType.SMART, GRADLE_FILE_PATTERN, GradleDependenciesCompletionProvider())
13+
}
14+
15+
16+
internal class GradleDependenciesCompletionProvider : CompletionProvider<CompletionParameters>() {
17+
18+
override fun addCompletions(parameters: CompletionParameters, context: ProcessingContext, result: CompletionResultSet) {
19+
val originalPosition = parameters.originalPosition
20+
if (originalPosition == null || !originalPosition.isValid) {
21+
return
22+
}
23+
val text = originalPosition.text
24+
if (TextUtils.isEmpty(text)) {
25+
return
26+
}
27+
DependencySearchManager(DependencyText(trimQuote(text))).search(result)
28+
}
29+
}
30+
31+
companion object {
32+
private val GRADLE_FILE_PATTERN = PlatformPatterns.psiElement().and(
33+
PlatformPatterns.psiElement().inFile(PlatformPatterns.psiFile().withName(PlatformPatterns.string().endsWith('.' + GradleConstants.EXTENSION))))
34+
}
35+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package me.hiten.completion
2+
3+
4+
private val splitPattern = Regex(":")
5+
6+
internal fun split(dependency: String) = splitPattern.split(dependency)
7+
8+
internal fun trimQuote(text: String) = text.trim('"', '\'').trimEnd('"', '\'')
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package me.hiten.completion.androidsearch
2+
3+
import me.hiten.completion.DependencySearcher
4+
5+
class AndroidDependencySearcher : DependencySearcher {
6+
7+
8+
companion object {
9+
const val SOURCE = "google"
10+
}
11+
12+
override fun searchDefault(keyword: String): List<DependencySearcher.Result>? {
13+
return GoogleMavenGroupIdSearcher.matchByWords(keyword)?.filter {
14+
it.matched
15+
}?.mapNotNull { it.groupId }?.map {
16+
DependencySearcher.Result(SOURCE).apply {
17+
this.groupId = it
18+
}
19+
}?.toList()
20+
}
21+
22+
override fun searchArtifact(groupId: String): List<DependencySearcher.Result>? {
23+
return GoogleMavenArtifactVersionSearcher.searchArtifact(groupId)?.map {
24+
DependencySearcher.Result(SOURCE).apply {
25+
this.groupId = groupId
26+
this.artifact = it
27+
}
28+
}?.toList()
29+
}
30+
31+
override fun searchVersion(groupId: String, artifact: String): List<DependencySearcher.Result>? {
32+
return GoogleMavenArtifactVersionSearcher.searchVersion(groupId,artifact)?.map {
33+
DependencySearcher.Result(SOURCE).apply {
34+
this.groupId = groupId
35+
this.artifact = artifact
36+
this.version = it
37+
}
38+
}?.toList()
39+
}
40+
}

0 commit comments

Comments
 (0)