Skip to content

Commit cf6e5f0

Browse files
committed
Fix NBTT reformatting for read-only files
1 parent 00d5d02 commit cf6e5f0

File tree

5 files changed

+58
-26
lines changed

5 files changed

+58
-26
lines changed

build.gradle.kts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ dependencies {
8686

8787
compile(files(gradleToolingExtensionJar))
8888

89+
// gradle-intellij-plugin doesn't attach sources properly for Kotlin unless it's manually defined here
90+
// compileOnly since it's only here for reference
91+
compileOnly(kotlin("stdlib-jdk8"))
92+
8993
"jflex"("org.jetbrains.idea:jflex:1.7.0-b7f882a")
9094
"jflex-skeleton"("org.jetbrains.idea:jflex:1.7.0-c1fdf11:idea@skeleton")
9195
"grammar-kit"("org.jetbrains.idea:grammar-kit:1.5.1")

src/main/kotlin/com/demonwav/mcdev/nbt/NbtVirtualFile.kt

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,19 @@ package com.demonwav.mcdev.nbt
1313
import com.demonwav.mcdev.nbt.editor.CompressionSelection
1414
import com.demonwav.mcdev.nbt.editor.NbtToolbar
1515
import com.demonwav.mcdev.nbt.lang.NbttFile
16+
import com.demonwav.mcdev.nbt.lang.NbttLanguage
17+
import com.demonwav.mcdev.util.invokeLaterAny
18+
import com.demonwav.mcdev.util.runWriteAction
1619
import com.intellij.notification.Notification
1720
import com.intellij.notification.NotificationType
1821
import com.intellij.openapi.project.Project
1922
import com.intellij.openapi.vfs.VfsUtilCore
2023
import com.intellij.openapi.vfs.VirtualFile
24+
import com.intellij.psi.PsiDocumentManager
25+
import com.intellij.psi.PsiFile
26+
import com.intellij.psi.PsiFileFactory
2127
import com.intellij.psi.PsiManager
28+
import com.intellij.psi.codeStyle.CodeStyleManager
2229
import java.io.ByteArrayInputStream
2330
import java.io.ByteArrayOutputStream
2431
import java.io.DataOutputStream
@@ -33,20 +40,37 @@ class NbtVirtualFile(private val backingFile: VirtualFile, private val project:
3340
val parseSuccessful: Boolean
3441

3542
init {
43+
this.bytes = byteArrayOf()
44+
var text: String
45+
3646
var tempCompressed: Boolean
3747
var tempParseSuccessful: Boolean
3848
try {
3949
val (rootCompound, isCompressed) = Nbt.buildTagTree(backingFile.inputStream, TimeUnit.SECONDS.toMillis(1))
40-
this.bytes = rootCompound.toString().toByteArray()
50+
text = rootCompound.toString()
4151
tempCompressed = isCompressed
4252
tempParseSuccessful = true
4353
} catch (e: MalformedNbtFileException) {
44-
this.bytes = "Malformed NBT file:\n${e.message}".toByteArray()
54+
text = "Malformed NBT file:\n${e.message}"
4555
tempCompressed = false
4656
tempParseSuccessful = false
4757
}
58+
4859
this.isCompressed = tempCompressed
4960
this.parseSuccessful = tempParseSuccessful
61+
62+
if (this.parseSuccessful) {
63+
val psiFile = PsiFileFactory.getInstance(project).createFileFromText(NbttLanguage, text)
64+
invokeLaterAny {
65+
psiFile.runWriteAction {
66+
this.bytes = PsiDocumentManager.getInstance(project).getDocument(
67+
CodeStyleManager.getInstance(project).reformat(psiFile, true) as PsiFile
68+
)?.immutableCharSequence?.toString()?.toByteArray() ?: byteArrayOf()
69+
}
70+
}
71+
} else {
72+
this.bytes = text.toByteArray()
73+
}
5074
}
5175

5276
override fun refresh(asynchronous: Boolean, recursive: Boolean, postRunnable: Runnable?) {
@@ -69,7 +93,7 @@ class NbtVirtualFile(private val backingFile: VirtualFile, private val project:
6993
override fun getOutputStream(requestor: Any, newModificationStamp: Long, newTimeStamp: Long) =
7094
VfsUtilCore.outputStreamAddingBOM(NbtOutputStream(this, requestor), this)
7195

72-
fun writeFile(requestor: Any) {
96+
fun writeFile(requester: Any) {
7397
val nbttFile = PsiManager.getInstance(project).findFile(this) as NbttFile
7498
val rootTag = nbttFile.getRootCompound()?.getRootCompoundTag()
7599

@@ -83,11 +107,14 @@ class NbtVirtualFile(private val backingFile: VirtualFile, private val project:
83107
return
84108
}
85109

110+
this.bytes = PsiDocumentManager.getInstance(project).getDocument(nbttFile)?.immutableCharSequence?.toString()?.toByteArray()
111+
?: byteArrayOf()
112+
86113
// just to be safe
87114
this.parent.bom = null
88115
val filteredStream = when (toolbar.selection) {
89-
CompressionSelection.GZIP -> GZIPOutputStream(this.parent.getOutputStream(requestor))
90-
CompressionSelection.UNCOMPRESSED -> this.parent.getOutputStream(requestor)
116+
CompressionSelection.GZIP -> GZIPOutputStream(this.parent.getOutputStream(requester))
117+
CompressionSelection.UNCOMPRESSED -> this.parent.getOutputStream(requester)
91118
}
92119

93120
DataOutputStream(filteredStream).use { stream ->

src/main/kotlin/com/demonwav/mcdev/nbt/editor/NbtFileEditorProvider.kt

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ package com.demonwav.mcdev.nbt.editor
1212

1313
import com.demonwav.mcdev.nbt.NbtVirtualFile
1414
import com.demonwav.mcdev.nbt.filetype.NbtFileType
15-
import com.intellij.codeInsight.actions.ReformatCodeProcessor
1615
import com.intellij.openapi.fileEditor.FileEditor
1716
import com.intellij.openapi.fileEditor.FileEditorPolicy
1817
import com.intellij.openapi.fileEditor.FileEditorState
@@ -23,7 +22,6 @@ import com.intellij.openapi.project.DumbAware
2322
import com.intellij.openapi.project.Project
2423
import com.intellij.openapi.util.Key
2524
import com.intellij.openapi.vfs.VirtualFile
26-
import com.intellij.psi.PsiManager
2725
import java.awt.BorderLayout
2826
import java.beans.PropertyChangeListener
2927
import javax.swing.JPanel
@@ -40,11 +38,6 @@ class NbtFileEditorProvider : PsiAwareTextEditorProvider(), DumbAware {
4038
NonProjectFileWritingAccessProvider.allowWriting(nbtFile)
4139
}
4240

43-
// Format to their format preferences
44-
PsiManager.getInstance(project).findFile(nbtFile)?.let {
45-
ReformatCodeProcessor(it, false).run()
46-
}
47-
4841
nbtFile.toolbar = fileEditor.toolbar
4942
return fileEditor
5043
}
@@ -54,7 +47,7 @@ class NbtFileEditorProvider : PsiAwareTextEditorProvider(), DumbAware {
5447
}
5548
}
5649

57-
private class NbtFileEditor(private val editor: FileEditor, nbtFile: NbtVirtualFile) : FileEditor {
50+
private class NbtFileEditor(private val editor: FileEditor, private val nbtFile: NbtVirtualFile) : FileEditor {
5851

5952
val toolbar = NbtToolbar(nbtFile)
6053
private val component = JPanel(BorderLayout())

src/main/kotlin/com/demonwav/mcdev/nbt/editor/NbtToolbar.kt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import javax.swing.JPanel
1919
class NbtToolbar(nbtFile: NbtVirtualFile) {
2020
lateinit var panel: JPanel
2121
private lateinit var compressionBox: JComboBox<CompressionSelection>
22-
private lateinit var saveButton: JButton
22+
lateinit var saveButton: JButton
2323

2424
private var lastSelection: CompressionSelection
2525

@@ -35,7 +35,7 @@ class NbtToolbar(nbtFile: NbtVirtualFile) {
3535
compressionBox.isEnabled = false
3636
} else {
3737
compressionBox.addActionListener {
38-
saveButton.isVisible = lastSelection != selection
38+
checkModified()
3939
}
4040
}
4141

@@ -44,14 +44,19 @@ class NbtToolbar(nbtFile: NbtVirtualFile) {
4444
}
4545

4646
saveButton.addActionListener {
47-
saveButton.isVisible = false
47+
lastSelection = selection
48+
checkModified()
4849

4950
runWriteTaskLater {
5051
nbtFile.writeFile(this)
5152
}
5253
}
5354
}
5455

56+
private fun checkModified() {
57+
saveButton.isVisible = lastSelection != selection
58+
}
59+
5560
val selection
5661
get() = compressionBox.selectedItem as CompressionSelection
5762
}

src/main/kotlin/com/demonwav/mcdev/util/utils.kt

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,22 @@ import com.intellij.openapi.command.WriteCommandAction
1919
import com.intellij.openapi.fileEditor.FileDocumentManager
2020
import com.intellij.openapi.module.Module
2121
import com.intellij.openapi.module.ModuleManager
22+
import com.intellij.openapi.util.Computable
23+
import com.intellij.openapi.util.Ref
2224
import com.intellij.psi.PsiDocumentManager
2325
import com.intellij.psi.PsiFile
2426
import org.jetbrains.annotations.Contract
2527

26-
inline fun runWriteTask(crossinline func: () -> Unit) {
28+
inline fun <T : Any?> runWriteTask(crossinline func: () -> T): T =
2729
if (ApplicationManager.getApplication().isWriteAccessAllowed) {
2830
func()
2931
} else {
3032
invokeAndWait {
31-
ApplicationManager.getApplication().runWriteAction {
33+
ApplicationManager.getApplication().runWriteAction(Computable {
3234
func()
33-
}
35+
})
3436
}
3537
}
36-
}
3738

3839
inline fun runWriteTaskLater(crossinline func: () -> Unit) {
3940
if (ApplicationManager.getApplication().isWriteAccessAllowed) {
@@ -47,13 +48,14 @@ inline fun runWriteTaskLater(crossinline func: () -> Unit) {
4748
}
4849
}
4950

50-
inline fun invokeAndWait(crossinline func: () -> Unit) {
51+
inline fun <T : Any?> invokeAndWait(crossinline func: () -> T): T =
5152
if (ApplicationManager.getApplication().isDispatchThread) {
5253
func()
5354
} else {
54-
ApplicationManager.getApplication().invokeAndWait({ func() }, ModalityState.defaultModalityState())
55+
val ref = Ref<T>()
56+
ApplicationManager.getApplication().invokeAndWait({ ref.set(func()) }, ModalityState.defaultModalityState())
57+
ref.get()
5558
}
56-
}
5759

5860
inline fun invokeLater(crossinline func: () -> Unit) {
5961
if (ApplicationManager.getApplication().isDispatchThread) {
@@ -76,7 +78,8 @@ inline fun <T : Any?> PsiFile.runWriteAction(crossinline func: () -> T) =
7678

7779
inline fun <T : Any?> PsiFile.applyWriteAction(crossinline func: PsiFile.() -> T): T {
7880
val result = WriteCommandAction.writeCommandAction(this).withGlobalUndo().compute<T, Throwable> { func() }
79-
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(FileDocumentManager.getInstance().getDocument(this.virtualFile) ?: return result)
81+
PsiDocumentManager.getInstance(project)
82+
.doPostponedOperationsAndUnblockDocument(FileDocumentManager.getInstance().getDocument(this.virtualFile) ?: return result)
8083
return result
8184
}
8285

@@ -96,13 +99,13 @@ inline fun <T : Collection<*>> T.ifEmpty(func: () -> Unit): T {
9699

97100
@Contract(pure = true)
98101
inline fun <T, R> Iterable<T>.mapFirstNotNull(transform: (T) -> R?): R? {
99-
forEach { transform(it)?.let { return it } }
102+
forEach { element -> transform(element)?.let { return it } }
100103
return null
101104
}
102105

103106
@Contract(pure = true)
104107
inline fun <T, R> Array<T>.mapFirstNotNull(transform: (T) -> R?): R? {
105-
forEach { transform(it)?.let { return it } }
108+
forEach { element -> transform(element)?.let { return it } }
106109
return null
107110
}
108111

0 commit comments

Comments
 (0)