Refactoring: move ScratchFileRenderer to separate file

This commit is contained in:
Natalia Selezneva
2018-05-16 12:14:07 +03:00
parent afa6110e6a
commit 614fa9d0c7
5 changed files with 162 additions and 251 deletions
@@ -0,0 +1,78 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.scratch.output
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.EditorCustomElementRenderer
import com.intellij.openapi.editor.impl.ComplementaryFontsRegistry
import com.intellij.openapi.editor.impl.FontInfo
import com.intellij.openapi.editor.markup.TextAttributes
import com.intellij.ui.Colors
import com.intellij.ui.JBColor
import java.awt.Color
import java.awt.Font
import java.awt.Graphics
import java.awt.Rectangle
class InlayScratchFileRenderer(val text: String, private val outputType: ScratchOutputType) : EditorCustomElementRenderer {
private fun getFontInfo(editor: Editor): FontInfo {
val colorsScheme = editor.colorsScheme
val fontPreferences = colorsScheme.fontPreferences
val attributes = getAttributes()
val fontStyle = attributes.fontType
return ComplementaryFontsRegistry.getFontAbleToDisplay(
'a'.toInt(), fontStyle, fontPreferences, FontInfo.getFontRenderContext(editor.contentComponent)
)
}
override fun calcWidthInPixels(editor: Editor): Int {
val fontInfo = getFontInfo(editor)
return fontInfo.fontMetrics().stringWidth(text)
}
override fun paint(editor: Editor, g: Graphics, r: Rectangle, textAttributes: TextAttributes) {
val attributes = getAttributes()
val fgColor = attributes.foregroundColor ?: return
g.color = fgColor
val fontInfo = getFontInfo(editor)
g.font = fontInfo.font
val metrics = fontInfo.fontMetrics()
g.drawString(text, r.x, r.y + metrics.ascent)
}
private fun getAttributes(): TextAttributes {
return when (outputType) {
ScratchOutputType.OUTPUT -> userOutputAttributes
ScratchOutputType.RESULT -> normalAttributes
ScratchOutputType.ERROR -> errorAttributes
}
}
override fun toString(): String {
return "${outputType.name}: ${text.trim()}"
}
companion object {
private val normalAttributes = TextAttributes(
JBColor.GRAY,
null, null, null,
Font.ITALIC
)
private val errorAttributes = TextAttributes(
JBColor(Colors.DARK_RED, Colors.DARK_RED),
null, null, null,
Font.ITALIC
)
private val userOutputColor = Color(0x5C5CFF)
private val userOutputAttributes = TextAttributes(
JBColor(userOutputColor, userOutputColor),
null, null, null,
Font.ITALIC
)
}
}
@@ -0,0 +1,78 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.scratch.output
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.EditorCustomElementRenderer
import com.intellij.openapi.editor.impl.ComplementaryFontsRegistry
import com.intellij.openapi.editor.impl.FontInfo
import com.intellij.openapi.editor.markup.TextAttributes
import com.intellij.ui.Colors
import com.intellij.ui.JBColor
import java.awt.Color
import java.awt.Font
import java.awt.Graphics
import java.awt.Rectangle
class InlayScratchFileRenderer(val text: String, private val outputType: ScratchOutputType) : EditorCustomElementRenderer {
private fun getFontInfo(editor: Editor): FontInfo {
val colorsScheme = editor.colorsScheme
val fontPreferences = colorsScheme.fontPreferences
val attributes = getAttributes()
val fontStyle = attributes.fontType
return ComplementaryFontsRegistry.getFontAbleToDisplay(
'a'.toInt(), fontStyle, fontPreferences, FontInfo.getFontRenderContext(editor.contentComponent)
)
}
override fun calcWidthInPixels(editor: Editor): Int {
val fontInfo = getFontInfo(editor)
return fontInfo.fontMetrics().stringWidth(text)
}
override fun paint(editor: Editor, g: Graphics, r: Rectangle) {
val attributes = getAttributes()
val fgColor = attributes.foregroundColor ?: return
g.color = fgColor
val fontInfo = getFontInfo(editor)
g.font = fontInfo.font
val metrics = fontInfo.fontMetrics()
g.drawString(text, r.x, r.y + metrics.ascent)
}
private fun getAttributes(): TextAttributes {
return when (outputType) {
ScratchOutputType.OUTPUT -> userOutputAttributes
ScratchOutputType.RESULT -> normalAttributes
ScratchOutputType.ERROR -> errorAttributes
}
}
override fun toString(): String {
return "${outputType.name}: ${text.trim()}"
}
companion object {
private val normalAttributes = TextAttributes(
JBColor.GRAY,
null, null, null,
Font.ITALIC
)
private val errorAttributes = TextAttributes(
JBColor(Colors.DARK_RED, Colors.DARK_RED),
null, null, null,
Font.ITALIC
)
private val userOutputColor = Color(0x5C5CFF)
private val userOutputAttributes = TextAttributes(
JBColor(userOutputColor, userOutputColor),
null, null, null,
Font.ITALIC
)
}
}
@@ -17,24 +17,13 @@
package org.jetbrains.kotlin.idea.scratch.output
import com.intellij.execution.ui.ConsoleViewContentType
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.EditorCustomElementRenderer
import com.intellij.openapi.editor.impl.ComplementaryFontsRegistry
import com.intellij.openapi.editor.impl.FontInfo
import com.intellij.openapi.editor.markup.TextAttributes
import com.intellij.openapi.fileEditor.TextEditor
import com.intellij.openapi.util.Disposer
import com.intellij.openapi.util.text.StringUtil
import com.intellij.ui.Colors
import com.intellij.ui.JBColor
import com.intellij.util.ui.UIUtil
import org.jetbrains.kotlin.idea.scratch.ScratchExpression
import org.jetbrains.kotlin.idea.scratch.ScratchFile
import org.jetbrains.kotlin.idea.scratch.ui.ScratchToolWindow
import java.awt.Color
import java.awt.Font
import java.awt.Graphics
import java.awt.Rectangle
object InlayScratchOutputHandler : ScratchOutputHandler {
private const val maxInsertOffset = 60
@@ -83,15 +72,15 @@ object InlayScratchOutputHandler : ScratchOutputHandler {
val existing = editor.inlayModel
.getInlineElementsInRange(lineEndOffset, lineEndOffset)
.singleOrNull { it.renderer is ScratchFileRenderer }
.singleOrNull { it.renderer is InlayScratchFileRenderer }
if (existing != null) {
existing.dispose()
editor.inlayModel.addInlineElement(
lineEndOffset,
ScratchFileRenderer((existing.renderer as ScratchFileRenderer).text + "; " + inlayText, outputType)
InlayScratchFileRenderer((existing.renderer as InlayScratchFileRenderer).text + "; " + inlayText, outputType)
)
} else {
editor.inlayModel.addInlineElement(lineEndOffset, ScratchFileRenderer(" ".repeat(spaceCount) + inlayText, outputType))
editor.inlayModel.addInlineElement(lineEndOffset, InlayScratchFileRenderer(" ".repeat(spaceCount) + inlayText, outputType))
}
}
}
@@ -108,68 +97,9 @@ object InlayScratchOutputHandler : ScratchOutputHandler {
UIUtil.invokeLaterIfNeeded {
editor
.editor.inlayModel.getInlineElementsInRange(0, editor.editor.document.textLength)
.filter { it.renderer is ScratchFileRenderer }
.filter { it.renderer is InlayScratchFileRenderer }
.forEach { Disposer.dispose(it) }
}
}
class ScratchFileRenderer(val text: String, val outputType: ScratchOutputType) : EditorCustomElementRenderer {
private fun getFontInfo(editor: Editor): FontInfo {
val colorsScheme = editor.colorsScheme
val fontPreferences = colorsScheme.fontPreferences
val attributes = getAttributes()
val fontStyle = attributes.fontType
return ComplementaryFontsRegistry.getFontAbleToDisplay(
'a'.toInt(), fontStyle, fontPreferences, FontInfo.getFontRenderContext(editor.contentComponent)
)
}
override fun calcWidthInPixels(editor: Editor): Int {
val fontInfo = getFontInfo(editor)
return fontInfo.fontMetrics().stringWidth(text)
}
override fun paint(editor: Editor, g: Graphics, r: Rectangle, textAttributes: TextAttributes) {
val attributes = getAttributes()
val fgColor = attributes.foregroundColor ?: return
g.color = fgColor
val fontInfo = getFontInfo(editor)
g.font = fontInfo.font
val metrics = fontInfo.fontMetrics()
g.drawString(text, r.x, r.y + metrics.ascent)
}
private fun getAttributes(): TextAttributes {
return when (outputType) {
ScratchOutputType.OUTPUT -> userOutputAttributes
ScratchOutputType.RESULT -> normalAttributes
ScratchOutputType.ERROR -> errorAttributes
}
}
override fun toString(): String {
return "${outputType.name}: ${text.trim()}"
}
companion object {
private val normalAttributes = TextAttributes(
JBColor.GRAY,
null, null, null,
Font.ITALIC
)
private val errorAttributes = TextAttributes(
JBColor(Colors.DARK_RED, Colors.DARK_RED),
null, null, null,
Font.ITALIC
)
private val userOutputColor = Color(0x5C5CFF)
private val userOutputAttributes = TextAttributes(
JBColor(userOutputColor, userOutputColor),
null, null, null,
Font.ITALIC
)
}
}
}
@@ -1,175 +0,0 @@
/*
* Copyright 2010-2017 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 org.jetbrains.kotlin.idea.scratch.output
import com.intellij.execution.ui.ConsoleViewContentType
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.EditorCustomElementRenderer
import com.intellij.openapi.editor.impl.ComplementaryFontsRegistry
import com.intellij.openapi.editor.impl.FontInfo
import com.intellij.openapi.editor.markup.TextAttributes
import com.intellij.openapi.fileEditor.TextEditor
import com.intellij.openapi.util.Disposer
import com.intellij.openapi.util.text.StringUtil
import com.intellij.ui.Colors
import com.intellij.ui.JBColor
import com.intellij.util.ui.UIUtil
import org.jetbrains.kotlin.idea.scratch.ScratchExpression
import org.jetbrains.kotlin.idea.scratch.ScratchFile
import org.jetbrains.kotlin.idea.scratch.ui.ScratchToolWindow
import java.awt.Color
import java.awt.Font
import java.awt.Graphics
import java.awt.Rectangle
object InlayScratchOutputHandler : ScratchOutputHandler {
private const val maxInsertOffset = 60
private const val minSpaceCount = 4
override fun onStart(file: ScratchFile) {
clear(file)
}
override fun handle(file: ScratchFile, expression: ScratchExpression, output: ScratchOutput) {
val inlayText = StringUtil.shortenTextWithEllipsis(output.text.substringBefore("\n"), 50, 0)
if (inlayText != output.text) {
ScratchToolWindow.addMessageToToolWindow(file.project, output.text, ConsoleViewContentType.NORMAL_OUTPUT)
}
createInlay(file, expression.lineStart, inlayText, output.type)
if (output.type == ScratchOutputType.ERROR) {
error(file, output.text)
}
}
override fun error(file: ScratchFile, message: String) {
ScratchToolWindow.addMessageToToolWindow(file.project, message, ConsoleViewContentType.ERROR_OUTPUT)
}
override fun onFinish(file: ScratchFile) {
}
override fun clear(file: ScratchFile) {
clearInlays(file.editor)
ScratchToolWindow.clearToolWindow(file.project)
}
private fun createInlay(file: ScratchFile, line: Int, inlayText: String, outputType: ScratchOutputType) {
UIUtil.invokeLaterIfNeeded {
val editor = file.editor.editor
val lineStartOffset = editor.document.getLineStartOffset(line)
val lineEndOffset = editor.document.getLineEndOffset(line)
val lineLength = lineEndOffset - lineStartOffset
var spaceCount = maxLineLength(file) - lineLength + minSpaceCount
while(spaceCount + lineLength > maxInsertOffset && spaceCount > minSpaceCount) spaceCount--
val existing = editor.inlayModel
.getInlineElementsInRange(lineEndOffset, lineEndOffset)
.singleOrNull { it.renderer is ScratchFileRenderer }
if (existing != null) {
existing.dispose()
editor.inlayModel.addInlineElement(
lineEndOffset,
ScratchFileRenderer((existing.renderer as ScratchFileRenderer).text + "; " + inlayText, outputType)
)
} else {
editor.inlayModel.addInlineElement(lineEndOffset, ScratchFileRenderer(" ".repeat(spaceCount) + inlayText, outputType))
}
}
}
private fun maxLineLength(file: ScratchFile): Int {
val doc = file.editor.editor.document
return (0 until doc.lineCount)
.map { doc.getLineEndOffset(it) - doc.getLineStartOffset(it) }
.max()
?: -1
}
private fun clearInlays(editor: TextEditor) {
UIUtil.invokeLaterIfNeeded {
editor
.editor.inlayModel.getInlineElementsInRange(0, editor.editor.document.textLength)
.filter { it.renderer is ScratchFileRenderer }
.forEach { Disposer.dispose(it) }
}
}
class ScratchFileRenderer(val text: String, val outputType: ScratchOutputType) : EditorCustomElementRenderer {
private fun getFontInfo(editor: Editor): FontInfo {
val colorsScheme = editor.colorsScheme
val fontPreferences = colorsScheme.fontPreferences
val attributes = getAttributes()
val fontStyle = attributes.fontType
return ComplementaryFontsRegistry.getFontAbleToDisplay(
'a'.toInt(), fontStyle, fontPreferences, FontInfo.getFontRenderContext(editor.contentComponent)
)
}
override fun calcWidthInPixels(editor: Editor): Int {
val fontInfo = getFontInfo(editor)
return fontInfo.fontMetrics().stringWidth(text)
}
override fun paint(editor: Editor, g: Graphics, r: Rectangle) {
val attributes = getAttributes()
val fgColor = attributes.foregroundColor ?: return
g.color = fgColor
val fontInfo = getFontInfo(editor)
g.font = fontInfo.font
val metrics = fontInfo.fontMetrics()
g.drawString(text, r.x, r.y + metrics.ascent)
}
private fun getAttributes(): TextAttributes {
return when (outputType) {
ScratchOutputType.OUTPUT -> userOutputAttributes
ScratchOutputType.RESULT -> normalAttributes
ScratchOutputType.ERROR -> errorAttributes
}
}
override fun toString(): String {
return "${outputType.name}: ${text.trim()}"
}
companion object {
private val normalAttributes = TextAttributes(
JBColor.GRAY,
null, null, null,
Font.ITALIC
)
private val errorAttributes = TextAttributes(
JBColor(Colors.DARK_RED, Colors.DARK_RED),
null, null, null,
Font.ITALIC
)
private val userOutputColor = Color(0x5C5CFF)
private val userOutputAttributes = TextAttributes(
JBColor(userOutputColor, userOutputColor),
null, null, null,
Font.ITALIC
)
}
}
}
@@ -35,7 +35,7 @@ import com.intellij.util.ui.UIUtil
import org.jetbrains.kotlin.compatibility.projectDisposableEx
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.scratch.actions.RunScratchAction
import org.jetbrains.kotlin.idea.scratch.output.InlayScratchOutputHandler
import org.jetbrains.kotlin.idea.scratch.output.InlayScratchFileRenderer
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
import org.jetbrains.kotlin.idea.util.application.runWriteAction
@@ -129,7 +129,7 @@ abstract class AbstractScratchRunActionTest : FileEditorManagerTestCase() {
doc.getLineStartOffset(line),
doc.getLineEndOffset(line)
).map { it.renderer }
.filterIsInstance<InlayScratchOutputHandler.ScratchFileRenderer>()
.filterIsInstance<InlayScratchFileRenderer>()
.forEach {
val str = it.toString()
val offset = doc.getLineEndOffset(line); actualOutput.insert(offset, " // $str")