Skip to content

Instantly share code, notes, and snippets.

@mob-sakai
Last active September 22, 2023 18:33
Show Gist options
  • Save mob-sakai/b98a62c1f2c94c1fef9021101635a5cd to your computer and use it in GitHub Desktop.
Save mob-sakai/b98a62c1f2c94c1fef9021101635a5cd to your computer and use it in GitHub Desktop.
Automatically remove empty folders in project for Unity.
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Linq;
using System;
/// <summary>
/// Remove empty folders automatically.
/// </summary>
public class RemoveEmptyFolders : UnityEditor.AssetModificationProcessor
{
public const string kMenuText = "Assets/Remove Empty Folders";
static readonly StringBuilder s_Log = new StringBuilder();
static readonly List<DirectoryInfo> s_Results = new List<DirectoryInfo>();
/// <summary>
/// Raises the initialize on load method event.
/// </summary>
[InitializeOnLoadMethod]
static void OnInitializeOnLoadMethod()
{
EditorApplication.delayCall += () => Valid();
}
/// <summary>
/// Raises the will save assets event.
/// </summary>
static string[] OnWillSaveAssets(string[] paths)
{
// If menu is unchecked, do nothing.
if (!EditorPrefs.GetBool(kMenuText, false))
return paths;
// Get empty directories in Assets directory
s_Results.Clear();
var assetsDir = Application.dataPath + Path.DirectorySeparatorChar;
GetEmptyDirectories(new DirectoryInfo(assetsDir), s_Results);
// When empty directories has detected, remove the directory.
if (0 < s_Results.Count)
{
s_Log.Length = 0;
s_Log.AppendFormat("Remove {0} empty directories as following:\n", s_Results.Count);
foreach (var d in s_Results)
{
s_Log.AppendFormat("- {0}\n", d.FullName.Replace(assetsDir, ""));
FileUtil.DeleteFileOrDirectory(d.FullName);
}
// UNITY BUG: Debug.Log can not set about more than 15000 characters.
s_Log.Length = Mathf.Min(s_Log.Length, 15000);
Debug.Log(s_Log.ToString());
s_Log.Length = 0;
AssetDatabase.Refresh();
}
return paths;
}
/// <summary>
/// Toggles the menu.
/// </summary>
[MenuItem(kMenuText)]
static void OnClickMenu()
{
// Check/Uncheck menu.
bool isChecked = !Menu.GetChecked(kMenuText);
Menu.SetChecked(kMenuText, isChecked);
// Save to EditorPrefs.
EditorPrefs.SetBool(kMenuText, isChecked);
OnWillSaveAssets(null);
}
[MenuItem(kMenuText, true)]
static bool Valid()
{
// Check/Uncheck menu from EditorPrefs.
Menu.SetChecked(kMenuText, EditorPrefs.GetBool(kMenuText, false));
return true;
}
/// <summary>
/// Get empty directories.
/// </summary>
static bool GetEmptyDirectories(DirectoryInfo dir, List<DirectoryInfo> results)
{
bool isEmpty = true;
try
{
isEmpty = dir.GetDirectories().Count(x => !GetEmptyDirectories(x, results)) == 0 // Are sub directories empty?
&& dir.GetFiles("*.*").All(x => x.Extension == ".meta"); // No file exist?
}
catch
{
}
// Store empty directory to results.
if (isEmpty)
results.Add(dir);
return isEmpty;
}
}
@HernandoNJ
Copy link

Solution 2020.2: Lines 48:

FileUtil.DeleteFileOrDirectory(d.FullName);
FileUtil.DeleteFileOrDirectory(d.Parent + "\\" + d.Name + ".meta"); // unity 2020.2 need to delete the meta too

This worked for me. I wrote it this way

foreach (var d in s_Results)
{
    // Line 1:  s_Log.AppendFormat("- {0}\n", d.FullName.Replace(assetsDir, "")); 
    FileUtil.DeleteFileOrDirectory(d.FullName);
    FileUtil.DeleteFileOrDirectory(d.Parent + "\\" + d.Name + ".meta"); // unity 2020.2 need to delete the meta too
}

I wonder if // Line 1: s_Log.AppendFormat("- {0}\n", d.FullName.Replace(assetsDir, "")); is required

@pointcache
Copy link

pointcache commented Sep 10, 2021

It is achievable without using IO. This is a context version, select folders to clean up, right click > Delete Empty Folders.
You can adapt it for project wide if you dare.

namespace Framework.Editor.Extensions
{
    using UnityEngine;
    using UnityEditor;

    internal static class DeleteEmptyFolders
    {
        [MenuItem("Assets/Delete Empty Folders")]
        static void deleteEmptyFolders()
        {
            foreach (var item in Selection.objects)
            {
                TryDeleteEmptyFolders(item);
            } 
        }

        private static void TryDeleteEmptyFolders(UnityEngine.Object obj)
        {
            if (!AssetDatabase.IsMainAsset(obj))
                return;

            // checks if the asset is a folder
            if (obj.GetType() != typeof(UnityEditor.DefaultAsset))
                return;

            string dir = AssetDatabase.GetAssetPath(obj);

            var subdirs = AssetDatabase.GetSubFolders(dir);

            string[] strBuffer = new string[1];

            foreach (var sub in subdirs)
            {
                strBuffer[0] = sub;
                var assets = AssetDatabase.FindAssets("*", strBuffer);

                if(assets.Length == 0)
                {
                    Debug.Log("Deleteing : " + sub);
                    AssetDatabase.MoveAssetToTrash(sub);
                }
            }
        }
    }
}

@TinyTeaTree
Copy link

Need to change line 97
.All(x => x.Extension == ".meta" || x.Name.Contains("DS_Store")); // No important files?

In Mac there are hidden files called .DS_Store.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment