Improve J2K progress reporting

This commit is contained in:
Simon Ogorodnik
2020-07-27 14:34:53 +03:00
parent 8bcf1000f6
commit dc963e4ff6
6 changed files with 95 additions and 18 deletions
@@ -298,6 +298,7 @@ interface WithProgressProcessor {
): List<TOutputItem> ): List<TOutputItem>
fun updateState(fileIndex: Int?, phase: Int, description: String) fun updateState(fileIndex: Int?, phase: Int, description: String)
fun updateState(phase: Int, subPhase: Int, subPhaseCount: Int, fileIndex: Int?, description: String)
fun <T> process(action: () -> T): T fun <T> process(action: () -> T): T
} }
@@ -348,6 +349,16 @@ class OldWithProgressProcessor(private val progress: ProgressIndicator?, private
override fun updateState(fileIndex: Int?, phase: Int, description: String) { override fun updateState(fileIndex: Int?, phase: Int, description: String) {
throw AbstractMethodError("Should not be called for old J2K") throw AbstractMethodError("Should not be called for old J2K")
} }
override fun updateState(
phase: Int,
subPhase: Int,
subPhaseCount: Int,
fileIndex: Int?,
description: String
) {
error("Should not be called for old J2K")
}
} }
class ProgressPortionReporter( class ProgressPortionReporter(
@@ -54,7 +54,7 @@ class NewJ2kPostProcessor : PostProcessor {
) { ) {
if (converterContext !is NewJ2kConverterContext) error("Invalid converter context for new J2K") if (converterContext !is NewJ2kConverterContext) error("Invalid converter context for new J2K")
for ((i, group) in processings.withIndex()) { for ((i, group) in processings.withIndex()) {
onPhaseChanged?.invoke(i + 1, group.description) onPhaseChanged?.invoke(i, group.description)
for (processing in group.processings) { for (processing in group.processings) {
try { try {
processing.runProcessingConsideringOptions(target, converterContext) processing.runProcessingConsideringOptions(target, converterContext)
@@ -1,4 +1,5 @@
progress.text={0} - phase {1,number,#} of {2,number,#} progress.text={0} - phase {1,number,#} of {2,number,#}
subphase.progress.text={0} ({1,number,#}/{2,number,#}) - phase {3,number,#} of {4,number,#}
progress.searching.usages.to.update=Searching usages to update... progress.searching.usages.to.update=Searching usages to update...
phase.converting.j2k=Converting Java code to Kotlin code phase.converting.j2k=Converting Java code to Kotlin code
@@ -18,13 +18,13 @@ interface Conversion {
val typeFactory: JKTypeFactory val typeFactory: JKTypeFactory
get() = context.typeFactory get() = context.typeFactory
fun runConversion(treeRoots: List<JKTreeElement>, context: NewJ2kConverterContext): Boolean fun runConversion(treeRoots: Sequence<JKTreeElement>, context: NewJ2kConverterContext): Boolean
} }
interface SequentialBaseConversion : Conversion { interface SequentialBaseConversion : Conversion {
fun runConversion(treeRoot: JKTreeElement, context: NewJ2kConverterContext): Boolean fun runConversion(treeRoot: JKTreeElement, context: NewJ2kConverterContext): Boolean
override fun runConversion(treeRoots: List<JKTreeElement>, context: NewJ2kConverterContext): Boolean { override fun runConversion(treeRoots: Sequence<JKTreeElement>, context: NewJ2kConverterContext): Boolean {
return treeRoots.asSequence().map { runConversion(it, context) }.max() ?: false return treeRoots.asSequence().map { runConversion(it, context) }.max() ?: false
} }
} }
@@ -85,10 +85,20 @@ object ConversionsRunner {
AddElementsInfoConversion(context) AddElementsInfoConversion(context)
) )
fun doApply(trees: List<JKTreeRoot>, context: NewJ2kConverterContext) {
fun doApply(
trees: List<JKTreeRoot>,
context: NewJ2kConverterContext,
updateProgress: (conversionIndex: Int, conversionCount: Int, fileIndex: Int, String) -> Unit
) {
val conversions = createConversions(context) val conversions = createConversions(context)
for (conversion in conversions) { for ((conversionIndex, conversion) in conversions.withIndex()) {
conversion.runConversion(trees, context) val treeSequence = trees.asSequence().onEachIndexed { index, _ ->
updateProgress(conversionIndex, conversions.size, index, conversion::class.simpleName ?: "Converting...")
}
conversion.runConversion(treeSequence, context)
} }
} }
} }
@@ -52,14 +52,15 @@ class NewJavaToKotlinConverter(
private val LOG = Logger.getInstance("#org.jetbrains.kotlin.j2k.JavaToKotlinConverter") private val LOG = Logger.getInstance("#org.jetbrains.kotlin.j2k.JavaToKotlinConverter")
private val phasesCount = J2KConversionPhase.values().size
override fun filesToKotlin( override fun filesToKotlin(
files: List<PsiJavaFile>, files: List<PsiJavaFile>,
postProcessor: PostProcessor, postProcessor: PostProcessor,
progress: ProgressIndicator progress: ProgressIndicator
): FilesResult { ): FilesResult {
progress.isIndeterminate = false progress.isIndeterminate = false
val phasesCount = postProcessor.phasesCount + 1 val withProgressProcessor = NewJ2kWithProgressProcessor(progress, files, postProcessor.phasesCount + phasesCount)
val withProgressProcessor = NewJ2kWithProgressProcessor(progress, files, phasesCount)
return withProgressProcessor.process { return withProgressProcessor.process {
val (results, externalCodeProcessing, context) = val (results, externalCodeProcessing, context) =
ApplicationManager.getApplication().runReadAction(Computable { ApplicationManager.getApplication().runReadAction(Computable {
@@ -69,6 +70,11 @@ class NewJavaToKotlinConverter(
val kotlinFiles = results.mapIndexed { i, result -> val kotlinFiles = results.mapIndexed { i, result ->
runUndoTransparentActionInEdt(inWriteAction = true) { runUndoTransparentActionInEdt(inWriteAction = true) {
val javaFile = files[i] val javaFile = files[i]
withProgressProcessor.updateState(
fileIndex = i,
phase = J2KConversionPhase.CREATE_FILES,
description = "Creating files..."
)
KtPsiFactory(project).createFileWithLightClassSupport( KtPsiFactory(project).createFileWithLightClassSupport(
javaFile.name.replace(".java", ".kt"), javaFile.name.replace(".java", ".kt"),
result!!.text, result!!.text,
@@ -84,7 +90,7 @@ class NewJavaToKotlinConverter(
JKMultipleFilesPostProcessingTarget(kotlinFiles), JKMultipleFilesPostProcessingTarget(kotlinFiles),
context context
) { phase, description -> ) { phase, description ->
withProgressProcessor.updateState(fileIndex = null, phase = phase + 1, description = description) withProgressProcessor.updateState(fileIndex = null, phase = phase + phasesCount, description = description)
} }
FilesResult(kotlinFiles.map { it.text }, externalCodeProcessing) FilesResult(kotlinFiles.map { it.text }, externalCodeProcessing)
} }
@@ -103,7 +109,7 @@ class NewJavaToKotlinConverter(
if (importList == null) { if (importList == null) {
addImportList(createdImportList) addImportList(createdImportList)
} else { } else {
val updatedList = if(importList.firstChild != null) { val updatedList = if (importList.firstChild != null) {
createdImportList.addRangeBefore(importList.firstChild, importList.lastChild, createdImportList.firstChild) createdImportList.addRangeBefore(importList.firstChild, importList.lastChild, createdImportList.firstChild)
} else createdImportList } else createdImportList
importList.replace(updatedList) importList.replace(updatedList)
@@ -149,7 +155,7 @@ class NewJavaToKotlinConverter(
} }
val asts = inputElements.mapIndexed { i, element -> val asts = inputElements.mapIndexed { i, element ->
processor.updateState(i, 1, phaseDescription) processor.updateState(i, J2KConversionPhase.BUILD_AST, phaseDescription)
element to treeBuilder.buildTree(element, saveImports) element to treeBuilder.buildTree(element, saveImports)
} }
val inConversionContext = { element: PsiElement -> val inConversionContext = { element: PsiElement ->
@@ -172,13 +178,18 @@ class NewJavaToKotlinConverter(
externalCodeProcessing, externalCodeProcessing,
languageVersion.supportsFeature(LanguageFeature.FunctionalInterfaceConversion) languageVersion.supportsFeature(LanguageFeature.FunctionalInterfaceConversion)
) )
ConversionsRunner.doApply(asts.withIndex().mapNotNull { (i, ast) -> ConversionsRunner.doApply(asts.mapNotNull { it.second }, context) { conversionIndex, conversionCount, i, desc ->
processor.updateState(i, 1, phaseDescription) processor.updateState(
ast.second J2KConversionPhase.RUN_CONVERSIONS.phaseNumber,
}, context) conversionIndex,
conversionCount,
i,
desc
)
}
val results = asts.mapIndexed { i, elementWithAst -> val results = asts.mapIndexed { i, elementWithAst ->
processor.updateState(i, 1, phaseDescription) processor.updateState(i, J2KConversionPhase.PRINT_CODE, phaseDescription)
val (element, ast) = elementWithAst val (element, ast) = elementWithAst
if (ast == null) return@mapIndexed null if (ast == null) return@mapIndexed null
val code = JKCodeBuilder(context).run { printCodeOut(ast) } val code = JKCodeBuilder(context).run { printCodeOut(ast) }
@@ -215,9 +226,42 @@ class NewJ2kWithProgressProcessor(
} }
override fun updateState(fileIndex: Int?, phase: Int, description: String) { override fun updateState(fileIndex: Int?, phase: Int, description: String) {
if (fileIndex == null)
updateState(phase, 1, 1, fileIndex, description)
else
updateState(phase, 0, 1, fileIndex, description)
}
override fun updateState(
phase: Int,
subPhase: Int,
subPhaseCount: Int,
fileIndex: Int?,
description: String
) {
progress?.checkCanceled() progress?.checkCanceled()
progress?.fraction = phase / phasesCount.toDouble() val singlePhaseFraction = 1.0 / phasesCount.toDouble()
progress?.text = KotlinNJ2KBundle.message("progress.text", description, phase, phasesCount) val singleSubPhaseFraction = singlePhaseFraction / subPhaseCount.toDouble()
var resultFraction = phase * singlePhaseFraction + subPhase * singleSubPhaseFraction
if (files != null && fileIndex != null && files.isNotEmpty()) {
val fileFraction = singleSubPhaseFraction / files.size.toDouble()
resultFraction += fileFraction * fileIndex
}
progress?.fraction = resultFraction
if (subPhaseCount > 1) {
progress?.text = KotlinNJ2KBundle.message(
"subphase.progress.text",
description,
subPhase,
subPhaseCount,
phase + 1,
phasesCount
)
} else {
progress?.text = KotlinNJ2KBundle.message("progress.text", description, phase + 1, phasesCount)
}
progress?.text2 = when { progress?.text2 = when {
files != null && files.isNotEmpty() && fileIndex != null -> files[fileIndex].virtualFile.presentableUrl + if (files.size > 1) " ($fileIndex/${files.size})" else "" files != null && files.isNotEmpty() && fileIndex != null -> files[fileIndex].virtualFile.presentableUrl + if (files.size > 1) " ($fileIndex/${files.size})" else ""
else -> "" else -> ""
@@ -238,4 +282,15 @@ class NewJ2kWithProgressProcessor(
return result!! return result!!
} }
}
internal fun WithProgressProcessor.updateState(fileIndex: Int?, phase: J2KConversionPhase, description: String) {
updateState(fileIndex, phase.phaseNumber, description)
}
internal enum class J2KConversionPhase(val phaseNumber: Int) {
BUILD_AST(0),
RUN_CONVERSIONS(1),
PRINT_CODE(2),
CREATE_FILES(3)
} }