【Unity拡張】カレントディレクトリをハイライトするエディター拡張を作ってみた。

#はじめに
プロジェクト内のフォルダの数が増えてくると、現在開いているディレクトリがプロジェクトビューのツリー上のどこにあるのか、探すのがだんだん大変になってきます。

<img width= 600 src = "https://qiita-image-store.s3.amazonaws.com/0/44288/79214c4c-9fb7-947d-af27-ff105ee60927.png">
(画像のフォルダ構成は今回の記事のために突貫で作ったものですが、ちょっとひどすぎるかもしれません...)

<br>
そこで、今回は現在開いているディレクトリ(=カレントディレクトリ) を**一発でハイライト**するエディター拡張を作ってみました。

# 環境
Unity 5.5.0f3
Windows 10

# 作ったものについて
右クリックメニューからワンクリックでカレントディレクトリをハイライトしてくれるエディター拡張を作ってみました。

![highlight_current_directory.gif](https://qiita-image-store.s3.amazonaws.com/0/44288/27c12ad3-0baa-e890-0e35-08edf4053124.gif)
結構便利かも。


#ソースコード
プロジェクト内にEditorフォルダを作成して、Editorフォルダの中へ以下のスクリプトを入れてください。

```ProjectBrowserExtension.cs
namespace ProjectBrowserExtension
{
    using UnityEditor;
    using System.Reflection;
    using System.Linq;

    public class ProjectBrowserExtension
    {
        const string MenuItemName = "Assets/Highlight Current Directory";

        /// <summary>
        /// プロジェクトウィンドウでカレントディレクトリの親フォルダをハイライトする
        /// </summary>
        [MenuItem(MenuItemName)]
        static void FrameCurrentDirectory()
        {
            string currentDirectory = GetCurrentDirectory(); // カレントディレクトリ

            // カレントディレクトリ直下のファイルのパスを取得
            int depth = currentDirectory.Split('/').Length;
            string path = AssetDatabase.GetAllAssetPaths()
            .Where(assetPath => assetPath.Contains(currentDirectory)) // カレントディレクトリのファイルかどうか
            .FirstOrDefault(assetPath => assetPath.Split('/').Length == depth + 1); // カレントディレクトリ直下のファイルかどうか

            if (string.IsNullOrEmpty(path)) // カレントディレクトリにファイルが存在しない場合
            {
                FrameObjectInTwoColumnMode(GetInstanceID(currentDirectory), true, false);
                EditorApplication.delayCall += () =>
                {
                    ShowFolderContents(GetInstanceID(currentDirectory), true);
                };
            }
            else // カレントディレクトリにファイルが存在する場合
            {
                FrameObjectInTwoColumnMode(GetInstanceID(path), true, true);
            }
        }

        /// <summary>
        /// FrameCurrentDirectory()のValidate関数
        /// </summary>
        [MenuItem(MenuItemName, true, 20000)]
        static bool ValidateFrameCurrentDirectory()
        {
            return IsTwoColumn();
        }

        /// <summary>
        /// ProjectウィンドウがTwoColumnモードかどうか
        /// </summary>
        static bool IsTwoColumn()
        {
            var flag = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
            var asm = Assembly.Load("UnityEditor.dll");
            var typeProjectBrowser = asm.GetType("UnityEditor.ProjectBrowser");
            var projectBrowserWindow = EditorWindow.GetWindow(typeProjectBrowser);

            return typeProjectBrowser.GetField("m_ViewMode", flag).GetValue(projectBrowserWindow).ToString() == "TwoColumns";
        }

        /// <summary>
        /// pathからInstanceIDを取得
        /// </summary>
        static int GetInstanceID(string path)
        {
            return AssetDatabase.LoadAssetAtPath(path, typeof(UnityEngine.Object)).GetInstanceID();
        }

        /// <summary>
        /// Projectウィンドウでオブジェクトをハイライトする
        /// </summary>
        static void FrameObjectInTwoColumnMode(int instanceID, bool frame, bool ping)
        {
            var flag = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
            var asm = Assembly.Load("UnityEditor.dll");
            var typeProjectBrowser = asm.GetType("UnityEditor.ProjectBrowser");
            var projectBrowserWindow = EditorWindow.GetWindow(typeProjectBrowser);
            typeProjectBrowser.GetMethod("FrameObjectInTwoColumnMode", flag).Invoke(projectBrowserWindow, new object[] { instanceID, frame, ping });
        }

        /// <summary>
        /// Projectウィンドウでフォルダの中身を表示
        /// </summary>
        static void ShowFolderContents(int folderInstanceID, bool revealAndFrameInFolderTree)
        {
            var flag = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
            var asm = Assembly.Load("UnityEditor.dll");
            var typeProjectBrowser = asm.GetType("UnityEditor.ProjectBrowser");
            var projectBrowserWindow = EditorWindow.GetWindow(typeProjectBrowser);
            typeProjectBrowser.GetMethod("ShowFolderContents", flag).Invoke(projectBrowserWindow, new object[] { folderInstanceID, revealAndFrameInFolderTree });
        }

        /// <summary>
        /// Projectウィンドウで現在開いているディレクトリを取得
        /// </summary>
        static string GetCurrentDirectory()
        {
            var flag = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
            var asm = Assembly.Load("UnityEditor.dll");
            var typeProjectBrowser = asm.GetType("UnityEditor.ProjectBrowser");
            var projectBrowserWindow = EditorWindow.GetWindow(typeProjectBrowser);
            return (string)typeProjectBrowser.GetMethod("GetActiveFolderPath", flag).Invoke(projectBrowserWindow, null);
        }
    }
}

```

# エディター拡張を使う
右クリックメニューから "Highlight Current Directory" を選ぶだけでOK。<br>カレントディレクトリがハイライトされます。

![image](https://qiita-image-store.s3.amazonaws.com/0/44288/604b1d73-0a3f-85e4-dc38-f776a9ad0f8c.png)

# エディター拡張なしで同じことをやる
エディター拡張を作った後に気が付いたのですが、パンくずリストのカレントディレクトリをクリックすることでもフォルダーをハイライトすることができるみたいです.

![highlight_no_extension.gif](https://qiita-image-store.s3.amazonaws.com/0/44288/ed9faa95-d788-09d1-d7f2-65d4fb0f2139.gif)

<br>
フォルダの階層が深くなりすぎて、パンくずリストが画面外にはみ出てしまった場合にはこのエディター拡張は便利かもしれません。(完)

<img height = 360 src = "https://qiita-image-store.s3.amazonaws.com/0/44288/de1f9f62-97e3-d337-72fe-0ba16ae8f663.png">