SyntaxEditor 3.0 - Serializing Macros

SyntaxEditor for Windows Forms Forum

Posted 19 years ago by Ashton - Developer, Schema Solutions LLC
Avatar
In testing the SE3.0 release, I need to serialize a macro (I want to save macros so they can be used in subsequent app executions). Since EditCommand and all subclasses are not serializable, I created the following classes to handle serializing MacroCommand. I have tested it and it works fairly well. It will not serialize Paste commands but should handle everything else. It also uses some heavy reflection so CAS might be an issue for some users.

Here is a sample on how to call this:

// serialize a macro that was just run
PersistentMacro mymacro = new PersistentMacro(editor.MacroRecording.LastMacroCommand);
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter binfm = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
// serialize the macro we created
binfm.Serialize(File.Create(@"c:\test.macro"), mymacro);

...

// deserialize
PersistentMacro newmymacro = (PersistentMacro)binfm.Deserialize(File.Open(@"c:\test.macro", FileMode.Open));
MacroCommand mm = newmymacro.GetMacro();
editor.SelectedView.RaiseEditCommand(mm);
// Here are the class definitions

    [Serializable]
    public class PersistentMacro : ISerializable    
    {
        private ArrayList m_CmdList = new ArrayList();

        /// <summary>
        /// Loop through the list and recreate the commands needed by SyntaxEditor
        /// </summary>
        /// <returns></returns>
        public MacroCommand GetMacro ()
        {
            // local variables
            Assembly ass = Assembly.GetAssembly(typeof(EditCommand));
            ArrayList cmdList = new ArrayList();
            EditCommand cmd;

            // loop through the list of persistent items we have
            foreach (PersistentMacroCommand macro in this.m_CmdList)
            {
                // create the item based on type of command we have
                if (macro is PersistentTypingMacroCommand)
                {
                    PersistentTypingMacroCommand typingMacro = macro as PersistentTypingMacroCommand;

                    cmd = (EditCommand)ass.CreateInstance(
                        macro.CommandName, true, BindingFlags.CreateInstance, null, 
                        new object[] {typingMacro.Charactere, typingMacro.Overwrite}, null, null);
                }
                else if (macro is PersistentCasingMacroCommand)
                {
                    PersistentCasingMacroCommand caseMacro = macro as PersistentCasingMacroCommand;

                    cmd = (EditCommand)ass.CreateInstance(
                        macro.CommandName, true, BindingFlags.CreateInstance, null,
                        new object[] {Enum.Parse(typeof(CharacterCasing), caseMacro.EnumValue)}, null, null);
                }
                else if (macro is PersistentCommentMacroCommand)
                {
                    PersistentCommentMacroCommand commentMacro = macro as PersistentCommentMacroCommand;

                    cmd = (EditCommand)ass.CreateInstance(
                        macro.CommandName, true, BindingFlags.CreateInstance, null,
                        new object[] {commentMacro.Prefix}, null, null);
                }
                else
                {
                    cmd = (EditCommand)ass.CreateInstance(
                        macro.CommandName, true, BindingFlags.CreateInstance, null,
                        null, null, null);
                }

                // add the item to the list
                cmdList.Add(cmd);
            }

            // create a macro command using the list we created
            MacroCommand newMacro = new MacroCommand(cmdList);            
            return newMacro;
        }

        /// <summary>
        /// Called by ISerialization to reload items into the class during deser
        /// </summary>
        /// <param name="info"></param>
        /// <param name="context"></param>
        protected PersistentMacro (SerializationInfo info, StreamingContext context)
        {
            this.m_CmdList = info.GetValue("MacroCommand", typeof(ArrayList)) as ArrayList;
        }

        /// <summary>
        /// Ctor to serialize the objects manually
        /// </summary>
        /// <param name="command"></param>
        public PersistentMacro (MacroCommand command)
        {
            // parse the command
            this.ParseCommand(command);
        }

        /// <summary>
        /// Loop through the commands and serialize them out to an array list
        /// </summary>
        /// <param name="command"></param>
        private void ParseCommand (MacroCommand command)
        {
            // local variables
            Type type;
            PersistentMacroCommand macro;

            // loop through the command in the command
            foreach (EditCommand cmd in command)
            {
                // get the type of the cmd
                type = cmd.GetType();

                if (cmd is TypingCommand)
                    macro = HandleCommand(cmd as TypingCommand, type);        /* handle when user simply types a key */
                else if (cmd is MacroCommand || cmd is PasteFromClipboardCommand)
                    continue;                                                /* skip this because we can't serialize these easily */
                else if (cmd is CommentLinesCommand)
                    macro = HandleCommand(cmd as CommentLinesCommand, type);/* serialize uncomment command */
                else if (cmd is UncommentLinesCommand)                        
                    macro = HandleCommand(cmd as UncommentLinesCommand, type);/* serialize comment command */
                else if (cmd is ChangeCharacterCasingCommand)
                    macro = HandleCommand(cmd as ChangeCharacterCasingCommand, type);/* serialize change char casing which takes an enum value */
                else
                    macro = HandleCommand(type);                            /* handle the basic edit command that has no private fields */
                this.m_CmdList.Add(macro);
            }
        }

        /// <summary>
        /// Handle the base type of command
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private PersistentMacroCommand HandleCommand (Type type)
        {
            // local variables
            PersistentMacroCommand macro = new PersistentMacroCommand(type.FullName);
            return macro;
        }

        /// <summary>
        /// Handle character casing command which have an enum in private member
        /// </summary>
        /// <param name="command"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        private PersistentMacroCommand HandleCommand (ChangeCharacterCasingCommand command, Type type)
        {
            // local variables
            PersistentCasingMacroCommand macro;
            string enumvalue = "";
            
            // get the field info items from the type
            FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
            foreach (FieldInfo field in fields)
            {
                if (field.FieldType == typeof(System.Enum))
                    enumvalue = field.GetValue(command).ToString();
            }

            // create the macro object
            macro = new PersistentCasingMacroCommand(type.FullName, enumvalue);
            return macro;
        }

        /// <summary>
        /// Handle uncomment commands which have a prefix private member
        /// </summary>
        /// <param name="command"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        private PersistentMacroCommand HandleCommand (UncommentLinesCommand command, Type type)
        {
            // local variables
            PersistentCommentMacroCommand macro;
            string prefix = "--";
            
            // get the field info items from the type
            FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
            foreach (FieldInfo field in fields)
            {
                if (field.FieldType == typeof(System.String))
                    prefix = field.GetValue(command).ToString();
            }

            // create the macro object
            macro = new PersistentCommentMacroCommand(type.FullName, prefix);
            return macro;
        }

        /// <summary>
        /// Handle comment lines which have a prefix private member
        /// </summary>
        /// <param name="command"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        private PersistentMacroCommand HandleCommand (CommentLinesCommand command, Type type)
        {
            // local variables
            PersistentCommentMacroCommand macro;
            string prefix = "--";
            
            // get the field info items from the type
            FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
            foreach (FieldInfo field in fields)
            {
                if (field.FieldType == typeof(System.String))
                    prefix = field.GetValue(command).ToString();
            }

            // create the macro object
            macro = new PersistentCommentMacroCommand(type.FullName, prefix);
            return macro;
        }

        /// <summary>
        /// Handle typing commands which have char and bool private members
        /// </summary>
        /// <param name="command"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        private PersistentMacroCommand HandleCommand (TypingCommand command, Type type)
        {
            // local variables
            PersistentTypingMacroCommand macro;
            char cChar = (char)0;
            bool bOverwrite = false;
            
            // get the field info items from the type
            FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
            foreach (FieldInfo field in fields)
            {
                if (field.FieldType == typeof(System.Char))
                    cChar = (char)field.GetValue(command);
                else if (field.FieldType == typeof(System.Boolean))
                    bOverwrite = (bool)field.GetValue(command);
            }

            // create the macro object
            macro = new PersistentTypingMacroCommand(type.FullName, cChar, bOverwrite);
            return macro;
        }

        /// <summary>
        /// Serialize the array list
        /// </summary>
        /// <param name="info"></param>
        /// <param name="context"></param>
        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("MacroCommand", this.m_CmdList);
            
        }
    }

    [Serializable]
    public class PersistentMacroCommand
    {
        private string m_sCommandName;        

        public PersistentMacroCommand (string commandName) {this.m_sCommandName = commandName;}

        public string CommandName {get {return this.m_sCommandName;}}
    }

    [Serializable]
    public class PersistentTypingMacroCommand : PersistentMacroCommand
    {
        private char m_cChar;
        private bool m_bOverwrite;

        public PersistentTypingMacroCommand (string commandName, char character, bool overwrite) : base(commandName)
        {this.m_cChar = character; this.m_bOverwrite = overwrite;}

        public char Charactere {get {return this.m_cChar;}}
        public bool Overwrite {get {return this.m_bOverwrite;}}
    }

    [Serializable]
    public class PersistentCommentMacroCommand : PersistentMacroCommand
    {
        private string m_sPrefix;

        public PersistentCommentMacroCommand (string commandName, string prefix) : base(commandName)
        {this.m_sPrefix = prefix;}

        public string Prefix {get {return this.m_sPrefix;}}
    }

    [Serializable]
    public class PersistentCasingMacroCommand : PersistentMacroCommand
    {
        private string m_sEnum;

        public PersistentCasingMacroCommand (string commandName, string enumValue) : base(commandName)
        {this.m_sEnum = enumValue;}

        public string EnumValue {get {return this.m_sEnum;}}
    }

// This code is release under the "I RULE" License
// You may use this code provide you admit I rule if 
// you ever meet me in person :)
If anyone has any improvements or implements the Paste command, please repost.

Thanks,

Ashton

[Modified at 04/27/2005 06:48 AM]

Comments (2)

Posted 19 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Well the good news is that we're adding ReadFromXml and WriteToXml methods to EditCommand. By calling these methods on MacroCommand you can serialize and deserialize an entire macro of commands. This loads any child command of the macro, including pastes, comments, etc.

By default, the ReadFromXml and WriteToXml methods in EditCommand do nothing. For a special command like CommentLinesCommand, it overrides the WriteToXml to write out a CommentText attribute. ReadToXml in turn, reads in that attribute.

So this makes it fairly easy to read/write to XML.


Actipro Software Support

Posted 19 years ago by Ashton - Developer, Schema Solutions LLC
Avatar
w00t!!!!

Now I don't have to use reflection to access all the private variables of the command classes.

Now that I can save off macros so I can persist them and load them back at each app, the macro feature is really a great new feature.

A.
The latest build of this product (v24.1.0) was released 2 months ago, which was after the last post in this thread.

Add Comment

Please log in to a validated account to post comments.