Skip to content

Instantly share code, notes, and snippets.

@elihart
Created May 10, 2019 03:23
Show Gist options
  • Select an option

  • Save elihart/732dc1b6c9686b531730f4a7504b9261 to your computer and use it in GitHub Desktop.

Select an option

Save elihart/732dc1b6c9686b531730f4a7504b9261 to your computer and use it in GitHub Desktop.
Kotlin File extension for easily editing the contents of a file
/**
* Edit the contents of a File with a [FileEditor]. The new contents will override the old.
*
* @param lineTransform Called with each line of the file in order.
* Return the new value you would like written in the file, or null to delete the line.
* You can also call [FileEditor.insertNext] to insert a line immediately above the given line, or
* [FileEditor.insertPrevious] to insert a line immediately after the given line.
*/
fun File.edit(lineTransform: FileEditor.(line: String) -> String) {
FileEditor(this).edit(lineTransform)
}
/** Used from [File.edit]. */
class FileEditor(val file: File) {
private var lines: MutableList<String> = file.readLines().toMutableList()
private val lineCount: Int get() = lines.size
private var currentLineIndex = 0
fun insertPrevious(line: String) {
lines.add(currentLineIndex, line)
currentLineIndex++
}
fun insertNext(line: String) {
lines.add(currentLineIndex + 1, line)
}
fun edit(lineTransform: FileEditor.(line: String) -> String?): File {
currentLineIndex = 0
while (currentLineIndex < lineCount) {
val line = lines.getOrNull(currentLineIndex) ?: throw IllegalStateException("No line at $currentLineIndex")
val newLine = lineTransform(line)
if (newLine == null) {
lines.removeAt(currentLineIndex)
} else {
lines[currentLineIndex] = newLine
currentLineIndex++
}
}
return file.replaceContents(lines)
}
}
/**
* Replaces the contents of this file with the given lines.
* Overwrites the old file and returns a new File instance with the new content.
*/
fun File.replaceContents(lines: List<String>): File {
val tempFile = createTempFile()
tempFile.printWriter().use { writer ->
lines.forEach { writer.println(it) }
}
check(this.delete() && tempFile.renameTo(this)) { "failed to replace file" }
return tempFile
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment