diff --git a/.github/workflows/ScalaCI.yml b/.github/workflows/ScalaCI.yml index d280e1e..e9bcc30 100644 --- a/.github/workflows/ScalaCI.yml +++ b/.github/workflows/ScalaCI.yml @@ -13,48 +13,60 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up JDK 17 - uses: actions/setup-java@v1 + uses: actions/setup-java@v4 with: + distribution: temurin java-version: 17 - cache: 'sbt' + cache: sbt + - uses: sbt/setup-sbt@v1 + - uses: coursier/cache-action@v6 - name: Build run: sbt compile lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up JDK 17 - uses: actions/setup-java@v1 + uses: actions/setup-java@v4 with: + distribution: temurin java-version: 17 - cache: 'sbt' + cache: sbt + - uses: sbt/setup-sbt@v1 + - uses: coursier/cache-action@v6 - name: Check Style run: sbt check test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup JDK - uses: actions/setup-java@v1 + uses: actions/setup-java@v4 with: + distribution: temurin java-version: 17 - cache: 'sbt' + cache: sbt + - uses: sbt/setup-sbt@v1 + - uses: coursier/cache-action@v6 - name: Test run: sbt test verification: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up JDK 17 - uses: actions/setup-java@v1 + uses: actions/setup-java@v4 with: + distribution: temurin java-version: 17 - cache: 'sbt' + cache: sbt + - uses: sbt/setup-sbt@v1 + - uses: coursier/cache-action@v6 - name: Check Binary Compatibility run: sbt runPluginVerifier diff --git a/build.sbt b/build.sbt index 79f2d3c..8412947 100644 --- a/build.sbt +++ b/build.sbt @@ -11,8 +11,8 @@ lazy val ktVersion = "1.9.10" // https://youtrack.jetbrains.com/articles/IDEA-A-2100661679/IntelliJ-IDEA-2023.3-Latest-Builds // NOTE: Latest-Builds 233 -lazy val intellijVersion = "242.21829.142" -lazy val pluginVersion = s"0.5.0-$intellijVersion" +lazy val intellijVersion = "243.24978.46" +lazy val pluginVersion = s"0.6.0-$intellijVersion" ThisBuild / version := pluginVersion diff --git a/src/main/kotlin/bitlap/sbt/analyzer/jbexternal/DataProvider.kt b/src/main/kotlin/bitlap/sbt/analyzer/jbexternal/DataProvider.kt deleted file mode 100644 index 1d01f1b..0000000 --- a/src/main/kotlin/bitlap/sbt/analyzer/jbexternal/DataProvider.kt +++ /dev/null @@ -1,14 +0,0 @@ -package bitlap.sbt.analyzer.jbexternal - -import com.intellij.openapi.actionSystem.DataProvider -import org.jetbrains.annotations.NonNls - -fun interface DataProvider : DataProvider { - - override fun getData(@NonNls dataId: String): Any? = getAnalyzerData(dataId) - - /** - * In order to meet the IJ standard, we do not directly use the getData function. - */ - fun getAnalyzerData(@NonNls dataId: String): Any? -} diff --git a/src/main/kotlin/bitlap/sbt/analyzer/jbexternal/DependencyAnalyzerViewImpl.kt b/src/main/kotlin/bitlap/sbt/analyzer/jbexternal/DependencyAnalyzerViewImpl.kt index 6ca0a59..85cbad5 100644 --- a/src/main/kotlin/bitlap/sbt/analyzer/jbexternal/DependencyAnalyzerViewImpl.kt +++ b/src/main/kotlin/bitlap/sbt/analyzer/jbexternal/DependencyAnalyzerViewImpl.kt @@ -14,13 +14,13 @@ import bitlap.sbt.analyzer.jbexternal.util.getDisplayText import com.intellij.icons.AllIcons import com.intellij.openapi.Disposable import com.intellij.openapi.actionSystem.CommonDataKeys +import com.intellij.openapi.actionSystem.DataSink import com.intellij.openapi.actionSystem.PlatformCoreDataKeys import com.intellij.openapi.application.invokeLater import com.intellij.openapi.application.runInEdt import com.intellij.openapi.module.Module import com.intellij.openapi.diagnostic.logger import com.intellij.openapi.externalSystem.autoimport.ExternalSystemProjectNotificationAware.Companion.isNotificationVisibleProperty -import com.intellij.openapi.externalSystem.autoimport.ProjectRefreshAction import com.intellij.openapi.externalSystem.dependency.analyzer.DependencyAnalyzerDependency import com.intellij.openapi.externalSystem.dependency.analyzer.DependencyAnalyzerExtension import com.intellij.openapi.externalSystem.dependency.analyzer.DependencyAnalyzerProject @@ -53,7 +53,7 @@ import com.intellij.openapi.externalSystem.dependency.analyzer.DependencyAnalyze */ class DependencyAnalyzerViewImpl( private val project: Project, private val systemId: ProjectSystemId, private val parentDisposable: Disposable -) : DependencyAnalyzerView , DataProvider { +) : DependencyAnalyzerView { private val iconsProvider = ExternalSystemIconProvider.getExtension(systemId) private val contributor = @@ -142,22 +142,19 @@ class DependencyAnalyzerViewImpl( return externalProjects.find(predicate) } - override fun getAnalyzerData(dataId: String): Any? { - return when (dataId) { - DependencyAnalyzerView.VIEW.name -> this - CommonDataKeys.PROJECT.name -> project - ExternalSystemDataKeys.EXTERNAL_SYSTEM_ID.name -> systemId - PlatformCoreDataKeys.MODULE.name -> externalProject?.module - else -> null - } - } - private fun updateViewModel() { executeLoadingTaskOnEdt { updateExternalProjectsModel() } } + override fun uiDataSnapshot(sink: DataSink) { + sink[DependencyAnalyzerView.VIEW] = this + sink[CommonDataKeys.PROJECT] = project + sink[ExternalSystemDataKeys.EXTERNAL_SYSTEM_ID] = systemId + sink[PlatformCoreDataKeys.MODULE] = externalProject?.module + } + private fun Iterable.filterDependencies(): List { val dependencyDataFilter = dependencyDataFilter val dependencyScopeFilter = dependencyScopeFilter.filter { it.isSelected }.map { it.scope } @@ -347,19 +344,27 @@ class DependencyAnalyzerViewImpl( }.asActionButton(ACTION_PLACE).bindEnabled(!dependencyLoadingProperty) val reloadNotificationProperty = isNotificationVisibleProperty(project, systemId) val projectReloadSeparator = separator().bindVisible(reloadNotificationProperty) - val projectReloadAction = action { ProjectRefreshAction.Manager.refreshProject(project) }.apply { + val projectReloadAction = action { ProjectUtil.refreshProject(project) }.apply { templatePresentation.icon = AllIcons.Actions.BuildLoadChanges }.asActionButton(ACTION_PLACE).bindVisible(reloadNotificationProperty) val dependencyTitle = label(ExternalSystemBundle.message("external.system.dependency.analyzer.resolved.title")) - val dependencyList = DependencyList( - dependencyListModel, showDependencyGroupIdProperty, showDependencySizeProperty, this - ).bindEmptyText(dependencyEmptyTextProperty).bindDependency(dependencyProperty) - .bindEnabled(!dependencyLoadingProperty) - val dependencyTree = DependencyTree( - dependencyTreeModel, showDependencyGroupIdProperty, showDependencySizeProperty, this - ).bindEmptyText(dependencyEmptyTextProperty).bindDependency(dependencyProperty) - .bindEnabled(!dependencyLoadingProperty) + val dependencyList = + object : DependencyList(dependencyListModel, showDependencyGroupIdProperty, showDependencySizeProperty) { + override fun uiDataSnapshot(sink: DataSink) { + super.uiDataSnapshot(sink) + DataSink.uiDataSnapshot(sink, this@DependencyAnalyzerViewImpl) + } + }.bindEmptyText(dependencyEmptyTextProperty).bindDependency(dependencyProperty) + .bindEnabled(!dependencyLoadingProperty) + val dependencyTree = + object : DependencyTree(dependencyTreeModel, showDependencyGroupIdProperty, showDependencySizeProperty) { + override fun uiDataSnapshot(sink: DataSink) { + super.uiDataSnapshot(sink) + DataSink.uiDataSnapshot(sink, this@DependencyAnalyzerViewImpl) + } + }.bindEmptyText(dependencyEmptyTextProperty).bindDependency(dependencyProperty) + .bindEnabled(!dependencyLoadingProperty) val dependencyPanel = cardPanel { ScrollPaneFactory.createScrollPane(if (it) dependencyTree else dependencyList, true) }.bind(showDependencyTreeProperty) @@ -378,9 +383,13 @@ class DependencyAnalyzerViewImpl( .bindEnabled(showDependencyTreeProperty and !dependencyLoadingProperty) val usagesTitle = label(usagesTitleProperty) - val usagesTree = UsagesTree( - usagesTreeModel, showDependencyGroupIdProperty, showDependencySizeProperty, this - ).apply { emptyText.text = "" }.bindEnabled(!dependencyLoadingProperty) + val usagesTree = + object : UsagesTree(usagesTreeModel, showDependencyGroupIdProperty, showDependencySizeProperty) { + override fun uiDataSnapshot(sink: DataSink) { + super.uiDataSnapshot(sink) + DataSink.uiDataSnapshot(sink, this@DependencyAnalyzerViewImpl) + } + }.apply { emptyText.text = "" }.bindEnabled(!dependencyLoadingProperty) val expandUsagesTreeButton = expandTreeAction(usagesTree).asActionButton(ACTION_PLACE).bindEnabled(!dependencyLoadingProperty) val collapseUsagesTreeButton = diff --git a/src/main/kotlin/bitlap/sbt/analyzer/jbexternal/util/DependencyUiUtil.kt b/src/main/kotlin/bitlap/sbt/analyzer/jbexternal/util/DependencyUiUtil.kt index 8753796..4369d26 100644 --- a/src/main/kotlin/bitlap/sbt/analyzer/jbexternal/util/DependencyUiUtil.kt +++ b/src/main/kotlin/bitlap/sbt/analyzer/jbexternal/util/DependencyUiUtil.kt @@ -8,9 +8,10 @@ import javax.swing.tree.DefaultMutableTreeNode import javax.swing.tree.TreeModel import bitlap.sbt.analyzer.jbexternal.SbtDAArtifact -import bitlap.sbt.analyzer.jbexternal.DataProvider import com.intellij.icons.AllIcons +import com.intellij.openapi.actionSystem.DataSink +import com.intellij.openapi.actionSystem.UiDataProvider import com.intellij.openapi.application.invokeLater import com.intellij.openapi.externalSystem.dependency.analyzer.DependencyAnalyzerView import com.intellij.openapi.externalSystem.util.ExternalSystemBundle @@ -86,8 +87,8 @@ private fun SimpleColoredComponent.customizeCellRenderer( } internal abstract class AbstractDependencyList( - model: ListModel, private val dataProvider: DataProvider -) : JBList(model), DataProvider { + model: ListModel +) : JBList(model), UiDataProvider { private val dependencyProperty = AtomicProperty(null) private val dependencyGroupProperty = AtomicProperty(null) @@ -96,12 +97,9 @@ internal abstract class AbstractDependencyList( dependencyProperty.bind(property) } - override fun getAnalyzerData(dataId: String): Any? { - return when (dataId) { - DependencyAnalyzerView.DEPENDENCY.name -> dependencyProperty.get() - DependencyAnalyzerView.DEPENDENCIES.name -> dependencyGroupProperty.get() - else -> dataProvider.getAnalyzerData(dataId) - } + override fun uiDataSnapshot(sink: DataSink) { + sink[DependencyAnalyzerView.DEPENDENCY] = dependencyProperty.get() + sink[DependencyAnalyzerView.DEPENDENCIES] = dependencyGroupProperty.get()?.variances } init { @@ -113,8 +111,8 @@ internal abstract class AbstractDependencyList( } internal abstract class AbstractDependencyTree( - model: TreeModel, private val dataProvider: DataProvider -) : SimpleTree(model), DataProvider { + model: TreeModel +) : SimpleTree(model), UiDataProvider { private val dependencyProperty = AtomicProperty(null) private val dependencyGroupProperty = AtomicProperty(null) @@ -123,12 +121,9 @@ internal abstract class AbstractDependencyTree( dependencyProperty.bind(property) } - override fun getAnalyzerData(dataId: String): Any? { - return when (dataId) { - DependencyAnalyzerView.DEPENDENCY.name -> dependencyProperty.get() - DependencyAnalyzerView.DEPENDENCIES.name -> dependencyGroupProperty.get() - else -> dataProvider.getAnalyzerData(dataId) - } + override fun uiDataSnapshot(sink: DataSink) { + sink[DependencyAnalyzerView.DEPENDENCY] = dependencyProperty.get() + sink[DependencyAnalyzerView.DEPENDENCIES] = dependencyGroupProperty.get()?.variances } init { @@ -140,12 +135,11 @@ internal abstract class AbstractDependencyTree( } } -internal class DependencyList( +internal open class DependencyList( model: ListModel, showGroupIdProperty: ObservableProperty, showSizeProperty: ObservableProperty, - dataProvider: DataProvider -) : AbstractDependencyList(model, dataProvider) { +) : AbstractDependencyList(model) { init { ListUiUtil.Selection.installSelectionOnRightClick(this) PopupHandler.installPopupMenu( @@ -155,12 +149,11 @@ internal class DependencyList( } } -internal class DependencyTree( +internal open class DependencyTree( model: TreeModel, showGroupIdProperty: ObservableProperty, showSizeProperty: ObservableProperty, - dataProvider: DataProvider -) : AbstractDependencyTree(model, dataProvider) { +) : AbstractDependencyTree(model) { init { PopupHandler.installPopupMenu( this, "ExternalSystem.DependencyAnalyzer.DependencyTreeGroup", DependencyAnalyzerView.ACTION_PLACE @@ -169,12 +162,11 @@ internal class DependencyTree( } } -internal class UsagesTree( +internal open class UsagesTree( model: TreeModel, showGroupIdProperty: ObservableProperty, showSizeProperty: ObservableProperty, - dataProvider: DataProvider -) : AbstractDependencyTree(model, dataProvider) { +) : AbstractDependencyTree(model) { init { PopupHandler.installPopupMenu( this, "ExternalSystem.DependencyAnalyzer.UsagesTreeGroup", DependencyAnalyzerView.ACTION_PLACE diff --git a/src/main/kotlin/bitlap/sbt/analyzer/jbexternal/util/ProjectUtil.kt b/src/main/kotlin/bitlap/sbt/analyzer/jbexternal/util/ProjectUtil.kt new file mode 100644 index 0000000..20e6c10 --- /dev/null +++ b/src/main/kotlin/bitlap/sbt/analyzer/jbexternal/util/ProjectUtil.kt @@ -0,0 +1,18 @@ +package bitlap.sbt.analyzer.jbexternal.util + +import com.intellij.openapi.externalSystem.autoimport.ExternalSystemProjectNotificationAware +import com.intellij.openapi.externalSystem.autoimport.ExternalSystemProjectTracker +import com.intellij.openapi.externalSystem.service.project.trusted.ExternalSystemTrustedProjectDialog +import com.intellij.openapi.project.Project + +@Suppress("DEPRECATION") +object ProjectUtil { + fun refreshProject(project: Project) { + val projectNotificationAware = ExternalSystemProjectNotificationAware.getInstance(project) + val systemIds = projectNotificationAware.getSystemIds() + if (ExternalSystemTrustedProjectDialog.confirmLoadingUntrustedProject(project, systemIds)) { + val projectTracker = ExternalSystemProjectTracker.getInstance(project) + projectTracker.scheduleProjectRefresh() + } + } +} \ No newline at end of file diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 1f8966c..5475830 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -2,12 +2,12 @@ org.bitlap.sbtDependencyAnalyzer Sbt Dependency Analyzer - 0.5.0-242.21829.142 + 0.6.0-243.24978.46 Bitlap - + com.intellij.modules.platform com.intellij.modules.lang @@ -136,6 +136,12 @@ 0.6.0-243.24978.46 +
    +
  • Upgrade Dependency.
  • +
