Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor editor notifications #235

Merged
merged 1 commit into from
Nov 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions src/main/kotlin/org/move/bytecode/AptosDecompiler.kt
Original file line number Diff line number Diff line change
Expand Up @@ -80,18 +80,14 @@ class AptosBytecodeDecompiler: BinaryFileDecompiler {
}

fun getDecompilerTargetFileDirOnTemp(project: Project, file: VirtualFile): Path? {
val rootDecompilerDir = getArtifactsDir()
val rootDecompilerDir = decompiledArtifactsFolder()
val projectDecompilerDir = rootDecompilerDir.resolve(project.name)
val root = project.rootPath ?: return null
val relativeFilePath = file.parent.pathAsPath.relativeTo(root)
val targetFileDir = projectDecompilerDir.toPath().resolve(relativeFilePath)
return targetFileDir
}

fun getArtifactsDir(): File {
return File(FileUtil.getTempDirectory(), "intellij-move-decompiled-artifacts")
}

fun sourceFileName(file: VirtualFile): String {
val fileName = file.name
return "$fileName.move"
Expand All @@ -101,6 +97,10 @@ class AptosBytecodeDecompiler: BinaryFileDecompiler {
val fileName = file.name
return "$fileName#decompiled.move"
}

companion object {
fun decompiledArtifactsFolder() = File(FileUtil.getTempDirectory(), "intellij-move-decompiled-artifacts")
}
}

