Skip to content

Internalization + multiple small fixes #2280

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

Merged
merged 13 commits into from
Feb 18, 2022
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
1 change: 1 addition & 0 deletions rider/.idea/fileTemplates/code/I18nized Concatenation.java

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions rider/.idea/fileTemplates/code/I18nized Expression.java

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 21 additions & 0 deletions rider/.idea/inspectionProfiles/Project_Default.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.jetbrains.rider.plugins.unity.actions

import com.intellij.DynamicBundle
import org.jetbrains.annotations.Nls
import org.jetbrains.annotations.NonNls
import org.jetbrains.annotations.PropertyKey

class UnityPluginActionsBundle: DynamicBundle(BUNDLE) {
companion object {
@NonNls
private const val BUNDLE = "messages.UnityPluginActionsBundle"
private val INSTANCE: UnityPluginActionsBundle = UnityPluginActionsBundle()

@Nls
fun message(
@PropertyKey(resourceBundle = BUNDLE) key: String,
vararg params: Any
): String {
return INSTANCE.getMessage(key, *params)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import com.intellij.util.PathUtil
import com.intellij.util.application
import com.intellij.workspaceModel.ide.WorkspaceModel
import com.jetbrains.rd.platform.util.getLogger
import com.jetbrains.rider.plugins.unity.explorer.UnityExplorerFileSystemNode.Companion.isHiddenAsset
import com.jetbrains.rider.plugins.unity.isUnityProjectFolder
import com.jetbrains.rider.plugins.unity.workspace.getPackages
import com.jetbrains.rider.projectDir
Expand All @@ -27,10 +28,8 @@ import java.nio.file.Paths
import java.time.LocalDateTime
import java.time.ZoneOffset
import java.util.*
import kotlin.io.path.ExperimentalPathApi
import kotlin.io.path.name

@ExperimentalPathApi
class MetaTracker : BulkFileListener, VfsBackendRequester, Disposable {
companion object {
private val logger = getLogger<MetaTracker>()
Expand All @@ -56,7 +55,7 @@ class MetaTracker : BulkFileListener, VfsBackendRequester, Disposable {
val ls = event.file?.detectedLineSeparator
?: "\n" // from what I see, Unity 2020.3 always uses "\n", but lets use same as the main file.
actions.add(metaFile, project) {
createMetaFile(event.parent, metaFileName, ls)
createMetaFile(event.file, event.parent, metaFileName, ls)
}
}
is VFileDeleteEvent -> {
Expand All @@ -69,7 +68,7 @@ class MetaTracker : BulkFileListener, VfsBackendRequester, Disposable {
val metaFile = getMetaFile(event.file.path) ?: continue
val ls = event.file.detectedLineSeparator ?: "\n"
actions.add(metaFile, project) {
createMetaFile(event.newParent, getMetaFileName(event.newChildName), ls)
createMetaFile(event.file, event.newParent, getMetaFileName(event.newChildName), ls)
}
}
is VFileMoveEvent -> {
Expand Down Expand Up @@ -145,12 +144,13 @@ class MetaTracker : BulkFileListener, VfsBackendRequester, Disposable {

private fun getMetaFileName(fileName: String) = "$fileName.meta"

private fun createMetaFile(parent: VirtualFile, metaFileName: String, ls:String) {
val file = parent.createChildData(this, metaFileName)
private fun createMetaFile(assetFile: VirtualFile?, parent: VirtualFile, metaFileName: String, ls: String) {
if (assetFile != null && isHiddenAsset(assetFile)) return // not that children of a hidden folder (like `Documentation~`), would still pass this check. I think it is fine.
val metaFile = parent.createChildData(this, metaFileName)
val guid = UUID.randomUUID().toString().replace("-", "").substring(0, 32)
val timestamp = LocalDateTime.now(ZoneOffset.UTC).atZone(ZoneOffset.UTC).toEpochSecond() // LocalDateTime to epoch seconds
val content = "fileFormatVersion: 2${ls}guid: ${guid}${ls}timeCreated: $timestamp"
VfsUtil.saveText(file, content)
VfsUtil.saveText(metaFile, content)
}

override fun dispose() = Unit
Expand Down Expand Up @@ -195,9 +195,9 @@ class MetaTracker : BulkFileListener, VfsBackendRequester, Disposable {
@Nls
fun getCommandName(): String {
return if (actions.count() == 1)
"Process '${actions.single().metaFile.name}'"
UnityPluginExplorerBundle.message("process.one.meta.file", actions.single().metaFile.name)
else
"Process ${actions.count()} .meta Files"
UnityPluginExplorerBundle.message("process.several.meta.files", actions.count())
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@file:Suppress("UnstableApiUsage")

package com.jetbrains.rider.plugins.unity.explorer

import com.intellij.icons.AllIcons
Expand All @@ -7,6 +9,9 @@ import com.intellij.openapi.actionSystem.ActionManager
import com.intellij.openapi.actionSystem.DefaultActionGroup
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.JDOMExternalizerUtil
import com.intellij.openapi.util.NlsSafe
import com.jetbrains.rider.actions.RiderActionsBundle
import com.jetbrains.rider.plugins.unity.actions.UnityPluginActionsBundle
import com.jetbrains.rider.plugins.unity.isUnityProject
import com.jetbrains.rider.projectView.views.SolutionViewPaneBase
import com.jetbrains.rider.projectView.views.actions.ConfigureScratchesAction
Expand All @@ -20,7 +25,7 @@ class UnityExplorer(project: Project) : SolutionViewPaneBase(project, createRoot

companion object {
const val ID = "UnityExplorer"
const val Title = "Unity"
@NlsSafe const val Title = "Unity"
const val Weight = 1
const val ShowProjectNamesOption = "show-project-names"
const val ShowTildeFoldersOption = "show-tilde-folders"
Expand All @@ -43,7 +48,6 @@ class UnityExplorer(project: Project) : SolutionViewPaneBase(project, createRoot
}

var showTildeFolders = true
private set

var showProjectNames = true
private set
Expand Down Expand Up @@ -104,13 +108,15 @@ class UnityExplorer(project: Project) : SolutionViewPaneBase(project, createRoot
// Adds to the tool window toolbar
override fun addToolbarActions(actionGroup: DefaultActionGroup) {
actionGroup.addAction(ConfigureScratchesAction()).setAsSecondary(true)
actionGroup.addAction(SolutionViewToggleAction("Show Project Names",
"Show names of owning projects next to folders",
actionGroup.addAction(SolutionViewToggleAction(
UnityPluginActionsBundle.message("action.show.project.names.text"),
UnityPluginActionsBundle.message("action.show.project.names.description"),
AllIcons.Actions.ListFiles,
{ showProjectNames }, { showProjectNames = it }
)).setAsSecondary(true)
actionGroup.addAction(SolutionViewToggleAction("Show Hidden Folders",
"Show folders ending with '~'",
actionGroup.addAction(SolutionViewToggleAction(
UnityPluginActionsBundle.message("action.show.tilde.folders.text"),
null,
AllIcons.Actions.ListFiles,
{ showTildeFolders }, { showTildeFolders = it }
)).setAsSecondary(true)
Expand All @@ -119,9 +125,10 @@ class UnityExplorer(project: Project) : SolutionViewPaneBase(project, createRoot

// Adds to the project view pane's own toolbar
override fun addPrimaryToolbarActions(actionGroup: DefaultActionGroup) {
actionGroup.addAction(SolutionViewToggleAction("Show All Files",
"Show all files, including .meta files",
AllIcons.Actions.ShowHiddens, {
actionGroup.addAction(SolutionViewToggleAction(
RiderActionsBundle.message("action.show.all.files.text"),
UnityPluginActionsBundle.message("action.show.all.files.description"),
AllIcons.Actions.ToggleVisibility, {
SolutionExplorerViewPane.getInstance(myProject).myShowAllFiles
}, {
SolutionExplorerViewPane.getInstance(myProject).myShowAllFiles = it
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ enum class AncestorNodeType {
UserEditablePackage,
ReadOnlyPackage,
IgnoredFolder,
HiddenAsset,
References,
FileSystem; // A folder in Packages that isn't a package. Gets no special treatment

Expand All @@ -48,6 +49,29 @@ open class UnityExplorerFileSystemNode(project: Project,
protected val descendentOf: AncestorNodeType)
: FileSystemNodeBase(project, virtualFile, nestedFiles) {

companion object {
// can be folder or file
// note that children of hidden folder are not matched by this function
fun isHiddenAsset(file: VirtualFile): Boolean {
// See https://docs.unity3d.com/Manual/SpecialFolders.html
val extension = file.extension?.lowercase(Locale.getDefault())
if (extension != null && UnityExplorer.IgnoredExtensions.contains(extension)) {
return true
}

val name = file.nameWithoutExtension.lowercase(Locale.getDefault())
if (name == "cvs" || file.name.startsWith(".")) {
return true
}

if (file.name.endsWith("~")) {
return true
}

return false
}
}

override val entities: List<ProjectModelEntity>
get() = WorkspaceModel
.getInstance(myProject)
Expand All @@ -72,14 +96,13 @@ open class UnityExplorerFileSystemNode(project: Project,

// Mark ignored file types. This is mainly so we can highlight that hidden folders are completely ignored. We
// have lots of non-indexed files in Assets and Packages, but they still appear in Find in Files when we check
// 'non-solution items'. Ignored file types are completely ignored, and don't show up at all. The default `*~`
// pattern matches Unity's hidden folder pattern, but can be used for e.g. `Samples~` and `Documentation~`.
// 'non-solution items'. Ignored file types are completely ignored, and don't show up at all.
// Make it clear that the folder is ignored/excluded/not indexed
val ignored = FileTypeManager.getInstance().isFileIgnored(virtualFile)
if (ignored || descendentOf == AncestorNodeType.IgnoredFolder) {
// TODO: Consider wording
// We can usually still search for a file that is not indexed. An ignored file is completely excluded
presentation.addText(" ${SolutionViewPaneBase.TextSeparator} ignored ${SolutionViewPaneBase.TextSeparator} no index", SimpleTextAttributes.GRAYED_ATTRIBUTES)
presentation.addText(UnityPluginExplorerBundle.message("label.ignored.no.index", SolutionViewPaneBase.TextSeparator), SimpleTextAttributes.GRAYED_ATTRIBUTES)
}

// Add additional info for directories
Expand All @@ -88,33 +111,40 @@ open class UnityExplorerFileSystemNode(project: Project,
addProjects(presentation)
}

// Add tooltip for non-imported folders (anything ending with tilde). Also, show the full name if we're hiding
// the tilde suffix.
if (isHiddenFolder(virtualFile)) {
// Add tooltip for non-imported files and folders. Also, show the full name if we're hiding the tilde suffix.
if (isHiddenAsset(virtualFile) || descendentOf == AncestorNodeType.HiddenAsset) {
var tooltip = if (presentation.tooltip.isNullOrEmpty()) "" else presentation.tooltip + "<br/>"
if (!SolutionExplorerViewPane.getInstance(myProject).myShowAllFiles) {
if (!SolutionExplorerViewPane.getInstance(myProject).myShowAllFiles && isFolderEndingWithTilde(virtualFile)) {
tooltip += virtualFile.name + "<br/>"
}
presentation.tooltip = tooltip + "This folder is not imported into the asset database"
presentation.tooltip = tooltip +
if (virtualFile.isDirectory) UnityPluginExplorerBundle.message("tooltip.this.folder.not.imported.into.asset.database") else
UnityPluginExplorerBundle.message("tooltip.this.file.not.imported.into.asset.database")
}

if (ignored) {
val tooltip = if (presentation.tooltip.isNullOrEmpty()) "" else presentation.tooltip + "<br/>"
presentation.tooltip = tooltip + "This folder matches an Ignored File and Folders pattern"
presentation.tooltip = tooltip + if (virtualFile.isDirectory)
UnityPluginExplorerBundle.message("tooltip.this.folder.matches.ignored.file.folders.pattern") else
UnityPluginExplorerBundle.message("tooltip.this.file.matches.ignored.file.folders.pattern")
}
}

override fun getName(): String {
// Remember that *~ is a default ignore pattern for IntelliJ. Any files/folders in and under this folder won't
// be indexed. Hopefully this comment will stop someone wasting as much time as I did.
if (isHiddenFolder(virtualFile) && !SolutionExplorerViewPane.getInstance(myProject).myShowAllFiles) {
if (isFolderEndingWithTilde(virtualFile) && !SolutionExplorerViewPane.getInstance(myProject).myShowAllFiles) {
return super.getName().removeSuffix("~")
}
return super.getName()
}

// Hidden from Unity's asset database
private fun isHiddenFolder(file: VirtualFile)
/* Special case of {@link #isHiddenAsset(VirtualFile)}
Files and folders ending with '~' are ignored by the asset importer. Files with '~' are usually backup files,
so should be hidden. Unity uses folders that end with '~' as a way of distributing files that are not to be
imported. This is usually `Documentation~` inside packages (https://docs.unity3d.com/Manual/cus-layout.html),
but it can also be used for distributing code, too (e.g. `Samples~`). This code will not be treated as assets
by Unity, but will still be added to the generated .csproj files to allow for use as e.g. command line tools
*/
private fun isFolderEndingWithTilde(file: VirtualFile)
= descendentOf != AncestorNodeType.FileSystem && file.isDirectory && file.name.endsWith("~")

// Ignored by IDE
Expand All @@ -132,10 +162,8 @@ open class UnityExplorerFileSystemNode(project: Project,
var description = projectNames.take(3).joinToString(", ")
if (projectNames.count() > 3) {
description += ", …"
presentation.tooltip = "Contains files from multiple projects:<br/>" + projectNames.take(10).joinToString("<br/>")
if (projectNames.count() > 10) {
presentation.tooltip += "<br/>and ${projectNames.count() - 10} others"
}
presentation.tooltip = UnityPluginExplorerBundle.message("tooltip.contains.files.from.multiple.projects") + "<br/>" + projectNames.take(10).joinToString("<br/>"
+ if (projectNames.count() > 10) "<br/>" + UnityPluginExplorerBundle.message("tooltip.and.count.others", projectNames.count() - 10) else "")
}
presentation.addText(" ($description)", SimpleTextAttributes.GRAYED_ATTRIBUTES)
}
Expand Down Expand Up @@ -205,6 +233,7 @@ open class UnityExplorerFileSystemNode(project: Project,
return null
}

@Suppress("SameParameterValue")
private fun findAncestor(root: FileSystemNodeBase?, name: String): FileSystemNodeBase? {
return forEachAncestor(root) { this.name.equals(name, true) }
}
Expand Down Expand Up @@ -271,7 +300,7 @@ open class UnityExplorerFileSystemNode(project: Project,

// Note that its only the root node that's marked as "unloaded"/not imported. Child files and folder icons
// are rendered as normal
if (isHiddenFolder(virtualFile)) {
if (virtualFile.isDirectory && isHiddenAsset(virtualFile)) {
return UnityIcons.Explorer.UnloadedFolder
}
}
Expand All @@ -282,6 +311,8 @@ open class UnityExplorerFileSystemNode(project: Project,
override fun createNode(virtualFile: VirtualFile, nestedFiles: List<NestingNode<VirtualFile>>): FileSystemNodeBase {
val desc = if (isIgnoredFolder(virtualFile) || (!virtualFile.isDirectory && isIgnoredFolder(virtualFile.parent))) {
AncestorNodeType.IgnoredFolder
} else if (isHiddenAsset(virtualFile)) {
AncestorNodeType.HiddenAsset
} else {
descendentOf
}
Expand All @@ -297,32 +328,12 @@ open class UnityExplorerFileSystemNode(project: Project,
return true
}

// See https://docs.unity3d.com/Manual/SpecialFolders.html
val extension = file.extension?.lowercase(Locale.getDefault())
if (extension != null && UnityExplorer.IgnoredExtensions.contains(extension)) {
return false
}

val name = file.nameWithoutExtension.lowercase(Locale.getDefault())
if (name == "cvs" || file.name.startsWith(".")) {
return false
}

/* Files and folders ending with '~' are ignored by the asset importer. Files with '~' are usually backup files,
so should be hidden. Unity uses folders that end with '~' as a way of distributing files that are not to be
imported. This is usually `Documentation~` inside packages (https://docs.unity3d.com/Manual/cus-layout.html),
but it can also be used for distributing code, too (e.g. `Samples~`). This code will not be treated as assets
by Unity, but will still be added to the generated .csproj files to allow for use as e.g. command line tools
*/
if (isHiddenFolder(file)) {
// special case, this check should go before isPartOfAssetDataBase
if (isFolderEndingWithTilde(file)) {
return UnityExplorer.getInstance(myProject).showTildeFolders
}

if (!file.isDirectory && file.name.endsWith("~")) {
return false
}

return true
return !isHiddenAsset(file)
}

override fun getFileStatus(): FileStatus {
Expand Down
Loading