ImmediateWindow

From Unify Community Wiki
Jump to: navigation, search

Author: Nick Gravelyn

Description

Some times you just need to execute some code in the editor. Maybe you want to randomize some positions. Or you want to line some things up quick. It's a hassle to make a new script, create a menu item, and then go click that item. It's even more annoying if you only need this operation once or twice. Now you can just use the Immediate Window instead.

Usage

Place the code into a file called "ImmediateWindow.cs" in a folder called "Editor" in your project. Once compiled you'll see a new item under "Window" called "Immediate". Click that to open the immediate window. You can now type C# script code and execute it.

By default the script has visibility into the UnityEngine, UnityEditor, System.Collections, System.Collections.Generic, and System.Text namespaces (so you don't need to fully qualify types from those namespaces) but you can fully qualify other types you need or modify the script to include the using statements you want.

ImmediateWindow.png

ImmediateWindow.cs

/*
 * ImmediateWindow.cs
 * Copyright (c) 2012 Nick Gravelyn
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of 
 * this software and associated documentation files (the "Software"), to deal in 
 * the Software without restriction, including without limitation the rights to use, 
 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 
 * Software, and to permit persons to whom the Software is furnished to do so, 
 * subject to the following conditions:
 
 * The above copyright notice and this permission notice shall be included in all 
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
 
using UnityEngine;
using UnityEditor;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Reflection;
 
public class ImmediateWindow : EditorWindow
{
    // script text
    private string scriptText = string.Empty;
 
    // cache of last method we compiled so repeat executions only incur a single compilation
    private MethodInfo lastScriptMethod;
 
    // position of scroll view
    private Vector2 scrollPos;
 
    void OnGUI()
    {
        // start the scroll view
        scrollPos = EditorGUILayout.BeginScrollView(scrollPos);
 
        // show the script field
        string newScriptText = EditorGUILayout.TextArea(scriptText);
        if (newScriptText != scriptText)
        {
            // if the script changed, update our cached version and null out our cached method
            scriptText = newScriptText;
            lastScriptMethod = null;
        }
 
        // store if the GUI is enabled so we can restore it later
        bool guiEnabled = GUI.enabled;
 
        // disable the GUI if the script text is empty
        GUI.enabled = guiEnabled && !string.IsNullOrEmpty(scriptText);
 
        // show the execute button
        if (GUILayout.Button("Execute"))
        {
            // if our script method needs compiling
            if (lastScriptMethod == null)
            {
                // create and configure the code provider
                var codeProvider = new CSharpCodeProvider();
                var options = new CompilerParameters();
                options.GenerateInMemory = true;
                options.GenerateExecutable = false;
 
                // bring in system libraries
                options.ReferencedAssemblies.Add("System.dll");
                options.ReferencedAssemblies.Add("System.Core.dll");
 
                // bring in Unity assemblies
                options.ReferencedAssemblies.Add(typeof(EditorWindow).Assembly.Location);
                options.ReferencedAssemblies.Add(typeof(Transform).Assembly.Location);
 
                // compile an assembly from our source code
                var result = codeProvider.CompileAssemblyFromSource(options, string.Format(scriptFormat, scriptText));
 
                // log any errors we got
                if (result.Errors.Count > 0)
                {
                    foreach (CompilerError error in result.Errors)
                    {
                        // the magic -11 on the line is to compensate for usings and class wrapper around the user script code.
                        // subtracting 11 from it will give the user the line numbers in their code.
                        Debug.LogError(string.Format("Immediate Compiler Error ({0}): {1}", error.Line - 11, error.ErrorText));   
                    }
                }
 
                // otherwise use reflection to pull out our action method so we can invoke it
                else
                {
                    var type = result.CompiledAssembly.GetType("ImmediateWindowCodeWrapper");
                    lastScriptMethod = type.GetMethod("PerformAction", BindingFlags.Public | BindingFlags.Static);
                }
            }
 
            // if we have a compiled method, invoke it
            if (lastScriptMethod != null)
                lastScriptMethod.Invoke(null, null);
        }
 
        // restore the GUI
        GUI.enabled = guiEnabled;
 
        // close the scroll view
        EditorGUILayout.EndScrollView();
    }
 
    [MenuItem("Window/Immediate")]
    static void Init()
    {
        // get the window, show it, and hand it focus
        var window = EditorWindow.GetWindow<ImmediateWindow>("Immediate", false);
        window.Show();
        window.Focus();
    }
 
    // script we wrap around user entered code
    static readonly string scriptFormat = @"
using UnityEngine; 
using UnityEditor;
using System.Collections;
using System.Collections.Generic;
using System.Text;
public static class ImmediateWindowCodeWrapper
{{
    public static void PerformAction()
    {{
        // user code goes here
        {0};
    }}
}}";
}
Personal tools
Namespaces

Variants
Actions
Navigation
Extras
Toolbox