fun Project.createDisposableOnFileChange(file: VirtualFile): Disposable {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import org.move.cli.readString
import org.move.cli.runConfigurations.CommandConfigurationBase.CleanConfiguration.Companion.configurationError
import org.move.cli.runConfigurations.test.AptosTestConsoleProperties.Companion.TEST_TOOL_WINDOW_SETTING_KEY
import org.move.cli.runConfigurations.test.AptosTestRunState
import org.move.cli.settings.aptosExecPath
import org.move.cli.settings.aptosCliPath
import org.move.cli.writePath
import org.move.cli.writeString
import org.move.stdext.exists
Expand Down Expand Up @@ -68,7 +68,7 @@ abstract class CommandConfigurationBase(
val workingDirectory = workingDirectory
?: return configurationError("No working directory specified")

val aptosPath = project.aptosExecPath ?: return configurationError("No Aptos CLI specified")
val aptosPath = project.aptosCliPath ?: return configurationError("No Aptos CLI specified")
if (!aptosPath.exists()) {
return configurationError("Invalid Aptos CLI location: $aptosPath")
}
Expand Down
21 changes: 10 additions & 11 deletions src/main/kotlin/org/move/cli/settings/MvProjectSettingsService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,16 @@ class MvProjectSettingsService(

val Project.moveSettings: MvProjectSettingsService get() = service()

fun Project.getAptosCli(parentDisposable: Disposable? = null): Aptos? {
val aptosExecPath =
AptosExecType.aptosExecPath(
this.moveSettings.aptosExecType,
this.moveSettings.localAptosPath
)
val aptos = aptosExecPath?.let { Aptos(it, parentDisposable) }
return aptos
}
val Project.aptosCliPath: Path?
get() {
val settings = this.moveSettings
return AptosExecType.aptosCliPath(settings.aptosExecType, settings.localAptosPath)
}

fun Project.getAptosCli(
parentDisposable: Disposable? = null
): Aptos? =
this.aptosCliPath?.let { Aptos(it, parentDisposable) }

val Project.isAptosConfigured: Boolean get() = this.getAptosCli() != null

Expand All @@ -106,8 +107,6 @@ fun Project.getAptosCliDisposedOnFileChange(file: VirtualFile): Aptos? {
return this.getAptosCli(anyChangeDisposable)
}

val Project.aptosExecPath: Path? get() = this.getAptosCli()?.cliLocation

fun Path?.isValidExecutable(): Boolean {
return this != null
&& this.toString().isNotBlank()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ enum class AptosExecType {

val bundledAptosCLIPath: Path? get() = BundledAptosManager.getBundledAptosPath()

fun aptosExecPath(execType: AptosExecType, localAptosPath: String?): Path? {
fun aptosCliPath(execType: AptosExecType, localAptosPath: String?): Path? {
val pathCandidate =
when (execType) {
BUNDLED -> bundledAptosCLIPath
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class MoveProjectGenerator: DirectoryProjectGeneratorBase<AptosProjectConfig>(),
) {
val packageName = project.name
val aptosPath =
AptosExecType.aptosExecPath(projectConfig.aptosExecType, projectConfig.localAptosPath)
AptosExecType.aptosCliPath(projectConfig.aptosExecType, projectConfig.localAptosPath)
?: error("validated before")
val aptos = Aptos(aptosPath, disposable)
val moveTomlFile =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class MoveProjectGeneratorPeer(val parentDisposable: Disposable): GeneratorPeerI
override fun validate(): ValidationInfo? {
val panelData = this.chooseAptosCliPanel.data
val aptosExecPath =
AptosExecType.aptosExecPath(panelData.aptosExecType, panelData.localAptosPath)
AptosExecType.aptosCliPath(panelData.aptosExecType, panelData.localAptosPath)
if (aptosExecPath == null) {
return ValidationInfo("Invalid path to Aptos executable")
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,38 +1,30 @@
package org.move.ide.notifications

import com.intellij.ide.impl.isTrusted
import com.intellij.openapi.project.DumbAware
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.ui.EditorNotificationPanel
import org.move.cli.settings.PerProjectAptosConfigurable
import org.move.cli.settings.aptos.AptosExecType.LOCAL
import org.move.cli.settings.aptosExecPath
import org.move.cli.settings.aptosCliPath
import org.move.cli.settings.isValidExecutable
import org.move.cli.settings.moveSettings
import org.move.lang.isMoveFile
import org.move.lang.isMoveTomlManifestFile
import org.move.openapiext.common.isUnitTestMode
import org.move.openapiext.showSettingsDialog
import org.move.stdext.getCliFromPATH

class InvalidBlockchainCliConfiguration(project: Project): MvEditorNotificationProvider(project),
DumbAware {
class InvalidAptosCliConfigurationNotification(project: Project): MvAptosEditorNotificationProvider(project),
DumbAware {

override val VirtualFile.disablingKey: String get() = NOTIFICATION_STATUS_KEY + path
override val notificationProviderId: String get() = NOTIFICATION_STATUS_KEY

override fun createNotificationPanel(file: VirtualFile, project: Project): EditorNotificationPanel? {
if (isUnitTestMode) return null
if (!(file.isMoveFile || file.isMoveTomlManifestFile)) return null
@Suppress("UnstableApiUsage")
if (!project.isTrusted()) return null
if (isNotificationDisabled(file)) return null
override fun createAptosNotificationPanel(file: VirtualFile, project: Project): EditorNotificationPanel? {

if (project.aptosExecPath.isValidExecutable()) return null
if (project.aptosCliPath.isValidExecutable()) return null

val aptosCliFromPATH = getCliFromPATH("aptos")?.toString()
return EditorNotificationPanel().apply {
text = "Aptos CLI path is not provided or invalid"

val aptosCliFromPATH = getCliFromPATH("aptos")?.toString()
if (aptosCliFromPATH != null) {
createActionLabel("Set to \"$aptosCliFromPATH\"") {
project.moveSettings.modify {
Expand All @@ -41,6 +33,7 @@ class InvalidBlockchainCliConfiguration(project: Project): MvEditorNotificationP
}
}
}

createActionLabel("Configure") {
project.showSettingsDialog<PerProjectAptosConfigurable>()
}
Expand All @@ -51,6 +44,10 @@ class InvalidBlockchainCliConfiguration(project: Project): MvEditorNotificationP
}
}

override val enableForScratchFiles: Boolean get() = true

override val enableForDecompiledFiles: Boolean get() = true

companion object {
private const val NOTIFICATION_STATUS_KEY = "org.move.hideMoveNotifications"
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package org.move.ide.notifications

import com.intellij.ide.impl.isTrusted
import com.intellij.ide.scratch.ScratchUtil
import com.intellij.ide.util.PropertiesComponent
import com.intellij.openapi.fileEditor.FileEditor
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.ui.EditorNotificationPanel
import com.intellij.ui.EditorNotificationProvider
import com.intellij.ui.EditorNotifications
import org.move.bytecode.AptosBytecodeDecompiler
import org.move.cli.settings.MvProjectSettingsServiceBase.*
import org.move.lang.isMoveFile
import org.move.lang.isMoveTomlManifestFile
import org.move.lang.toNioPathOrNull
import org.move.openapiext.common.isUnitTestMode
import java.util.function.Function
import javax.swing.JComponent
import kotlin.io.relativeToOrNull

fun updateAllNotifications(project: Project) {
EditorNotifications.getInstance(project).updateAllNotifications()
}

class UpdateNotificationsOnSettingsChangeListener(val project: Project): MoveSettingsListener {

override fun <T: MvProjectSettingsBase<T>> settingsChanged(e: SettingsChangedEventBase<T>) {
updateAllNotifications(project)
}
}

abstract class MvNotificationProvider(protected val project: Project): EditorNotificationProvider {

protected abstract val VirtualFile.disablingKey: String

override fun collectNotificationData(
project: Project,
file: VirtualFile
): Function<in FileEditor, out JComponent?> {
return Function {
createNotificationPanel(file, project)
}
}

abstract fun createNotificationPanel(file: VirtualFile, project: Project): EditorNotificationPanel?

protected fun disableNotification(file: VirtualFile) {
PropertiesComponent.getInstance(project).setValue(file.disablingKey, true)
}

protected fun isNotificationDisabled(file: VirtualFile): Boolean =
PropertiesComponent.getInstance(project).getBoolean(file.disablingKey)

protected fun updateAllNotifications() {
EditorNotifications.getInstance(project).updateAllNotifications()
}
}

abstract class MvAptosEditorNotificationProvider(project: Project): MvNotificationProvider(project) {

abstract val notificationProviderId: String

abstract fun createAptosNotificationPanel(file: VirtualFile, project: Project): EditorNotificationPanel?

open val enableForScratchFiles: Boolean = false
open val enableForDecompiledFiles: Boolean = false

override val VirtualFile.disablingKey: String get() = notificationProviderId + path

override fun createNotificationPanel(file: VirtualFile, project: Project): EditorNotificationPanel? {
// disable in unit tests
if (isUnitTestMode) return null

if (!enableForScratchFiles && ScratchUtil.isScratch(file)) return null
@Suppress("UnstableApiUsage")
if (!project.isTrusted()) return null

// only run for .move or Move.toml files
if (!file.isMoveFile && !file.isMoveTomlManifestFile) return null

val nioFile = file.toNioPathOrNull()?.toFile()
// skip non-physical file
if (nioFile == null) return null

if (!enableForDecompiledFiles) {
// check whether file is a decompiler artifact
val decompiledArtifactsFolder = AptosBytecodeDecompiler.decompiledArtifactsFolder()
// belongs to the decompiled artifacts directory
if (nioFile.relativeToOrNull(decompiledArtifactsFolder) != null) return null
}

// explicitly disabled in file
if (isNotificationDisabled(file)) return null

return createAptosNotificationPanel(file, project)
}

}
Loading