+ +

0.5.0-242.21829.142

  • Improve code and API compatibility.
  • diff --git a/src/main/resources/messages/SbtDependencyAnalyzerBundle.properties b/src/main/resources/messages/SbtDependencyAnalyzerBundle.properties index 7c17f65..c68317e 100644 --- a/src/main/resources/messages/SbtDependencyAnalyzerBundle.properties +++ b/src/main/resources/messages/SbtDependencyAnalyzerBundle.properties @@ -12,6 +12,7 @@ analyzer.notification.addSdap.text=The "{0}" has been added or updated, \ and it has also been ignored by the ".git/info/exclude" file in the git environment, \ please wait a moment, go to see more. analyzer.notification.setting.changed.title=Sbt Dependency Analyzer settings have been changed +analyzer.notification.reimport.title=Sbt Dependency Analyzer is refreshing the project analyzer.notification.updated.failure.title=Failed to load! analyzer.notification.updated.failure.text=Open in browser↗ analyzer.notification.updated.title={0} plugin updated to v{1} diff --git a/src/main/resources/messages/SbtDependencyAnalyzerBundle_zh.properties b/src/main/resources/messages/SbtDependencyAnalyzerBundle_zh.properties index 4bebad2..3caf1aa 100644 --- a/src/main/resources/messages/SbtDependencyAnalyzerBundle_zh.properties +++ b/src/main/resources/messages/SbtDependencyAnalyzerBundle_zh.properties @@ -12,6 +12,7 @@ analyzer.notification.addSdap.text=已添加或更新文件 “{0}”,\ 并且在git环境中也已经被“.git/info/exclude”文件忽略了,\ 请稍等片刻,前往查看更多 analyzer.notification.setting.changed.title=Sbt Dependency Analyzer 配置已被更改 +analyzer.notification.reimport.title=Sbt Dependency Analyzer 正在刷新项目 analyzer.notification.updated.failure.title=加载失败! analyzer.notification.updated.failure.text=在浏览器中打开↗ analyzer.notification.updated.title={0} 插件已更新为 v{1} diff --git a/src/main/scala/bitlap/sbt/analyzer/SbtDependencyAnalyzerContributor.scala b/src/main/scala/bitlap/sbt/analyzer/SbtDependencyAnalyzerContributor.scala index d948d08..269e011 100644 --- a/src/main/scala/bitlap/sbt/analyzer/SbtDependencyAnalyzerContributor.scala +++ b/src/main/scala/bitlap/sbt/analyzer/SbtDependencyAnalyzerContributor.scala @@ -280,32 +280,37 @@ final class SbtDependencyAnalyzerContributor(project: Project) extends Dependenc } -object SbtDependencyAnalyzerContributor extends SettingsState.SettingsChangeListener: - - final val isAvailable = new AtomicBoolean(true) +object SbtDependencyAnalyzerContributor + extends SettingsState.SettingsChangeListener, + SbtReimportProject.ReimportProjectListener: + import com.intellij.openapi.observable.properties.AtomicProperty + private final val dependencyIsAvailable = new AtomicProperty[Boolean](true) // if data change - override def onAnalyzerConfigurationChanged(project: Project, settingsState: SettingsState): Unit = { - isAvailable.set(false) - SbtUtils.refreshProject(project) - isAvailable.set(true) + override def onConfigurationChanged(project: Project, settingsState: SettingsState): Unit = { + SbtReimportProject.ReimportProjectPublisher.onReimportProject(project) + } + + override def onReimportProject(project: Project): Unit = { + SbtUtils.forceRefreshProject(project) } ApplicationManager.getApplication.getMessageBus.connect().subscribe(SettingsState._Topic, this) + ApplicationManager.getApplication.getMessageBus.connect().subscribe(SbtReimportProject._Topic, this) - private final val isNotifying = new AtomicBoolean(false) + private final val hasNotified = new AtomicBoolean(false) private def isValidFile(project: Project, file: String): Boolean = { - if (isAvailable.get()) { + if (dependencyIsAvailable.get()) { val lastModified = VfsUtil.findFile(Path.of(file), true).getTimeStamp val upToDate = System.currentTimeMillis() <= lastModified + SettingsState.getSettings(project).fileCacheTimeout * 1000 if (!upToDate) { - isAvailable.set(false) + dependencyIsAvailable.set(false) } - isAvailable.get() + dependencyIsAvailable.get() } else { - isAvailable.get() + dependencyIsAvailable.get() } } @@ -370,10 +375,10 @@ object SbtDependencyAnalyzerContributor extends SettingsState.SettingsChangeList if (DependencyUtils.canIgnoreModule(module)) return Collections.emptyList() - if (isNotifying.get() && SbtUtils.untilProjectReady(project)) { + if (hasNotified.get() && SbtUtils.untilProjectReady(project)) { // must reload project to enable it SbtShellOutputAnalysisTask.reloadTask.executeCommand(project) - isNotifying.compareAndSet(true, false) + hasNotified.compareAndSet(true, false) } // if the analysis files already exist (.dot), use it directly. @@ -402,7 +407,7 @@ object SbtDependencyAnalyzerContributor extends SettingsState.SettingsChangeList createRootScopeNode(scope, project) ) } else { - isAvailable.set(true) + dependencyIsAvailable.set(true) SbtShellDependencyAnalysisTask.dependencyDotTask.executeCommand( project, moduleData, @@ -433,7 +438,7 @@ object SbtDependencyAnalyzerContributor extends SettingsState.SettingsChangeList } } catch { case _: AnalyzerCommandNotFoundException => - if (isNotifying.compareAndSet(false, true)) { + if (hasNotified.compareAndSet(false, true)) { Notifications.notifyAndCreateSdapFile(project) } break() diff --git a/src/main/scala/bitlap/sbt/analyzer/SbtDependencyAnalyzerPanel.java b/src/main/scala/bitlap/sbt/analyzer/SbtDependencyAnalyzerPanel.java index c43c1ca..c9afa3a 100644 --- a/src/main/scala/bitlap/sbt/analyzer/SbtDependencyAnalyzerPanel.java +++ b/src/main/scala/bitlap/sbt/analyzer/SbtDependencyAnalyzerPanel.java @@ -60,7 +60,7 @@ void apply() { } if (changed) { Notifications$.MODULE$.notifySettingsChanged(project); - SettingsState.SettingsChangePublisher().onAnalyzerConfigurationChanged(this.project, settings); + SettingsState.SettingsChangePublisher().onConfigurationChanged(this.project, settings); } } diff --git a/src/main/scala/bitlap/sbt/analyzer/SettingsState.scala b/src/main/scala/bitlap/sbt/analyzer/SettingsState.scala index 8c21234..9911a0a 100644 --- a/src/main/scala/bitlap/sbt/analyzer/SettingsState.scala +++ b/src/main/scala/bitlap/sbt/analyzer/SettingsState.scala @@ -50,7 +50,7 @@ object SettingsState { trait SettingsChangeListener: - def onAnalyzerConfigurationChanged(project: Project, settingsState: SettingsState): Unit + def onConfigurationChanged(project: Project, settingsState: SettingsState): Unit end SettingsChangeListener diff --git a/src/main/scala/bitlap/sbt/analyzer/action/SbtDependencyAnalyzerAction.scala b/src/main/scala/bitlap/sbt/analyzer/action/SbtDependencyAnalyzerAction.scala index 3ec0ef2..9e04dc3 100644 --- a/src/main/scala/bitlap/sbt/analyzer/action/SbtDependencyAnalyzerAction.scala +++ b/src/main/scala/bitlap/sbt/analyzer/action/SbtDependencyAnalyzerAction.scala @@ -97,7 +97,7 @@ final class ProjectViewDependencyAnalyzerAction extends AbstractSbtDependencyAna override def isEnabledAndVisible(e: AnActionEvent): Boolean = { super.isEnabledAndVisible(e) - && (e.getData(LangDataKeys.MODULE_CONTEXT_ARRAY) != null || !ActionPlaces.isPopupPlace(e.getPlace)) + && (e.getData(LangDataKeys.MODULE_CONTEXT_ARRAY) != null || !e.isFromContextMenu) } end ProjectViewDependencyAnalyzerAction diff --git a/src/main/scala/bitlap/sbt/analyzer/action/SbtDependencyAnalyzerExcludeAction.scala b/src/main/scala/bitlap/sbt/analyzer/action/SbtDependencyAnalyzerExcludeAction.scala index 8f17c38..6579bbe 100644 --- a/src/main/scala/bitlap/sbt/analyzer/action/SbtDependencyAnalyzerExcludeAction.scala +++ b/src/main/scala/bitlap/sbt/analyzer/action/SbtDependencyAnalyzerExcludeAction.scala @@ -20,34 +20,36 @@ final class SbtDependencyAnalyzerExcludeAction extends BaseRefreshDependenciesAc override def actionPerformed(e: AnActionEvent): Unit = { Option(SbtDependencyAnalyzerActionUtil.getModifiableDependency(e)).foreach { modifiableDependency => val parent = getUnifiedCoordinates(modifiableDependency.parentDependency) - val unifiedDependency = - new UnifiedDependency(parent, modifiableDependency.parentDependency.getParent.getScope.getTitle) - val coordinates: UnifiedCoordinates = modifiableDependency.coordinates - if (coordinates == parent) { - // remove declared dependency - try { - SbtDependencyModifier.removeDependency(modifiableDependency.module, unifiedDependency) - Notifications.notifyDependencyChanged( - modifiableDependency.module.getProject, - coordinates.getDisplayName, - true - ) - } catch { - case e: AnalyzerCommandNotFoundException => - LOG.error(s"Cannot remove declared dependency: ${coordinates.getDisplayName}", e) - case ignore: Exception => throw ignore - } - - } else { - // add exclude coordinates - val ret = - SbtDependencyModifier.addExcludeToDependency(modifiableDependency.module, unifiedDependency, coordinates) - if (ret) { - Notifications.notifyDependencyChanged( - modifiableDependency.module.getProject, - coordinates.getDisplayName, - false - ) + if (modifiableDependency.parentDependency.getParent != null) { + val unifiedDependency = + new UnifiedDependency(parent, modifiableDependency.parentDependency.getParent.getScope.getTitle) + val coordinates: UnifiedCoordinates = modifiableDependency.coordinates + if (coordinates == parent) { + try { + // remove declared dependency + SbtDependencyModifier.removeDependency(modifiableDependency.module, unifiedDependency) + Notifications.notifyDependencyChanged( + modifiableDependency.module.getProject, + coordinates.getDisplayName, + true + ) + } catch { + case e: AnalyzerCommandNotFoundException => + LOG.error(s"Cannot remove declared dependency: ${coordinates.getDisplayName}", e) + case ignore: Exception => throw ignore + } + + } else { + // add exclude coordinates + val ret = + SbtDependencyModifier.addExcludeToDependency(modifiableDependency.module, unifiedDependency, coordinates) + if (ret) { + Notifications.notifyDependencyChanged( + modifiableDependency.module.getProject, + coordinates.getDisplayName, + false + ) + } } } } diff --git a/src/main/scala/bitlap/sbt/analyzer/action/SbtDependencyAnalyzerGoToAction.scala b/src/main/scala/bitlap/sbt/analyzer/action/SbtDependencyAnalyzerGoToAction.scala index c75ab2c..86d2945 100644 --- a/src/main/scala/bitlap/sbt/analyzer/action/SbtDependencyAnalyzerGoToAction.scala +++ b/src/main/scala/bitlap/sbt/analyzer/action/SbtDependencyAnalyzerGoToAction.scala @@ -24,15 +24,20 @@ final class SbtDependencyAnalyzerGoToAction extends DependencyAnalyzerGoToAction private val LOG = Logger.getInstance(classOf[SbtDependencyAnalyzerGoToAction]) + // PsiNavigationSupport override def getNavigatable(e: AnActionEvent): Navigatable = Option(SbtDependencyAnalyzerActionUtil.getModifiableDependency(e)) .flatMap(_.declaredDependency) .flatMap { dependency => Try { - val data = dependency.getDataContext.getData(CommonDataKeys.PSI_ELEMENT.getName) + // warn: this will always yield false since type com.intellij.psi.PsiElement and class Tuple3 are unrelated + // add asInstanceOf to fix it + val data = dependency.getDataContext.getData(CommonDataKeys.PSI_ELEMENT).asInstanceOf[AnyRef] data match - case t: (_, _, _) if t._1.isInstanceOf[PsiElement] => - Some(t._1.asInstanceOf[PsiElement]) + case t: (_, _, _) => + t._1 match + case element: PsiElement => Some(element) + case _ => None case _ => None }.getOrElse { LOG.error(s"Cannot get 'PSI_ELEMENT' as 'PsiElement' for ${dependency.getCoordinates}") diff --git a/src/main/scala/bitlap/sbt/analyzer/action/SbtRefreshDependenciesAction.scala b/src/main/scala/bitlap/sbt/analyzer/action/SbtRefreshDependenciesAction.scala index 45e6f0e..ae53d0c 100644 --- a/src/main/scala/bitlap/sbt/analyzer/action/SbtRefreshDependenciesAction.scala +++ b/src/main/scala/bitlap/sbt/analyzer/action/SbtRefreshDependenciesAction.scala @@ -3,7 +3,7 @@ package sbt package analyzer package action -import bitlap.sbt.analyzer.util.SbtUtils +import bitlap.sbt.analyzer.util.SbtReimportProject import com.intellij.openapi.actionSystem.AnActionEvent @@ -15,9 +15,7 @@ final class SbtRefreshDependenciesAction extends BaseRefreshDependenciesAction: SbtDependencyAnalyzerBundle.message("analyzer.refresh.dependencies.description") override def actionPerformed(e: AnActionEvent): Unit = { - SbtDependencyAnalyzerContributor.isAvailable.set(false) - SbtUtils.refreshProject(e.getProject) - SbtDependencyAnalyzerContributor.isAvailable.set(true) + SbtReimportProject.ReimportProjectPublisher.onReimportProject(e.getProject) } end SbtRefreshDependenciesAction diff --git a/src/main/scala/bitlap/sbt/analyzer/action/SbtRefreshSnapshotDependenciesAction.scala b/src/main/scala/bitlap/sbt/analyzer/action/SbtRefreshSnapshotDependenciesAction.scala index 759a21d..abec9e2 100644 --- a/src/main/scala/bitlap/sbt/analyzer/action/SbtRefreshSnapshotDependenciesAction.scala +++ b/src/main/scala/bitlap/sbt/analyzer/action/SbtRefreshSnapshotDependenciesAction.scala @@ -2,6 +2,7 @@ package bitlap.sbt.analyzer.action import bitlap.sbt.analyzer.* import bitlap.sbt.analyzer.task.* +import bitlap.sbt.analyzer.util.SbtReimportProject import bitlap.sbt.analyzer.util.SbtUtils import com.intellij.openapi.actionSystem.AnActionEvent @@ -15,10 +16,8 @@ final class SbtRefreshSnapshotDependenciesAction extends BaseRefreshDependencies SbtDependencyAnalyzerBundle.message("analyzer.refresh.snapshot.dependencies.description") override def actionPerformed(e: AnActionEvent): Unit = { - SbtDependencyAnalyzerContributor.isAvailable.set(false) SbtShellOutputAnalysisTask.refreshSnapshotsTask.executeCommand(e.getProject) - SbtUtils.refreshProject(e.getProject) - SbtDependencyAnalyzerContributor.isAvailable.set(true) + SbtReimportProject.ReimportProjectPublisher.onReimportProject(e.getProject) } end SbtRefreshSnapshotDependenciesAction diff --git a/src/main/scala/bitlap/sbt/analyzer/parser/DotUtil.scala b/src/main/scala/bitlap/sbt/analyzer/parser/DotUtil.scala index f4e0887..6e13304 100644 --- a/src/main/scala/bitlap/sbt/analyzer/parser/DotUtil.scala +++ b/src/main/scala/bitlap/sbt/analyzer/parser/DotUtil.scala @@ -13,6 +13,7 @@ import scala.util.control.Breaks.breakable import org.jetbrains.plugins.scala.extensions.inReadAction import org.jetbrains.plugins.scala.project.VirtualFileExt +import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.vfs.VfsUtil import analyzer.util.Notifications @@ -23,6 +24,8 @@ import model.ModuleContext object DotUtil { + private val LOG = Logger.getInstance(getClass) + private lazy val parser = (new Parser).forEngine(ValidatorEngine.DOT).notValidating() private def parseAsGraphTestOnly(file: String): MutableGraph = { @@ -61,6 +64,7 @@ object DotUtil { } } catch { case ignore: Throwable => + LOG.error(ignore) Notifications.notifyParseFileError(file, "The file parsing failed") null } diff --git a/src/main/scala/bitlap/sbt/analyzer/task/RefreshSnapshotsTask.scala b/src/main/scala/bitlap/sbt/analyzer/task/RefreshSnapshotsTask.scala index b957f05..a477fb3 100644 --- a/src/main/scala/bitlap/sbt/analyzer/task/RefreshSnapshotsTask.scala +++ b/src/main/scala/bitlap/sbt/analyzer/task/RefreshSnapshotsTask.scala @@ -20,17 +20,17 @@ final class RefreshSnapshotsTask extends SbtShellOutputAnalysisTask[Unit]: getCommandOutputLines( project, """ - |set update / skip := false + |set update / skip := false; |set csrConfiguration := csrConfiguration.value.withTtl(Option(scala.concurrent.duration.DurationInt(0).seconds)); - |update + |update; |""".stripMargin ) } else { getCommandOutputLines( project, """ - |set update / skip := false - |update + |set update / skip := false; + |update; |""".stripMargin ) } diff --git a/src/main/scala/bitlap/sbt/analyzer/util/Notifications.scala b/src/main/scala/bitlap/sbt/analyzer/util/Notifications.scala index 4921708..c145ba7 100644 --- a/src/main/scala/bitlap/sbt/analyzer/util/Notifications.scala +++ b/src/main/scala/bitlap/sbt/analyzer/util/Notifications.scala @@ -18,6 +18,7 @@ import com.intellij.icons.AllIcons import com.intellij.ide.BrowserUtil import com.intellij.notification.* import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.editor.Document import com.intellij.openapi.fileEditor.* import com.intellij.openapi.project.{ DumbAwareAction, Project } @@ -61,7 +62,7 @@ object Notifications { def notifySettingsChanged(project: Project): Unit = { val notification = NotificationGroup .createNotification( - SbtDependencyAnalyzerBundle.message("analyzer.notification.dependency.excluded.title"), + SbtDependencyAnalyzerBundle.message("analyzer.notification.setting.changed.title"), NotificationType.INFORMATION ) .setIcon(SbtDependencyAnalyzerIcons.ICON) @@ -145,7 +146,7 @@ object Notifications { // SbtUtils.untilProjectReady(project) } - invokeAndWait(SbtUtils.refreshProject(project)) + invokeAndWait(SbtUtils.forceRefreshProject(project)) // 2. add notification NotificationGroup .createNotification( diff --git a/src/main/scala/bitlap/sbt/analyzer/util/SbtReimportProject.scala b/src/main/scala/bitlap/sbt/analyzer/util/SbtReimportProject.scala new file mode 100644 index 0000000..1a0c18f --- /dev/null +++ b/src/main/scala/bitlap/sbt/analyzer/util/SbtReimportProject.scala @@ -0,0 +1,21 @@ +package bitlap.sbt.analyzer.util + +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.project.Project +import com.intellij.util.messages.Topic + +object SbtReimportProject { + + val _Topic: Topic[ReimportProjectListener] = + Topic.create("SbtDependencyAnalyzerReimportProject", classOf[ReimportProjectListener]) + + trait ReimportProjectListener: + + def onReimportProject(project: Project): Unit + + end ReimportProjectListener + + val ReimportProjectPublisher: ReimportProjectListener = + ApplicationManager.getApplication.getMessageBus.syncPublisher(_Topic) + +} diff --git a/src/main/scala/bitlap/sbt/analyzer/util/SbtUtils.scala b/src/main/scala/bitlap/sbt/analyzer/util/SbtUtils.scala index a4f7bc9..9daba14 100644 --- a/src/main/scala/bitlap/sbt/analyzer/util/SbtUtils.scala +++ b/src/main/scala/bitlap/sbt/analyzer/util/SbtUtils.scala @@ -15,10 +15,15 @@ import org.jetbrains.sbt.settings.SbtSettings import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.externalSystem.autoimport.{ + ExternalSystemProjectNotificationAware, + ExternalSystemProjectTracker +} import com.intellij.openapi.externalSystem.importing.ImportSpecBuilder import com.intellij.openapi.externalSystem.model.project.dependencies.DependencyNode import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskType import com.intellij.openapi.externalSystem.service.internal.ExternalSystemProcessingManager +import com.intellij.openapi.externalSystem.service.project.trusted.ExternalSystemTrustedProjectDialog import com.intellij.openapi.externalSystem.util.{ ExternalSystemApiUtil, ExternalSystemUtil } import com.intellij.openapi.module.ModuleManager import com.intellij.openapi.project.* @@ -50,7 +55,7 @@ object SbtUtils { def getSbtProject(project: Project): SbtSettings = SSbtUtil.sbtSettings(project) - def refreshProject(project: Project): Unit = { + def forceRefreshProject(project: Project): Unit = { ExternalSystemUtil.refreshProjects( new ImportSpecBuilder(project, SbtProjectSystem.Id) .dontNavigateToError() @@ -60,14 +65,18 @@ object SbtUtils { } def untilProjectReady(project: Project): Boolean = { - while (!SbtUtils.isProjectReady(project)) { - waitInterval(100.millis) + val timeout = 10.minutes + val interval = 100.millis + val startTime = System.currentTimeMillis() + val endTime = startTime + timeout.toMillis + while (System.currentTimeMillis() < endTime && !SbtUtils.isProjectReady(project)) { + waitInterval(interval) } true } // TODO - def isProjectReady(project: Project): Boolean = { + private def isProjectReady(project: Project): Boolean = { SbtUtils .getExternalProjectPath(project) .map { externalProjectPath =>