From 692e27e7316d4333dcf1bb54cee3f228e8245878 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Fri, 10 Nov 2023 16:38:52 +0100 Subject: [PATCH] improvement: Set icons properly for all parts of tree view Previously, only some nodes would have their icons set, which would result with some having folder icons added by VS Code but not all. Now, we set icons for each node manually. The only problem I have is with packages, which doesn't really have a great icon anywhere. symbol-package is the same as symbol-object, which is too similar. So I decided to go with folder, which seems the next best thing. --- .../meta/internal/tvp/ClasspathTreeView.scala | 10 +++- .../internal/tvp/MetalsTreeViewProvider.scala | 56 ++++++++++--------- 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/metals/src/main/scala/scala/meta/internal/tvp/ClasspathTreeView.scala b/metals/src/main/scala/scala/meta/internal/tvp/ClasspathTreeView.scala index 6a81132e02f..f94ea152f67 100644 --- a/metals/src/main/scala/scala/meta/internal/tvp/ClasspathTreeView.scala +++ b/metals/src/main/scala/scala/meta/internal/tvp/ClasspathTreeView.scala @@ -28,17 +28,19 @@ class ClasspathTreeView[Value, Key]( valueTooltip: Value => String, toplevels: () => Iterator[Value], loadSymbols: (Key, String) => Iterator[TreeViewSymbolInformation], + toplevelIcon: String, ) { val scheme: String = s"$schemeId-${folder.path.toString()}" val rootUri: String = scheme + ":" - def root(showFolderName: Boolean): TreeViewNode = { + def root(showFolderName: Boolean, icon: String): TreeViewNode = { val folderPart = if (showFolderName) s" (${folder.nameOrUri})" else "" TreeViewNode( viewId, rootUri, title + folderPart + s" (${toplevels().size})", collapseState = MetalsTreeItemCollapseState.collapsed, + icon = icon, ) } @@ -50,7 +52,7 @@ class ClasspathTreeView[Value, Key]( def children(uri: String): Array[TreeViewNode] = { if (uri == rootUri) { - TreeViewNode.sortAlphabetically(toplevels().map(toViewNode).toArray) + TreeViewNode.sortAlphabetically(toplevels().map(toplevelNode).toArray) } else { val node = fromUri(uri) @@ -119,6 +121,7 @@ class ClasspathTreeView[Value, Key]( case k.FIELD => "symbol-field" case k.TYPE_PARAMETER => "symbol-type-parameter" case k.TYPE => "symbol-type-parameter" + case k.PACKAGE => "symbol-folder" case _ => null } @@ -170,7 +173,7 @@ class ClasspathTreeView[Value, Key]( } } - def toViewNode(value: Value): TreeViewNode = { + def toplevelNode(value: Value): TreeViewNode = { val uri = toUri(id(value)).toUri TreeViewNode( viewId, @@ -178,6 +181,7 @@ class ClasspathTreeView[Value, Key]( valueTitle(value), tooltip = valueTooltip(value), collapseState = MetalsTreeItemCollapseState.collapsed, + icon = toplevelIcon, ) } diff --git a/metals/src/main/scala/scala/meta/internal/tvp/MetalsTreeViewProvider.scala b/metals/src/main/scala/scala/meta/internal/tvp/MetalsTreeViewProvider.scala index 90c15f7d527..09aee86dad9 100644 --- a/metals/src/main/scala/scala/meta/internal/tvp/MetalsTreeViewProvider.scala +++ b/metals/src/main/scala/scala/meta/internal/tvp/MetalsTreeViewProvider.scala @@ -260,15 +260,15 @@ class FolderTreeViewProvider( private val pendingProjectUpdates = ConcurrentHashSet.empty[BuildTargetIdentifier] val libraries = new ClasspathTreeView[AbsolutePath, AbsolutePath]( - definitionIndex, - TreeViewProvider.Project, - s"libraries", - s"Libraries", - folder, - identity, - _.toURI.toString(), - _.toAbsolutePath(followSymlink = false), - path => { + definitionIndex = definitionIndex, + viewId = TreeViewProvider.Project, + schemeId = s"libraries", + title = s"Libraries", + folder = folder, + id = identity, + encode = _.toURI.toString(), + decode = _.toAbsolutePath(followSymlink = false), + valueTitle = path => { if (path.filename == JdkSources.zipFileName) { maybeUsedJdkVersion .map(ver => s"jdk-${ver}-sources") @@ -276,31 +276,32 @@ class FolderTreeViewProvider( } else path.filename }, - _.toString, - () => buildTargets.allSourceJars, - (path, symbol) => { + valueTooltip = _.toString, + toplevels = () => buildTargets.allSourceJars, + loadSymbols = (path, symbol) => { val dialect = ScalaVersions.dialectForDependencyJar(path.filename) classpath.jarSymbols(path, symbol, dialect) }, + toplevelIcon = "package", ) val projects = new ClasspathTreeView[BuildTarget, BuildTargetIdentifier]( - definitionIndex, - TreeViewProvider.Project, - s"projects", - s"Projects", - folder, - _.getId(), - _.getUri(), - uri => new BuildTargetIdentifier(uri), - _.getDisplayName(), - _.baseDirectory, - { () => + definitionIndex = definitionIndex, + viewId = TreeViewProvider.Project, + schemeId = s"projects", + title = s"Projects", + folder = folder, + id = _.getId(), + encode = _.getUri(), + decode = uri => new BuildTargetIdentifier(uri), + valueTitle = _.getDisplayName(), + valueTooltip = _.baseDirectory, + toplevels = { () => buildTargets.all.filter(target => buildTargets.buildTargetSources(target.getId()).nonEmpty ) }, - { (id, symbol) => + loadSymbols = { (id, symbol) => val tops = for { scalaTarget <- buildTargets.scalaTarget(id).iterator source <- buildTargets.buildTargetSources(id) @@ -308,6 +309,7 @@ class FolderTreeViewProvider( } yield classpath.workspaceSymbols(source, symbol) tops.flatten }, + toplevelIcon = "target", ) def setVisible(viewId: String, visibility: Boolean): Unit = { @@ -325,7 +327,7 @@ class FolderTreeViewProvider( if (toUpdate.nonEmpty) { val nodes = toUpdate.map { target => projects - .toViewNode(target) + .toplevelNode(target) .copy(collapseState = MetalsTreeItemCollapseState.expanded) } Some(nodes) @@ -387,8 +389,8 @@ class FolderTreeViewProvider( nodeUri match { case None if buildTargets.all.nonEmpty => Array( - projects.root(showFolderName), - libraries.root(showFolderName), + projects.root(showFolderName, "project"), + libraries.root(showFolderName, "library"), ) case Some(uri) => if (libraries.matches(uri)) {