[Inlay Text Hints] added action to report tourbled inline hints

This commit is contained in:
Yaroslav Lepenkin
2016-08-25 16:20:49 +03:00
parent 327f3bd4a4
commit 292e231cc8
5 changed files with 246 additions and 1 deletions
@@ -21,6 +21,7 @@ import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorCustomElementRenderer;
import com.intellij.openapi.editor.EditorCustomTextElementRenderer;
import com.intellij.openapi.editor.Inlay;
import com.intellij.openapi.editor.impl.FontInfo;
import com.intellij.openapi.editor.markup.TextAttributes;
@@ -124,7 +125,7 @@ public class ParameterHintsPresentationManager implements Disposable {
return metrics;
}
private static class MyRenderer implements EditorCustomElementRenderer {
private static class MyRenderer implements EditorCustomTextElementRenderer {
private String myText;
private int startWidth;
private int steps;
@@ -147,6 +148,12 @@ public class ParameterHintsPresentationManager implements Disposable {
step = 1;
steps = Math.max(1, Math.abs(endWidth - startWidth) / metrics.charWidth('a') / ANIMATION_CHARS_PER_STEP);
}
@NotNull
@Override
public String getText() {
return myText;
}
public boolean nextStep() {
return ++step <= steps;
@@ -0,0 +1,143 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.reporting
import com.intellij.codeInsight.hint.HintManager
import com.intellij.openapi.actionSystem.*
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.PathManager
import com.intellij.openapi.components.ApplicationComponent
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.EditorCustomTextElementRenderer
import com.intellij.openapi.editor.Inlay
import com.intellij.openapi.util.TextRange
import com.intellij.openapi.util.registry.Registry
import java.io.File
class InlineHintReporterRegistration : ApplicationComponent {
override fun getComponentName() = "Inline Hints Reporter Initializer"
override fun initComponent() {
if (!isHintsEnabled()) return
val manager = ActionManager.getInstance()
val action = ReportMissingOrExcessiveInlineHint()
manager.registerAction("ReportMissingOrExcessiveInlineHint", action)
val group = manager.getAction("EditorPopupMenu") as DefaultActionGroup
group.add(action)
}
override fun disposeComponent() {
}
}
class ReportMissingOrExcessiveInlineHint : AnAction() {
private val text = "Report Missing or Excessive Inline Hint"
private val description = "Text line at caret will be anonymously reported to our servers"
init {
val presentation = templatePresentation
presentation.text = text
presentation.description = description
}
private val recorderId = "inline-hints-reports"
private val file = File(PathManager.getTempPath(), recorderId)
override fun update(e: AnActionEvent) {
if (!isHintsEnabled()) return
val editor = CommonDataKeys.EDITOR.getData(e.dataContext) ?: return
val range = getCurrentLineRange(editor)
if (editor.getInlays(range).isNotEmpty()) {
e.presentation.isEnabled = true
}
}
override fun actionPerformed(e: AnActionEvent) {
val editor = CommonDataKeys.EDITOR.getData(e.dataContext)!!
val document = editor.document
val range = getCurrentLineRange(editor)
val inlays = editor.getInlays(range)
if (inlays.isNotEmpty()) {
val line = document.getText(range)
reportInlays(line.trim(), inlays)
showHint(editor)
}
}
private fun reportInlays(text: String, inlays: List<Inlay>) {
val hints = inlays
.map { it.renderer }
.mapNotNull { if (it is EditorCustomTextElementRenderer) it else null }
.map { it.text }
trySend(text, hints)
}
private fun trySend(text: String, inlays: List<String>) {
val report = InlayReport(text, inlays)
writeToFile(createReportLine(recorderId, report))
trySendFileInBackground()
}
private fun trySendFileInBackground() {
if (!file.exists() || file.length() == 0L) return
ApplicationManager.getApplication().executeOnPooledThread {
val text = file.readText()
if (StatsSender.send(text)) {
file.delete()
}
}
}
private fun showHint(editor: Editor) {
ApplicationManager.getApplication().invokeLater {
HintManager.getInstance().showInformationHint(editor, "Troubled inline hint was reported")
}
}
private fun writeToFile(line: String) {
if (!file.exists()) {
file.createNewFile()
}
file.appendText(line)
}
private fun getCurrentLineRange(editor: Editor): TextRange {
val offset = editor.caretModel.currentCaret.offset
val document = editor.document
val line = document.getLineNumber(offset)
return TextRange(document.getLineStartOffset(line), document.getLineEndOffset(line))
}
}
private fun isHintsEnabled() = Registry.`is`("editor.inline.parameter.hints")
private fun Editor.getInlays(range: TextRange): List<Inlay> {
return inlayModel.getInlineElementsInRange(range.startOffset, range.endOffset)
}
private class InlayReport(var text: String, var inlays: List<String>)
@@ -0,0 +1,23 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.editor;
import org.jetbrains.annotations.NotNull;
public interface EditorCustomTextElementRenderer extends EditorCustomElementRenderer {
@NotNull
String getText();
}
@@ -0,0 +1,69 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.reporting
import com.google.gson.Gson
import com.intellij.openapi.application.PermanentInstallationID
import org.apache.http.client.fluent.Request
import org.apache.http.entity.ContentType
private class StatsServerInfo(var status: String, var url: String) {
fun isServiceAlive() = "ok" == status
}
private object Utils {
val gson = Gson()
}
object StatsSender {
private val infoUrl = "https://www.jetbrains.com/config/features-service-status.json"
private fun requestServerUrl(): String? {
try {
val response = Request.Get(infoUrl).execute().returnContent().asString()
val info = Utils.gson.fromJson(response, StatsServerInfo::class.java)
if (info.isServiceAlive()) return info.url
}
catch (e: Exception) {
}
return null
}
fun send(text: String): Boolean {
val url = requestServerUrl() ?: return false
try {
val response = Request.Post(url).bodyString(text, ContentType.TEXT_HTML).execute()
val code = response.handleResponse { it.statusLine.statusCode }
if (code >= 200 && code < 300) {
return true
}
}
catch (e: Exception) {
}
return false
}
}
fun <T> createReportLine(recorderId: String, data: T): String {
val json = Utils.gson.toJson(data)
val userUid = PermanentInstallationID.get()
val stamp = System.currentTimeMillis()
return "$stamp\t$recorderId\t$userUid\trandom_session_id\t$json"
}
+3
View File
@@ -51,6 +51,9 @@
<component>
<implementation-class>com.intellij.util.xml.impl.JavaDomApplicationComponent</implementation-class>
</component>
<component>
<implementation-class>com.intellij.reporting.InlineHintReporterRegistration</implementation-class>
</component>
</application-components>
<project-components>