Fix issue when proximity features were tracked only as UNDEFINED
[idea/community.git] / plugins / stats-collector / src / com / intellij / stats / completion / LookupCompletedTracker.kt
1 /*
2  * Copyright 2000-2017 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.intellij.stats.completion
18
19 import com.intellij.codeInsight.lookup.LookupAdapter
20 import com.intellij.codeInsight.lookup.LookupElement
21 import com.intellij.codeInsight.lookup.LookupEvent
22 import com.intellij.codeInsight.lookup.impl.LookupImpl
23 import com.intellij.completion.FeatureManagerImpl
24 import com.intellij.stats.personalization.UserFactorDescriptions
25 import com.intellij.stats.personalization.UserFactorStorage
26 import com.jetbrains.completion.ranker.features.impl.FeatureUtils
27
28 /**
29  * @author Vitaliy.Bibaev
30  */
31 class LookupCompletedTracker : LookupAdapter() {
32     override fun lookupCanceled(event: LookupEvent?) {
33         val lookup = event?.lookup as? LookupImpl ?: return
34         val element = lookup.currentItem ?: return
35         if (isSelectedByTyping(lookup, element)) {
36             processTypedSelect(lookup, element)
37         }
38     }
39
40     override fun itemSelected(event: LookupEvent?) {
41         val lookup = event?.lookup as? LookupImpl ?: return
42         val element = event.item ?: return
43         processExplicitSelect(lookup, element)
44     }
45
46     private fun isSelectedByTyping(lookup: LookupImpl, element: LookupElement): Boolean =
47             element.lookupString == lookup.itemPattern(element)
48
49     private fun processElementSelected(lookup: LookupImpl, element: LookupElement) {
50         val relevanceObjects =
51                 lookup.getRelevanceObjects(listOf(element), false)
52         val relevanceMap = relevanceObjects[element]?.associate { it.first to it.second } ?: return
53         val featuresValues = FeatureUtils.preparedMap(relevanceMap)
54         val project = lookup.project
55         val featureManager = FeatureManagerImpl.getInstance()
56         featureManager.binaryFactors.filter { !featureManager.isUserFeature(it.name) }.forEach { feature ->
57             UserFactorStorage.applyOnBoth(project, UserFactorDescriptions.binaryFeatureDescriptor(feature))
58             { updater ->
59                 updater.update(featuresValues[feature.name])
60             }
61         }
62
63         featureManager.doubleFactors.filter { !featureManager.isUserFeature(it.name) }.forEach { feature ->
64             UserFactorStorage.applyOnBoth(project, UserFactorDescriptions.doubleFeatureDescriptor(feature))
65             { updater ->
66                 updater.update(featuresValues[feature.name])
67             }
68         }
69
70         featureManager.categorialFactors.filter { !featureManager.isUserFeature(it.name) }.forEach { feature ->
71             UserFactorStorage.applyOnBoth(project, UserFactorDescriptions.categoriealFeatureDescriptor(feature))
72             { updater ->
73                 updater.update(featuresValues[feature.name])
74             }
75         }
76     }
77
78     private fun processExplicitSelect(lookup: LookupImpl, element: LookupElement) {
79         processElementSelected(lookup, element)
80
81         UserFactorStorage.applyOnBoth(lookup.project, UserFactorDescriptions.COMPLETION_FINISH_TYPE) { updater ->
82             updater.fireExplicitCompletionPerformed()
83         }
84
85         val prefixLength = lookup.getPrefixLength(element)
86         UserFactorStorage.applyOnBoth(lookup.project, UserFactorDescriptions.PREFIX_LENGTH_ON_COMPLETION) { updater ->
87             updater.fireCompletionPerformed(prefixLength)
88         }
89
90         val itemPosition = lookup.selectedIndex
91         if (itemPosition != -1) {
92             UserFactorStorage.applyOnBoth(lookup.project, UserFactorDescriptions.SELECTED_ITEM_POSITION) { updater ->
93                 updater.fireCompletionPerformed(itemPosition)
94             }
95         }
96
97         if (prefixLength > 1) {
98             val pattern = lookup.itemPattern(element)
99             val isMmemonicsUsed = !element.lookupString.startsWith(pattern)
100             UserFactorStorage.applyOnBoth(lookup.project, UserFactorDescriptions.MNEMONICS_USAGE) { updater ->
101                 updater.fireCompletionFinished(isMmemonicsUsed)
102             }
103         }
104     }
105
106     private fun processTypedSelect(lookup: LookupImpl, element: LookupElement) {
107         processElementSelected(lookup, element)
108
109         UserFactorStorage.applyOnBoth(lookup.project, UserFactorDescriptions.COMPLETION_FINISH_TYPE) { updater ->
110             updater.fireTypedSelectPerformed()
111         }
112     }
113 }