Refactoring: introduce file attribute utils

This commit is contained in:
Natalia Selezneva
2018-04-03 16:09:08 +03:00
parent bed5a3c8f3
commit 178dad3b4e
3 changed files with 107 additions and 88 deletions
@@ -6,26 +6,15 @@
package org.jetbrains.kotlin.idea.core.script
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileWithId
import com.intellij.openapi.vfs.newvfs.FileAttribute
import kotlin.reflect.KProperty
import org.jetbrains.kotlin.idea.core.util.fileAttribute
import org.jetbrains.kotlin.idea.core.util.readString
import org.jetbrains.kotlin.idea.core.util.writeString
import java.io.DataInputStream
import java.io.DataOutputStream
var VirtualFile.scriptRelatedModuleName: String? by ScratchModuleNameProperty()
private val moduleNameAttribute = FileAttribute("kotlin-script-moduleName", 1, false)
private class ScratchModuleNameProperty {
operator fun getValue(file: VirtualFile, property: KProperty<*>): String? {
if (file !is VirtualFileWithId) return null
return moduleNameAttribute.readAttributeBytes(file)?.let { String(it) }
}
operator fun setValue(file: VirtualFile, property: KProperty<*>, newValue: String?) {
if (file !is VirtualFileWithId) return
if (newValue != null) {
moduleNameAttribute.writeAttributeBytes(file, newValue.toByteArray())
}
}
}
var VirtualFile.scriptRelatedModuleName: String? by fileAttribute(
name = "kotlin-script-moduleName",
version = 1,
read = DataInputStream::readString,
write = DataOutputStream::writeString
)
@@ -17,75 +17,30 @@
package org.jetbrains.kotlin.idea.core.script
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileWithId
import com.intellij.openapi.vfs.newvfs.FileAttribute
import com.intellij.util.io.DataInputOutputUtil.readSeq
import com.intellij.util.io.DataInputOutputUtil.writeSeq
import com.intellij.util.io.IOUtil.readUTF
import com.intellij.util.io.IOUtil.writeUTF
import org.jetbrains.kotlin.idea.core.util.*
import java.io.DataInput
import java.io.DataOutput
import java.io.File
import kotlin.reflect.KProperty
import kotlin.script.experimental.dependencies.ScriptDependencies
var VirtualFile.scriptDependencies: ScriptDependencies? by ScriptDependenciesProperty()
private val scriptDependencies = FileAttribute("kotlin-script-dependencies", 4, false)
private class ScriptDependenciesProperty {
operator fun setValue(file: VirtualFile, property: KProperty<*>, newValue: ScriptDependencies?) {
if (file !is VirtualFileWithId) return
val output = scriptDependencies.writeAttribute(file)
output.use {
it.writeNullable(newValue) { value ->
with(value) {
writeFileList(classpath)
writeStringList(imports)
writeNullable(javaHome, DataOutput::writeFile)
writeFileList(scripts)
writeFileList(sources)
}
}
var VirtualFile.scriptDependencies: ScriptDependencies? by fileAttribute(
name = "kotlin-script-dependencies",
version = 3,
read = {
ScriptDependencies(
classpath = readFileList(),
imports = readStringList(),
javaHome = readNullable(DataInput::readFile),
scripts = readFileList(),
sources = readFileList()
)
},
write = {
with(it) {
writeFileList(classpath)
writeStringList(imports)
writeNullable(javaHome, DataOutput::writeFile)
writeFileList(scripts)
writeFileList(sources)
}
}
operator fun getValue(file: VirtualFile, property: KProperty<*>): ScriptDependencies? {
if (file !is VirtualFileWithId) return null
val input = scriptDependencies.readAttribute(file)
return input?.use {
it.readNullable {
ScriptDependencies(
classpath = readFileList(),
imports = readStringList(),
javaHome = readNullable(DataInput::readFile),
scripts = readFileList(),
sources = readFileList()
)
}
}
}
}
private fun DataInput.readStringList(): List<String> = readSeq(this) { readString() }
private fun DataInput.readFileList() = readSeq(this) { readFile() }
private fun DataInput.readString() = readUTF(this)
private fun DataInput.readFile() = readUTF(this).let { File(it) }
private fun DataOutput.writeFileList(iterable: Iterable<File>) = writeSeq(this, iterable.toList()) { writeFile(it) }
private fun DataOutput.writeFile(it: File) = writeString(it.canonicalPath)
private fun DataOutput.writeString(string: String) = writeUTF(this, string)
private fun DataOutput.writeStringList(iterable: Iterable<String>) = writeSeq(this, iterable.toList()) { writeString(it) }
private fun <T : Any> DataOutput.writeNullable(nullable: T?, writeT: DataOutput.(T) -> Unit) {
writeBoolean(nullable != null)
nullable?.let { writeT(it) }
}
private fun <T : Any> DataInput.readNullable(readT: DataInput.() -> T): T? {
val hasValue = readBoolean()
return if (hasValue) readT() else null
}
)
@@ -0,0 +1,75 @@
/*
* 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.core.util
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileWithId
import com.intellij.openapi.vfs.newvfs.FileAttribute
import com.intellij.util.io.DataInputOutputUtil.readSeq
import com.intellij.util.io.DataInputOutputUtil.writeSeq
import com.intellij.util.io.IOUtil.readUTF
import com.intellij.util.io.IOUtil.writeUTF
import java.io.*
import kotlin.reflect.KProperty
fun <T : Any> fileAttribute(
name: String,
version: Int,
read: DataInputStream.() -> T,
write: DataOutputStream.(T) -> Unit
): FileAttributeProperty<T> {
return object : FileAttributeProperty<T>(name, version) {
override fun readValue(input: DataInputStream): T = read(input)
override fun writeValue(output: DataOutputStream, value: T) = write(output, value)
}
}
abstract class FileAttributeProperty<T : Any>(name: String, version: Int, private val default: T? = null) {
abstract fun readValue(input: DataInputStream): T
abstract fun writeValue(output: DataOutputStream, value: T)
private val attribute = FileAttribute(name, version, false)
operator fun setValue(file: VirtualFile, property: KProperty<*>, newValue: T?) {
if (file !is VirtualFileWithId) return
attribute.writeAttribute(file).use { output ->
output.writeNullable(newValue) { value ->
writeValue(output, value)
}
}
}
operator fun getValue(file: VirtualFile, property: KProperty<*>): T? {
if (file !is VirtualFileWithId) return null
return attribute.readAttribute(file)?.use { input ->
input.readNullable {
readValue(input)
}
} ?: default
}
}
fun DataInput.readStringList(): List<String> = readSeq(this) { readString() }
fun DataInput.readFileList(): List<File> = readSeq(this) { readFile() }
fun DataInput.readString(): String = readUTF(this)
fun DataInput.readFile() = readUTF(this).let { File(it) }
fun DataOutput.writeFileList(iterable: Iterable<File>) = writeSeq(this, iterable.toList()) { writeFile(it) }
fun DataOutput.writeFile(it: File) = writeString(it.canonicalPath)
fun DataOutput.writeString(string: String) = writeUTF(this, string)
fun DataOutput.writeStringList(iterable: Iterable<String>) = writeSeq(this, iterable.toList()) { writeString(it) }
fun <T : Any> DataOutput.writeNullable(nullable: T?, writeT: DataOutput.(T) -> Unit) {
writeBoolean(nullable != null)
nullable?.let { writeT(it) }
}
fun <T : Any> DataInput.readNullable(readT: DataInput.() -> T): T? {
val hasValue = readBoolean()
return if (hasValue) readT() else null
}