New "Add Custom Editor" MenuItem
I wrote this little script which adds a new Add Custom Editor MenuItem to the Assets context menu:

Usage
- Right-click a
Component script in the Scripts folder.
- Select
Add Custom Editor.
- The component now has an
Editor which gets automatically selected, so you can modify it as you like. It has the same name (with Editor appended) and is at the same relative path, but in the Scripts/Editor folder
The screenshots below show an example: Given script Scripts/Test/TestScript, it creates a new editor at Scripts/Editor/Test/TestScriptEditor.
NOTE: The MenuItem will be disabled unless you have selected a Script that:
- Has a
.cs file ending
- Is located somewhere under the
Scripts folder (can be nested in any sub-directory)
- Is not in the
Editor folder
- Does not have an editor yet

Setup
Create -> C# Script
- Call it
AddCustomEditorMenuItem
- Replace its contents with the code from this gist
- Done!
- Test it: Right-click a script file in the
Scripts directory.
Code Highlights
- Figuring out all the paths took most of the time:
scriptName = scriptAsset.name;
// get system file path
scriptPath = Path.GetFullPath(ProjectRoot + AssetDatabase.GetAssetPath (scriptAsset));
// get file name of the editor file
editorFileName = GetEditorFileNameFor (scriptName);
// split the script path
var results = scriptPathRegex.Matches (scriptPath).GetEnumerator ();
results.MoveNext ();
var match = (Match)results.Current;
scriptsPath = match.Groups [1].Value;
scriptRelativePath = match.Groups [2].Value;
// re-combine editor path
editorPath = Path.Combine (scriptsPath, "Editor");
editorPath = Path.Combine (editorPath, scriptRelativePath);
editorPath = Path.Combine (editorPath, editorFileName);
// nicely formatted file path
editorPath = Path.GetFullPath(editorPath);
editorRelativeAssetPath = editorPath.Substring(ProjectRoot.Length);
- Once, paths are figured out, actually writing the file is nice and easy!
public void WriteCustomEditorFile ()
{
// create all missing directories in the hierarchy
Directory.CreateDirectory (Path.GetDirectoryName (editorPath));
// write file
File.WriteAllText (editorPath, BuildCustomEditorCode(scriptName));
// let Asset DB pick up the new file
AssetDatabase.Refresh();
// highlight in GUI
var os = AssetDatabase.LoadAllAssetsAtPath(editorRelativeAssetPath);
EditorGUIUtility.PingObject (os[0]);
// log
Debug.Log("Created new custom Editor at: " + editorRelativeAssetPath);
}
// ...
/// <summary>
/// The menu item entry
/// </summary>
[MenuItem ("Assets/Add Custom Editor %#e", false, 0)]
public static void AddCustomEditor ()
{
var scriptAsset = Selection.activeObject;
// figure out paths
var scriptPathInfo = new ScriptPathInfo (scriptAsset);
// write file
scriptPathInfo.WriteCustomEditorFile ();
}
- If you don't like the default contents of a newly created editor, feel free to edit this part:
static string BuildCustomEditorCode (string name)
{
return @"using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(" + name + @"))]
public class " + name + @"Editor : Editor {
public override void OnInspectorGUI ()
{
base.OnInspectorGUI ();
var obj = (" + name + @") target;
if (GUILayout.Button (""Hi!"")) {
// do something with obj when button is clicked
Debug.Log(""Button pressed for: "" + obj.name);
EditorGUIUtility.PingObject (obj);
}
}
}";
}
- If your menu item is always grayed out, consider first checking out my explanations above, before debugging the code that determines if a valid script is selected:
[MenuItem ("Assets/Add Custom Editor %#e", true, 0)]
public static bool ValidateAddCustomEditor ()
{
var scriptAsset = Selection.activeObject;
if (scriptAsset == null) {
// nothing selected? (should probably not happen)
return false;
}
var path = ProjectRoot + AssetDatabase.GetAssetPath (scriptAsset);
if (!scriptPathRegex.IsMatch (path)) {
// not a Script in the Script folder
return false;
}
if (editorScriptPathRegex.IsMatch (path)) {
// we are not interested in Editor scripts
return false;
}
if (Directory.Exists (path)) {
// it's a directory, but we want a file
return false;
}
var scriptPathInfo = new ScriptPathInfo (scriptAsset);
// Debug.Log (scriptPathInfo.scriptPath);
// Debug.Log (Path.GetFullPath(AssetsPath + "/../"));
// Debug.Log (scriptPathInfo.editorRelativeAssetPath);
// Debug.Log (scriptPathInfo.editorPath);
if (File.Exists (scriptPathInfo.editorPath)) {
// editor has already been created
return false;
}
// all good!
return true;
}