-
Notifications
You must be signed in to change notification settings - Fork 513
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Compact middle packages in project tree
- Loading branch information
1 parent
1f68367
commit ba3cc81
Showing
3 changed files
with
179 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
148 changes: 148 additions & 0 deletions
148
...ea-plugin/src/main/kotlin/app/cash/sqldelight/intellij/SqlDelightTreeStructureProvider.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
package app.cash.sqldelight.intellij | ||
|
||
import app.cash.sqldelight.core.SqlDelightFileIndex | ||
import com.intellij.icons.AllIcons | ||
import com.intellij.ide.DeleteProvider | ||
import com.intellij.ide.projectView.PresentationData | ||
import com.intellij.ide.projectView.TreeStructureProvider | ||
import com.intellij.ide.projectView.ViewSettings | ||
import com.intellij.ide.projectView.impl.ProjectRootsUtil | ||
import com.intellij.ide.projectView.impl.ProjectTreeStructure | ||
import com.intellij.ide.projectView.impl.nodes.ProjectViewDirectoryHelper | ||
import com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode | ||
import com.intellij.ide.util.DeleteHandler | ||
import com.intellij.ide.util.treeView.AbstractTreeNode | ||
import com.intellij.openapi.actionSystem.CommonDataKeys | ||
import com.intellij.openapi.actionSystem.DataContext | ||
import com.intellij.openapi.actionSystem.PlatformDataKeys | ||
import com.intellij.openapi.module.ModuleUtil | ||
import com.intellij.openapi.project.Project | ||
import com.intellij.openapi.vfs.VfsUtilCore | ||
import com.intellij.openapi.vfs.VirtualFile | ||
import com.intellij.openapi.vfs.VirtualFileFilter | ||
import com.intellij.psi.PsiDirectory | ||
import com.intellij.psi.PsiElement | ||
import com.intellij.psi.PsiManager | ||
import org.jetbrains.kotlin.konan.file.File | ||
|
||
internal class SqlDelightTreeStructureProvider( | ||
private val project: Project, | ||
) : TreeStructureProvider { | ||
override fun modify( | ||
parent: AbstractTreeNode<*>, | ||
children: MutableCollection<AbstractTreeNode<*>>, | ||
settings: ViewSettings?, | ||
): MutableCollection<AbstractTreeNode<*>> { | ||
if (settings !is ProjectTreeStructure || !settings.isHideEmptyMiddlePackages) { | ||
return children | ||
} | ||
if (parent !is PsiDirectoryNode || ProjectRootsUtil.isSourceRoot(parent.value)) { | ||
return children | ||
} | ||
|
||
val module = ModuleUtil.findModuleForPsiElement(parent.value) ?: return children | ||
val fileIndex = SqlDelightFileIndex.getInstance(module) | ||
if (!fileIndex.isConfigured) { | ||
return children | ||
} | ||
val packagePrefix = fileIndex.packageName.substringBefore(".") | ||
if (packagePrefix.isEmpty()) { | ||
return children | ||
} | ||
val srcPaths = fileIndex.sourceFolders(true) | ||
.flatMap { sourceFolders -> sourceFolders.map { it.folder.toPath() } } | ||
|
||
val path = try { | ||
parent.value.virtualFile.toNioPath().toAbsolutePath() | ||
} catch (exception: UnsupportedOperationException) { | ||
return children | ||
} | ||
if (srcPaths.none { path.startsWith(it) }) { | ||
return children | ||
} | ||
val srcDirName = parent.value.name | ||
|
||
val result = mutableListOf<AbstractTreeNode<*>>() | ||
val psiManager = PsiManager.getInstance(project) | ||
for (child in children) { | ||
if (child is PsiDirectoryNode && child.value.name == packagePrefix) { | ||
val leafDir = findLeafDirectory(child) | ||
val psiFile = psiManager.findDirectory(leafDir) ?: return children | ||
result.add(SqlDelightPackageNode(srcDirName, project, psiFile, settings)) | ||
} else { | ||
result.add(child) | ||
} | ||
} | ||
return result | ||
} | ||
|
||
private fun findLeafDirectory(node: PsiDirectoryNode): VirtualFile { | ||
var virtualFile = node.value.virtualFile | ||
VfsUtilCore.iterateChildrenRecursively(virtualFile, VirtualFileFilter.ALL) { file -> | ||
virtualFile = file | ||
val filteredChildren = file.children.filter { !it.name.startsWith(".") } | ||
if (filteredChildren.size == 1) { | ||
filteredChildren.first().isDirectory | ||
} else { | ||
false | ||
} | ||
} | ||
return virtualFile | ||
} | ||
|
||
override fun getData(selected: MutableCollection<AbstractTreeNode<*>>, dataId: String): Any? { | ||
if (PlatformDataKeys.DELETE_ELEMENT_PROVIDER.`is`(dataId)) { | ||
if (selected.any { it is SqlDelightPackageNode }) { | ||
return SqlDelightDeleteProvider(selected) | ||
} | ||
} | ||
return null | ||
} | ||
|
||
private class SqlDelightDeleteProvider( | ||
selected: Collection<AbstractTreeNode<*>>, | ||
) : DeleteProvider { | ||
|
||
private val elements = collectPsiElements(selected) | ||
override fun deleteElement(dataContext: DataContext) { | ||
val project = CommonDataKeys.PROJECT.getData(dataContext) | ||
DeleteHandler.deletePsiElement(elements, project) | ||
} | ||
|
||
override fun canDeleteElement(dataContext: DataContext): Boolean { | ||
return DeleteHandler.shouldEnableDeleteAction(elements) | ||
} | ||
|
||
private fun collectPsiElements(selected: Collection<AbstractTreeNode<*>>): Array<PsiElement> { | ||
val result = mutableSetOf<PsiElement>() | ||
for (node in selected) { | ||
if (node is SqlDelightPackageNode) { | ||
result.addAll(node.children.map { it.value as PsiElement }) | ||
generateSequence(node.value) { it.parent } | ||
.takeWhile { it.name != node.srcDirName } | ||
.forEach { result.add(it) } | ||
} else if (node.value is PsiElement) { | ||
result.add(node.value as PsiElement) | ||
} | ||
} | ||
return result.toTypedArray() | ||
} | ||
} | ||
|
||
private class SqlDelightPackageNode( | ||
val srcDirName: String, | ||
project: Project, | ||
value: PsiDirectory, | ||
viewSettings: ViewSettings?, | ||
) : PsiDirectoryNode(project, value, viewSettings) { | ||
|
||
override fun updateImpl(data: PresentationData) { | ||
data.presentableText = value.virtualFile.path.substringAfterLast(srcDirName) | ||
.replace(File.separator, ".") | ||
.removePrefix(".") | ||
data.locationString = | ||
ProjectViewDirectoryHelper.getInstance(project).getLocationString(value, false, false) | ||
data.setIcon(AllIcons.Nodes.Package) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters