Esempio n. 1
0
        public static string GetFileName(this DocDataTextReader reader)
        {
            var value = typeof(DocDataTextReader).GetProperty("DocData", BindingFlags.Instance | BindingFlags.NonPublic)
                        .GetValue(reader) as DocData;

            return(value.Name);
        }
Esempio n. 2
0
        public static string GetDesignerFileName(this DocDataTextReader reader)
        {
            var fileName = reader.GetFileName();

            var index = fileName.LastIndexOf('.');

            return(fileName.Insert(index + 1, "Designer."));
        }
Esempio n. 3
0
        public override CodeCompileUnit Parse(TextReader codeStream)
        {
            CodeCompileUnit compileUnit = null;
            //
            string mainFilePath = GetFilePath();

            // Are we are from the Designer ?
            if (codeStream is DocDataTextReader)
            {
                this.FileName = mainFilePath;
                // Do the parse
                // If the TextReader is a DocDataTextReader, we should be running from VisualStudio, called by the designer
                // So, we will guess the FileName to check if we have a .Designer.Prg file at the same place.
                // If so, we will have to handle both .prg to produce two CodeCompileUnit, then we will merge the result into one, with markers in it
                // so we can split again when the Designer is willing to save. ( See GenerateCodeFromCompileUnit )
                if (codeStream is DocDataTextReader)
                {
                    // Anyway, we have that source, just parse it.
                    compileUnit = base.Parse(codeStream);
                    // Now, we should check if we have a partial Class inside, if so, that's a Candidate for .Designer.prg
                    CodeNamespace       nameSpace;
                    CodeTypeDeclaration className;
                    if (XSharpCodeDomHelper.HasPartialClass(compileUnit, out nameSpace, out className))
                    {
                        // Ok, so get the Filename, to get the .Designer.prg
                        DocDataTextReader ddtr        = codeStream as DocDataTextReader;
                        DocData           dd          = ((IServiceProvider)ddtr).GetService(typeof(DocData)) as DocData;
                        String            prgFileName = dd.Name;
                        // Build the Designer FileName
                        String designerPrgFile = XSharpCodeDomHelper.BuildDesignerFileName(prgFileName);
                        if (!String.IsNullOrEmpty(designerPrgFile) && File.Exists(designerPrgFile))
                        {
                            // Ok, we have a candidate !!!
                            DocData           docdata = new DocData((IServiceProvider)ddtr, designerPrgFile);
                            DocDataTextReader reader  = new DocDataTextReader(docdata);
                            // so parse
                            CodeCompileUnit designerCompileUnit = base.Parse(reader);
                            CodeCompileUnit mergedCompileUnit   = null;
                            // Now we have Two CodeCompileUnit, we must merge them
                            mergedCompileUnit = XSharpCodeDomHelper.MergeCodeCompileUnit(compileUnit, designerCompileUnit);
                            mergedCompileUnit.UserData[XSharpCodeConstants.USERDATA_HASDESIGNER] = true;
                            mergedCompileUnit.UserData[XSharpCodeConstants.USERDATA_FILENAME]    = prgFileName;
                            // Save CCU for GenerateCode operation, it will be faster and easier than to recreate it
                            mergedCompileUnit.UserData[XSharpCodeConstants.USERDATA_CCU_FORM]     = compileUnit;
                            mergedCompileUnit.UserData[XSharpCodeConstants.USERDATA_CCU_DESIGNER] = designerCompileUnit;
                            return(mergedCompileUnit);
                        }
                    }
                }
                else
                {
                    compileUnit = base.Parse(codeStream);
                }
            }
            //
            return(compileUnit);
        }
        public override CodeCompileUnit Parse(TextReader codeStream)
        {
            //
            string mainFilePath = GetFilePath();
            // Are we are from the Designer ?
            var ddtr = codeStream as DocDataTextReader;

            if (ddtr != null)
            {
                this.FileName = mainFilePath;
                // Do the parse
                // If the TextReader is a DocDataTextReader, we should be running from VisualStudio, called by the designer
                // So, we will guess the FileName to check if we have a .Designer.boo file at the same place.
                // If so, we will have to build both .boo files to produce the CodeCompileUnit
                // Now, we should check if we have a partial Class inside, if so, that's a Candidate for .Designer.boo
                // Ok, so get the Filename, to get the companion file
                var    dd         = ((IServiceProvider)ddtr).GetService(typeof(DocData)) as DocData;
                String ddFileName = dd.Name;
                // Build the Designer FileName
                var    baseIsDesignForm = ddFileName.EndsWith(".Designer.boo");
                String companionFile    = baseIsDesignForm
                    ? BooCodeDomHelper.BuildNonDesignerFileName(ddFileName)
                    : BooCodeDomHelper.BuildDesignerFileName(ddFileName);
                if (File.Exists(companionFile))
                {
                    // Ok, we have a candidate !!!
                    DocData           docdata = new DocData(ddtr, companionFile);
                    DocDataTextReader reader  = new DocDataTextReader(docdata);
                    // so parse
                    var result = base.Parse(new TextReader[] { codeStream, reader }, new[] { ddFileName, companionFile });
                    BooCodeDomHelper.AnnotateCompileUnit(result);
                    result.UserData[BooCodeDomHelper.USERDATA_HASDESIGNER] = true;
                    result.UserData[BooCodeDomHelper.USERDATA_FILENAME]    = ddFileName;
                    return(result);
                }
            }
            return(base.Parse(codeStream));
        }
        public override CodeCompileUnit Parse(TextReader codeStream)
        {
            CodeCompileUnit compileUnit = null;
            //
            string mainFilePath = GetFilePath();
            // Are we are from the Designer ?
            if (codeStream is DocDataTextReader)
            {
                this.FileName = mainFilePath;
                // Do the parse
#if DESIGNERSUPPORT
                // If the TextReader is a DocDataTextReader, we should be running from VisualStudio, called by the designer
                // So, we will guess the FileName to check if we have a .Designer.Prg file at the same place.
                // If so, we will have to handle both .prg to produce two CodeCompileUnit, then we will merge the result into one, with markers in it
                // so we can split again when the Designer is willing to save. ( See GenerateCodeFromCompileUnit )
                if (codeStream is DocDataTextReader)
                {
                    // Anyway, we have that source, just parse it.
                    compileUnit = base.Parse(codeStream);
                    // Now, we should check if we have a partial Class inside, if so, that's a Candidate for .Designer.prg
                    CodeNamespace nameSpace;
                    CodeTypeDeclaration className;
                    if (XSharpCodeDomHelper.HasPartialClass(compileUnit, out nameSpace, out className))
                    {
                        // Ok, so get the Filename, to get the .Designer.prg
                        DocDataTextReader ddtr = codeStream as DocDataTextReader;
                        DocData dd = ((IServiceProvider)ddtr).GetService(typeof(DocData)) as DocData;
                        String prgFileName = dd.Name;
                        // Build the Designer FileName
                        String designerPrgFile = XSharpCodeDomHelper.BuildDesignerFileName(prgFileName);
                        if (File.Exists(designerPrgFile))
                        {
                            // Ok, we have a candidate !!!
                            DocData docdata = new DocData((IServiceProvider)ddtr, designerPrgFile);
                            DocDataTextReader reader = new DocDataTextReader(docdata);
                            // so parse
                            CodeCompileUnit designerCompileUnit = base.Parse(reader);
                            CodeCompileUnit mergedCompileUnit = null;
                            // Now we have Two CodeCompileUnit, we must merge them
                            mergedCompileUnit = XSharpCodeDomHelper.MergeCodeCompileUnit(compileUnit, designerCompileUnit);
                            mergedCompileUnit.UserData[XSharpCodeConstants.USERDATA_HASDESIGNER] = true;
                            mergedCompileUnit.UserData[XSharpCodeConstants.USERDATA_FILENAME] = prgFileName;
                            // Save CCU for GenerateCode operation, it will be faster and easier than to recreate it
                            mergedCompileUnit.UserData[XSharpCodeConstants.USERDATA_CCU_FORM] = compileUnit;
                            mergedCompileUnit.UserData[XSharpCodeConstants.USERDATA_CCU_DESIGNER] = designerCompileUnit;
                            return mergedCompileUnit;
                        }
                    }
                }
                else
#endif
                {
                    compileUnit = base.Parse(codeStream);
                }

            }
            //
            return compileUnit;
        }
        // Called by the WinForm designer at save time
        public override void GenerateCodeFromCompileUnit(CodeCompileUnit compileUnit, TextWriter writer, CodeGeneratorOptions options)
        {
#if DESIGNERSUPPORT
            // Does that CodeCompileUnit comes from a "Merged" unit ?
            if (compileUnit.UserData.Contains(XSharpCodeConstants.USERDATA_HASDESIGNER))
            {
                // Retrieve the Form Class
                CodeTypeDeclaration designerClass = XSharpCodeDomHelper.FindDesignerClass(compileUnit);
                // and retrieve the filename of the prg file
                String prgFileName = (string)compileUnit.UserData[XSharpCodeConstants.USERDATA_FILENAME];
                // Build the Designer FileName
                String designerPrgFile = XSharpCodeDomHelper.BuildDesignerFileName(prgFileName);
                // Retrieve Both CodeCompileUnit
                CodeCompileUnit formCCU = (CodeCompileUnit)compileUnit.UserData[XSharpCodeConstants.USERDATA_CCU_FORM];
                CodeCompileUnit designCCU = (CodeCompileUnit)compileUnit.UserData[XSharpCodeConstants.USERDATA_CCU_DESIGNER];
                // suppress generating the "generated code" header in the form.prg
                formCCU.UserData[XSharpCodeConstants.USERDATA_NOHEADER] = true;
                //
                CodeTypeDeclaration formClass = XSharpCodeDomHelper.FindFirstClass(formCCU);
                CodeTypeDeclaration designClass = XSharpCodeDomHelper.FindFirstClass(designCCU);
                // Now, remove the members
                formClass.Members.Clear();
                designClass.Members.Clear();
                // Now, split the members
                foreach (CodeTypeMember ctm in designerClass.Members)
                {
                    // Was it a member that we have found in the original merged CodeCompileUnits ?
                    if (ctm.UserData.Contains(XSharpCodeConstants.USERDATA_FROMDESIGNER))
                    {
                        if ((bool)ctm.UserData[XSharpCodeConstants.USERDATA_FROMDESIGNER])
                        {
                            // Comes from the Designer.prg file
                            // so go back to Designer.prg
                            designClass.Members.Add(ctm);
                        }
                        else
                        {
                            // Comes from the original Form file
                            formClass.Members.Add(ctm);
                        }
                    }
                    else
                    {
                        // This must be a member generated by the Designer !
                        // So we will move Methods to the Form and all others to the Designer
                        if (ctm is CodeMemberMethod)
                        {
                            formClass.Members.Add(ctm);
                        }
                        else
                        {
                            designClass.Members.Add(ctm);
                        }
                    }
                }
                // now, we must save both CodeCompileUnit
                // The received TextWriter is pointing to the Form
                // so we must create our own TextWriter for the Designer
                // First, let's make in Memory
                String generatedSource;
                MemoryStream inMemory = new MemoryStream();
                StreamWriter designerStream = new StreamWriter(inMemory, Encoding.UTF8);
                // 
                base.GenerateCodeFromCompileUnit(designCCU, designerStream, options);
                // and force Flush
                designerStream.Flush();
                // Reset and read to String
                inMemory.Position = 0;
                StreamReader reader = new StreamReader(inMemory, Encoding.UTF8, true);
                generatedSource = reader.ReadToEnd();
                Encoding realencoding = reader.CurrentEncoding;
                reader.Close();
                designerStream.Close();
                // and now write the "real" file
                designerStream = new StreamWriter(designerPrgFile, false, realencoding);
                designerStream.Write(generatedSource);
                designerStream.Flush();
                designerStream.Close();
                NormalizeLineEndings(designerPrgFile);
                // The problem here, is that we "may" have some new members, like EvenHandlers, and we need to update their position (line/col)
                XSharpCodeParser parser = new XSharpCodeParser();
                parser.TabSize = XSharpCodeDomProvider.TabSize;
                parser.FileName = designerPrgFile;
                CodeCompileUnit resultDesigner = parser.Parse(generatedSource);
                CodeTypeDeclaration resultClass = XSharpCodeDomHelper.FindDesignerClass(resultDesigner);
                // just to be sure...
                if (resultClass != null)
                {
                    // Now push all elements from resultClass to designClass
                    designClass.Members.Clear();
                    foreach (CodeTypeMember ctm in resultClass.Members)
                    {
                        ctm.UserData[XSharpCodeConstants.USERDATA_FROMDESIGNER] = true;
                        designClass.Members.Add(ctm);
                    }
                }
                // Ok,we MUST do the same thing for the Form file
                base.GenerateCodeFromCompileUnit(formCCU, writer, options);
                // BUT, the writer is hold by the Form Designer, don't close  it !!
                writer.Flush();
                NormalizeLineEndings(prgFileName);
                // Now, we must re-read it and parse again
                IServiceProvider provider = (DocDataTextWriter)writer;
                DocData docData = (DocData)provider.GetService(typeof(DocData));
                DocDataTextReader ddtr = new DocDataTextReader(docData);
                // Retrieve 
                generatedSource = ddtr.ReadToEnd();
                // normalize the line endings
                generatedSource = generatedSource.Replace("\n", "");
                generatedSource = generatedSource.Replace("\r", "\r\n");
                // Don't forget to set the name of the file where the source is... 
                parser.FileName = prgFileName;
                resultDesigner = parser.Parse(generatedSource);
                resultClass = XSharpCodeDomHelper.FindFirstClass(resultDesigner);
                // just to be sure...
                if (resultClass != null)
                {
                    // Now push all elements from resultClass to formClass
                    formClass.Members.Clear();
                    foreach (CodeTypeMember ctm in resultClass.Members)
                    {
                        ctm.UserData[XSharpCodeConstants.USERDATA_FROMDESIGNER] = false;
                        formClass.Members.Add(ctm);
                    }
                }
                // Ok, it should be ok....
                // We have updated the file and the types that are stored inside each CCU that have been merged in compileUnit
                //XSharpCodeDomHelper.MergeCodeCompileUnit(compileUnit, formCCU, designCCU);
                // And update...
                designerClass.Members.Clear();
                foreach (CodeTypeMember m in designClass.Members)
                {
                    designerClass.Members.Add(m);
                }
                foreach (CodeTypeMember m in formClass.Members)
                {
                    designerClass.Members.Add(m);
                }
            }
            else
#endif
            {
                // suppress generating the "generated code" header
                compileUnit.UserData[XSharpCodeConstants.USERDATA_NOHEADER] = true;
                base.GenerateCodeFromCompileUnit(compileUnit, writer, options);
                writer.Flush();
                // Designer gave us these informations
                CodeTypeDeclaration formClass = XSharpCodeDomHelper.FindFirstClass(compileUnit);
                // Now, we must re-read it and parse again
                IServiceProvider provider = (DocDataTextWriter)writer;
                DocData docData = (DocData)provider.GetService(typeof(DocData));
                DocDataTextReader ddtr = new DocDataTextReader(docData);
                // Retrieve 
                string generatedSource = ddtr.ReadToEnd();
                XSharpCodeParser parser = new XSharpCodeParser();
                parser.TabSize = XSharpCodeDomProvider.TabSize;
                if (compileUnit.UserData.Contains(XSharpCodeConstants.USERDATA_FILENAME))
                {
                    parser.FileName = (string)compileUnit.UserData[XSharpCodeConstants.USERDATA_FILENAME];
                }
                CodeCompileUnit resultCcu = parser.Parse(generatedSource);
                CodeTypeDeclaration resultClass = XSharpCodeDomHelper.FindFirstClass(resultCcu);
                // just to be sure...
                if (resultClass != null)
                {
                    // Now push all elements from resultClass to formClass
                    formClass.Members.Clear();
                    foreach (CodeTypeMember ctm in resultClass.Members)
                    {
                        formClass.Members.Add(ctm);
                    }
                }

            }
        }
        // Called by the WinForms designer at save time
        public override void GenerateCodeFromCompileUnit(CodeCompileUnit compileUnit, TextWriter writer, CodeGeneratorOptions options)
        {
            // Does that CodeCompileUnit comes from a "Merged" unit ?
            if (compileUnit.UserData.Contains(BooCodeDomHelper.USERDATA_HASDESIGNER))
            {
                // Retrieve the Form Class
                CodeTypeDeclaration designerClass = BooCodeDomHelper.LimitToDesignerClass(compileUnit);
                // and retrieve the filename of the prg file
                String prgFileName = (string)compileUnit.UserData[BooCodeDomHelper.USERDATA_FILENAME];
                // Build the Designer FileName
                String designerPrgFile = BooCodeDomHelper.BuildDesignerFileName(prgFileName);
                var    newMethods      = new List <CodeMemberMethod>();
                //
                // Retrieve Both CodeCompileUnit
                // Now, split the members
                foreach (CodeTypeMember ctm in designerClass.Members.Cast <CodeTypeMember>().ToArray())
                {
                    var li = ctm.UserData["LexicalInfo"] as LexicalInfo;
                    // Was it a member that we have found in the original code ?
                    if (li != null)
                    {
                        if (!li.FileName.Equals(designerPrgFile))
                        {
                            //This was in the form file
                            designerClass.Members.Remove(ctm);
                        }
                    }
                    else
                    {
                        // This must be a member generated by the Designer !
                        // So we will move Methods to the Form and all others to the Designer
                        var cmm = ctm as CodeMemberMethod;
                        if (cmm != null)
                        {
                            newMethods.Add(cmm);
                            designerClass.Members.Remove(cmm);
                        }
                    }
                }
                if (newMethods.Count > 0)
                {
                    WriteNewMethods(newMethods, designerPrgFile, designerClass.Name);
                }
                // now, we must save both CodeCompileUnit
                // The received TextWriter is pointing to the Form
                // so we must create our own TextWriter for the Designer
                // First, let's make in Memory
                String       generatedSource;
                MemoryStream inMemory       = new MemoryStream();
                StreamWriter designerStream = new StreamWriter(inMemory, Encoding.UTF8);
                //
                base.GenerateCodeFromCompileUnit(compileUnit, designerStream, options);
                // and force Flush
                designerStream.Flush();
                // Reset and read to String
                inMemory.Position = 0;
                StreamReader reader = new StreamReader(inMemory, Encoding.UTF8, true);
                generatedSource = reader.ReadToEnd();
                Encoding realencoding = reader.CurrentEncoding;
                reader.Close();
                designerStream.Close();
                // and now write the "real" file
                designerStream = new StreamWriter(designerPrgFile, false, realencoding);
                designerStream.Write(generatedSource);
                designerStream.Flush();
                designerStream.Close();
                NormalizeLineEndings(designerPrgFile);

                /*
                 * // The problem here, is that we "may" have some new members, like EvenHandlers, and we need to update their position (line/col)
                 * var parser = CreateParser();
                 * //                parser.TabSize = provider.TabSize;
                 * //                parser.FileName = designerPrgFile;
                 * CodeCompileUnit resultDesigner = parser.Parse(new StringReader(generatedSource));
                 * CodeTypeDeclaration resultClass = BooCodeDomHelper.FindDesignerClass(resultDesigner);
                 * // just to be sure...
                 * if (resultClass != null)
                 * {
                 *  // Now push all elements from resultClass to designClass
                 *  designClass.Members.Clear();
                 *  foreach (CodeTypeMember ctm in resultClass.Members)
                 *  {
                 *      ctm.UserData[BooCodeDomHelper.USERDATA_FROMDESIGNER] = true;
                 *      designClass.Members.Add(ctm);
                 *  }
                 * }
                 * // Ok,we MUST do the same thing for the Form file
                 * base.GenerateCodeFromCompileUnit(formCCU, writer, options);
                 * // BUT, the writer is hold by the Form Designer, don't close  it !!
                 * writer.Flush();
                 * NormalizeLineEndings(prgFileName);
                 * // Now, we must re-read it and parse again
                 * IServiceProvider provider = (DocDataTextWriter)writer;
                 * DocData docData = (DocData)provider.GetService(typeof(DocData));
                 * DocDataTextReader ddtr = new DocDataTextReader(docData);
                 * // Retrieve
                 * generatedSource = ddtr.ReadToEnd();
                 * // normalize the line endings
                 * generatedSource = generatedSource.Replace("\n", "");
                 * generatedSource = generatedSource.Replace("\r", "\r\n");
                 * // Don't forget to set the name of the file where the source is...
                 * resultDesigner = parser.Parse(new StringReader(generatedSource));
                 * resultClass = BooCodeDomHelper.FindFirstClass(resultDesigner);
                 * // just to be sure...
                 * if (resultClass != null)
                 * {
                 *  // Now push all elements from resultClass to formClass
                 *  formClass.Members.Clear();
                 *  foreach (CodeTypeMember ctm in resultClass.Members)
                 *  {
                 *      ctm.UserData[BooCodeDomHelper.USERDATA_FROMDESIGNER] = false;
                 *      formClass.Members.Add(ctm);
                 *  }
                 * }
                 * // Ok, it should be ok....
                 * // We have updated the file and the types that are stored inside each CCU that have been merged in compileUnit
                 * //BooCodeDomHelper.MergeCodeCompileUnit(compileUnit, formCCU, designCCU);
                 * // And update...
                 * designerClass.Members.Clear();
                 * foreach (CodeTypeMember m in designClass.Members)
                 * {
                 *  designerClass.Members.Add(m);
                 * }
                 * foreach (CodeTypeMember m in formClass.Members)
                 * {
                 *  designerClass.Members.Add(m);
                 * }
                 */
            }
            else
            {
                // suppress generating the "generated code" header
                compileUnit.UserData[BooCodeDomHelper.USERDATA_NOHEADER] = true;
                base.GenerateCodeFromCompileUnit(compileUnit, writer, options);
                writer.Flush();
                // Designer gave us these informations
                CodeTypeDeclaration formClass = BooCodeDomHelper.FindFirstClass(compileUnit);
                // Now, we must re-read it and parse again
                IServiceProvider  provider = (DocDataTextWriter)writer;
                DocData           docData  = (DocData)provider.GetService(typeof(DocData));
                DocDataTextReader ddtr     = new DocDataTextReader(docData);
                // Retrieve
                string generatedSource = ddtr.ReadToEnd();

                var                 parser      = CreateParser();
                CodeCompileUnit     resultCcu   = parser.Parse(new StringReader(generatedSource));
                CodeTypeDeclaration resultClass = BooCodeDomHelper.FindFirstClass(resultCcu);
                // just to be sure...
                if (resultClass != null)
                {
                    // Now push all elements from resultClass to formClass
                    formClass.Members.Clear();
                    foreach (CodeTypeMember ctm in resultClass.Members)
                    {
                        formClass.Members.Add(ctm);
                    }
                }
            }
        }
Esempio n. 8
0
        // Called by the WinForm designer at save time
        public override void GenerateCodeFromCompileUnit(CodeCompileUnit compileUnit, TextWriter writer, CodeGeneratorOptions options)
        {
            // Does that CodeCompileUnit comes from a "Merged" unit ?
            if (compileUnit.UserData.Contains(XSharpCodeConstants.USERDATA_HASDESIGNER))
            {
                // Retrieve the Form Class
                CodeTypeDeclaration designerClass = XSharpCodeDomHelper.FindDesignerClass(compileUnit);
                // and retrieve the filename of the prg file
                String prgFileName = (string)compileUnit.UserData[XSharpCodeConstants.USERDATA_FILENAME];
                // Build the Designer FileName
                String designerPrgFile = XSharpCodeDomHelper.BuildDesignerFileName(prgFileName);
                // Retrieve Both CodeCompileUnit
                CodeCompileUnit formCCU   = (CodeCompileUnit)compileUnit.UserData[XSharpCodeConstants.USERDATA_CCU_FORM];
                CodeCompileUnit designCCU = (CodeCompileUnit)compileUnit.UserData[XSharpCodeConstants.USERDATA_CCU_DESIGNER];
                // suppress generating the "generated code" header in the form.prg
                formCCU.UserData[XSharpCodeConstants.USERDATA_NOHEADER] = true;
                //
                CodeTypeDeclaration formClass   = XSharpCodeDomHelper.FindFirstClass(formCCU);
                CodeTypeDeclaration designClass = XSharpCodeDomHelper.FindFirstClass(designCCU);
                // Now, remove the members
                CopyClassProperties(designerClass, formClass);
                CopyClassProperties(designerClass, designClass);
                formClass.Members.Clear();
                designClass.Members.Clear();
                // Now, split the members
                foreach (CodeTypeMember ctm in designerClass.Members)
                {
                    // Was it a member that we have found in the original merged CodeCompileUnits ?
                    if (ctm.UserData.Contains(XSharpCodeConstants.USERDATA_FROMDESIGNER))
                    {
                        if ((bool)ctm.UserData[XSharpCodeConstants.USERDATA_FROMDESIGNER])
                        {
                            // Comes from the Designer.prg file
                            // so go back to Designer.prg
                            designClass.Members.Add(ctm);
                        }
                        else
                        {
                            // Comes from the original Form file
                            formClass.Members.Add(ctm);
                        }
                    }
                    else
                    {
                        // This must be a member generated by the Designer !
                        // So we will move Methods to the Form and all others to the Designer
                        if (ctm is CodeMemberMethod)
                        {
                            formClass.Members.Add(ctm);
                        }
                        else
                        {
                            designClass.Members.Add(ctm);
                        }
                    }
                }
                // now, we must save both CodeCompileUnit
                // The received TextWriter is pointing to the Form
                // so we must create our own TextWriter for the Designer
                // First, let's make in Memory
                String       generatedSource;
                MemoryStream inMemory       = new MemoryStream();
                StreamWriter designerStream = new StreamWriter(inMemory, Encoding.UTF8);
                //
                base.GenerateCodeFromCompileUnit(designCCU, designerStream, options);
                // and force Flush
                designerStream.Flush();
                // Reset and read to String
                inMemory.Position = 0;
                StreamReader reader = new StreamReader(inMemory, Encoding.UTF8, true);
                generatedSource = reader.ReadToEnd();
                Encoding realencoding = reader.CurrentEncoding;
                reader.Close();
                designerStream.Close();

                XSharpFileNode node = _fileNode.FindChild(designerPrgFile) as XSharpFileNode;
                bool           done = false;
                if (node != null)
                {
                    // assign the source to the open buffer when possible
                    if (node.DocumentSetText(generatedSource))
                    {
                        // then use automation to save the file, because that is much easier
                        // since we do not have to worry about the docdata etc.
                        var oaFile = (OAXSharpFileItem)node.GetAutomationObject();
                        oaFile.Save(designerPrgFile);
                        done = true;
                    }
                }
                if (!done)
                {
                    // File is not open in editor, so write to disk
                    designerStream = new StreamWriter(designerPrgFile, false, realencoding);
                    designerStream.Write(generatedSource);
                    designerStream.Flush();
                    designerStream.Close();
                    NormalizeLineEndings(designerPrgFile);
                }
                // The problem here, is that we "may" have some new members, like EvenHandlers, and we need to update their position (line/col)
                XSharpCodeParser parser = new XSharpCodeParser(_projectNode);
                parser.TabSize  = XSharpCodeDomProvider.TabSize;
                parser.FileName = designerPrgFile;
                CodeCompileUnit     resultDesigner = parser.Parse(generatedSource);
                CodeTypeDeclaration resultClass    = XSharpCodeDomHelper.FindDesignerClass(resultDesigner);
                // just to be sure...
                if (resultClass != null)
                {
                    // Now push all elements from resultClass to designClass
                    designClass.Members.Clear();
                    foreach (CodeTypeMember ctm in resultClass.Members)
                    {
                        ctm.UserData[XSharpCodeConstants.USERDATA_FROMDESIGNER] = true;
                        designClass.Members.Add(ctm);
                    }
                }
                // Ok,we MUST do the same thing for the Form file
                base.GenerateCodeFromCompileUnit(formCCU, writer, options);
                // BUT, the writer is hold by the Form Designer, don't close  it !!
                writer.Flush();
                NormalizeLineEndings(prgFileName);
                // Now, we must re-read it and parse again
                IServiceProvider  provider = (DocDataTextWriter)writer;
                DocData           docData  = (DocData)provider.GetService(typeof(DocData));
                DocDataTextReader ddtr     = new DocDataTextReader(docData);
                // Retrieve
                generatedSource = ddtr.ReadToEnd();
                // normalize the line endings
                generatedSource = generatedSource.Replace("\n", "");
                generatedSource = generatedSource.Replace("\r", "\r\n");
                // Don't forget to set the name of the file where the source is...
                parser.FileName = prgFileName;
                resultDesigner  = parser.Parse(generatedSource);
                resultClass     = XSharpCodeDomHelper.FindFirstClass(resultDesigner);
                // just to be sure...
                if (resultClass != null)
                {
                    // Now push all elements from resultClass to formClass
                    formClass.Members.Clear();
                    foreach (CodeTypeMember ctm in resultClass.Members)
                    {
                        ctm.UserData[XSharpCodeConstants.USERDATA_FROMDESIGNER] = false;
                        formClass.Members.Add(ctm);
                    }
                }
                // Ok, it should be ok....
                // We have updated the file and the types that are stored inside each CCU that have been merged in compileUnit
                //XSharpCodeDomHelper.MergeCodeCompileUnit(compileUnit, formCCU, designCCU);
                // And update...
                designerClass.Members.Clear();
                foreach (CodeTypeMember m in designClass.Members)
                {
                    designerClass.Members.Add(m);
                }
                foreach (CodeTypeMember m in formClass.Members)
                {
                    designerClass.Members.Add(m);
                }
            }
            else
            {
                // suppress generating the "generated code" header
                if (writer is  DocDataTextWriter)       // Form Editor
                {
                    compileUnit.UserData[XSharpCodeConstants.USERDATA_NOHEADER] = true;
                }
                base.GenerateCodeFromCompileUnit(compileUnit, writer, options);
                writer.Flush();
                // Designer gave us these informations
                // Now, we must re-read it and parse again
                if (writer is DocDataTextWriter)
                {
                    CodeTypeDeclaration formClass = XSharpCodeDomHelper.FindFirstClass(compileUnit);
                    IServiceProvider    provider  = (DocDataTextWriter)writer;
                    DocData             docData   = (DocData)provider.GetService(typeof(DocData));
                    DocDataTextReader   ddtr      = new DocDataTextReader(docData);
                    // Retrieve
                    string           generatedSource = ddtr.ReadToEnd();
                    XSharpCodeParser parser          = new XSharpCodeParser(_projectNode);
                    parser.TabSize = XSharpCodeDomProvider.TabSize;
                    if (compileUnit.UserData.Contains(XSharpCodeConstants.USERDATA_FILENAME))
                    {
                        parser.FileName = (string)compileUnit.UserData[XSharpCodeConstants.USERDATA_FILENAME];
                    }
                    CodeCompileUnit     resultCcu   = parser.Parse(generatedSource);
                    CodeTypeDeclaration resultClass = XSharpCodeDomHelper.FindFirstClass(resultCcu);
                    // just to be sure...
                    if (resultClass != null)
                    {
                        // Now push all elements from resultClass to formClass
                        formClass.Members.Clear();
                        foreach (CodeTypeMember ctm in resultClass.Members)
                        {
                            formClass.Members.Add(ctm);
                        }
                    }
                }
            }
        }
        public override CodeCompileUnit Parse(TextReader codeStream)
        {
            XCodeCompileUnit compileUnit = null;
            //
            string mainFilePath = GetFilePath();

            // Are we are from the Designer ?
            if (codeStream is DocDataTextReader)
            {
                this.FileName = mainFilePath;
                // Do the parse
                // If the TextReader is a DocDataTextReader, we should be running from VisualStudio, called by the designer
                // So, we will guess the FileName to check if we have a .Designer.Prg file at the same place.
                // If so, we will have to handle both .prg to produce two CodeCompileUnit, then we will merge the result into one, with markers in it
                // so we can split again when the Designer is willing to save. ( See GenerateCodeFromCompileUnit )
                if (codeStream is DocDataTextReader)
                {
                    // Anyway, we have that source, just parse it.

                    WriteOutputMessage("Start Parse " + this.FileName);
                    compileUnit = ToXCodeCompileUnit(base.Parse(codeStream));
                    WriteOutputMessage("End Parse " + this.FileName);
                    // Now, we should check if we have a partial Class inside, if so, that's a Candidate for .Designer.prg
                    CodeNamespace       nameSpace;
                    CodeTypeDeclaration className;
                    if (XSharpCodeDomHelper.HasPartialClass(compileUnit, out nameSpace, out className))
                    {
                        // Ok, so get the Filename, to get the .Designer.prg
                        DocDataTextReader ddtr = codeStream as DocDataTextReader;
                        DocData           dd   = ((IServiceProvider)ddtr).GetService(typeof(DocData)) as DocData;
                        Assumes.Present(dd);
                        string prgFileName = dd.Name;
                        // Build the Designer FileName
                        string designerPrgFile = XSharpCodeDomHelper.BuildDesignerFileName(prgFileName);
                        if (!string.IsNullOrEmpty(designerPrgFile) && File.Exists(designerPrgFile))
                        {
                            // Ok, we have a candidate !!!
                            DocData           docdata = new DocData(ddtr, designerPrgFile);
                            DocDataTextReader reader  = new XDocDataTextReader(docdata, className);
                            // so parse
                            WriteOutputMessage("Start Parse " + designerPrgFile);
                            var designerCompileUnit = ToXCodeCompileUnit(base.Parse(reader));
                            designerCompileUnit.FileName = designerPrgFile;
                            WriteOutputMessage("End Parse " + designerPrgFile);
                            // Now we have Two CodeCompileUnit, we must merge them
                            WriteOutputMessage("Start merge compile Units " + this.FileName);
                            var mergedCompileUnit = XSharpCodeDomHelper.MergeCodeCompileUnit(compileUnit, designerCompileUnit);
                            WriteOutputMessage("End merge compile Units " + this.FileName);
                            return(mergedCompileUnit);
                        }
                    }
                }
                else
                {
                    var unit = base.Parse(codeStream);
                    if (unit is XCodeCompileUnit xccu)
                    {
                        compileUnit = xccu;
                    }
                    else
                    {
                        compileUnit = new XCodeCompileUnit(unit);
                    }
                }
            }
            //
            return(compileUnit);
        }
        // Called by the WinForm designer at save time
        public override void GenerateCodeFromCompileUnit(CodeCompileUnit compileUnit, TextWriter writer, CodeGeneratorOptions options)
        {
            // Does that CodeCompileUnit comes from a "Merged" unit ?
            if (compileUnit is XMergedCodeCompileUnit mergedUnit)
            {
                // Retrieve the Form Class
                CodeTypeDeclaration combinedClass = XSharpCodeDomHelper.FindDesignerClass(compileUnit);
                // and retrieve the filename of the prg file
                string prgFileName = mergedUnit.FileName;
                // Build the Designer FileName
                // Retrieve Both CodeCompileUnit
                var    formCCU         = mergedUnit.FormUnit;
                var    designCCU       = mergedUnit.DesignerUnit;
                string designerPrgFile = designCCU.FileName;
                var    formMembers     = new CodeTypeMemberCollection(formCCU.Members);
                foreach (CodeTypeMember m in formMembers)
                {
                    m.SetWritten(false);
                }
                // suppress generating the "generated code" header in the form.prg
                formCCU.GenerateHeader = false;

                CodeTypeDeclaration formClass   = formCCU.GetFirstClass();
                CodeTypeDeclaration designClass = designCCU.GetFirstClass();
                // Now, remove the members
                CopyClassProperties(combinedClass, formClass);
                CopyClassProperties(combinedClass, designClass);
                combinedClass.IsPartial = true;
                formClass.Members.Clear();
                designClass.Members.Clear();
                // Now, split the members
                // And make sure no members are deleted
                foreach (CodeTypeMember ctm in combinedClass.Members)
                {
                    // Was it a member that we have found in the original merged CodeCompileUnits ?
                    if (ctm is IXCodeObject xco)
                    {
                        if (ctm.GetFromDesigner())
                        {
                            // Comes from the Designer.prg file
                            // so go back to Designer.prg
                            designClass.Members.Add(ctm);
                            ctm.SetWritten(true);
                        }
                        else
                        {
                            // Comes from the original Form file
                            formClass.Members.Add(ctm);
                            foreach (CodeTypeMember member in formMembers)
                            {
                                if (member == ctm)
                                {
                                    member.SetWritten(true);
                                    formMembers.Remove(member);
                                    break;
                                }
                            }
                        }
                    }
                    else
                    {
                        // This must be a member generated by the Designer !
                        // So we will move Methods to the Form and all others to the Designer
                        if (ctm is CodeMemberMethod)
                        {
                            formClass.Members.Add(ctm);
                            ctm.SetWritten(true);
                        }
                        else
                        {
                            designClass.Members.Add(ctm);
                            ctm.SetWritten(true);
                        }
                    }
                }

                // Check for members that are not written
                foreach (CodeTypeMember member in formMembers)
                {
                    if (!member.WasWritten())
                    {
                        formClass.Members.Add(member);
                    }
                }

                // now, we must save both CodeCompileUnit
                // The received TextWriter is pointing to the Form
                // so we must create our own TextWriter for the Designer
                // First, let's make in Memory
                String       generatedSource;
                MemoryStream inMemory       = new MemoryStream();
                StreamWriter designerStream = new StreamWriter(inMemory, Encoding.UTF8);
                //
                // Backup original Form file and Form.Designer file
                //
                if (XSharpModel.XSettings.FormEditorMakeBackupFiles)
                {
                    if (File.Exists(prgFileName))
                    {
                        var bak = Path.ChangeExtension(prgFileName, ".bak");
                        Utilities.CopyFileSafe(prgFileName, bak);
                    }
                    if (File.Exists(designerPrgFile))
                    {
                        var bak = Path.ChangeExtension(designerPrgFile, ".bak");
                        Utilities.CopyFileSafe(designerPrgFile, bak);
                    }
                }

                base.GenerateCodeFromCompileUnit(designCCU, designerStream, options);
                // and force Flush
                designerStream.Flush();
                // Reset and read to String
                inMemory.Position = 0;
                StreamReader reader = new StreamReader(inMemory, Encoding.UTF8, true);
                generatedSource = reader.ReadToEnd();
                generatedSource = this._projectNode.SynchronizeKeywordCase(generatedSource, prgFileName);
                Encoding realencoding = reader.CurrentEncoding;
                reader.Close();
                designerStream.Close();

                XSharpFileNode node = _fileNode.FindChild(designerPrgFile) as XSharpFileNode;
                bool           done = false;
                if (node != null)
                {
                    // assign the source to the open buffer when possible
                    if (node.DocumentSetText(generatedSource))
                    {
                        // then use automation to save the file, because that is much easier
                        // since we do not have to worry about the docdata etc.
                        var oaFile = (OAXSharpFileItem)node.GetAutomationObject();
                        oaFile.Save(designerPrgFile);
                        done = true;
                    }
                }
                if (!done)
                {
                    // File is not open in editor, so write to disk
                    designerStream = new StreamWriter(designerPrgFile, false, realencoding);
                    designerStream.Write(generatedSource);
                    designerStream.Flush();
                    designerStream.Close();
                }
                // The problem here, is that we "may" have some new members, like EvenHandlers, and we need to update their position (line/col)
                XSharpCodeParser parser = new XSharpCodeParser(_projectNode, formClass);
                parser.FileName = designerPrgFile;
                CodeCompileUnit     resultDesigner = parser.Parse(generatedSource);
                CodeTypeDeclaration resultClass    = XSharpCodeDomHelper.FindDesignerClass(resultDesigner);
                // just to be sure...
                if (resultClass != null)
                {
                    // Now push all elements from resultClass to designClass
                    designClass.Members.Clear();
                    foreach (CodeTypeMember ctm in resultClass.Members)
                    {
                        ctm.SetFromDesigner(true);
                        designClass.Members.Add(ctm);
                    }
                }
                // Ok,we MUST do the same thing for the Form file
                base.GenerateCodeFromCompileUnit(formCCU, writer, options);
                // BUT, the writer is hold by the Form Designer, don't close  it !!
                writer.Flush();
                // Now, we must re-read it and parse again
                IServiceProvider  provider = (DocDataTextWriter)writer;
                DocData           docData  = (DocData)provider.GetService(typeof(DocData));
                DocDataTextReader ddtr     = new DocDataTextReader(docData);
                // Retrieve
                generatedSource = ddtr.ReadToEnd();
                var newsource = this._projectNode.SynchronizeKeywordCase(generatedSource, prgFileName);

                if (string.Compare(newsource, generatedSource) != 0)
                {
                    // get DocDataTextWriter and update the source after the case has been synchronized
                    generatedSource = newsource;
                    DocDataTextWriter dtw = new DocDataTextWriter(docData);
                    dtw.Write(generatedSource);
                    dtw.Flush();
                }
                // Don't forget to set the name of the file where the source is...
                parser.FileName = prgFileName;
                resultDesigner  = parser.Parse(generatedSource);
                resultClass     = resultDesigner.GetFirstClass();
                // just to be sure...
                if (resultClass != null)
                {
                    // Now push all elements from resultClass to formClass
                    formClass.Members.Clear();
                    foreach (CodeTypeMember ctm in resultClass.Members)
                    {
                        ctm.SetFromDesigner(false);
                        formClass.Members.Add(ctm);
                    }
                }
                // Ok, it should be ok....
                // We have updated the file and the types that are stored inside each CCU that have been merged in compileUnit
                //XSharpCodeDomHelper.MergeCodeCompileUnit(compileUnit, formCCU, designCCU);
                // And update...
                combinedClass.Members.Clear();
                combinedClass.Members.AddRange(designClass.Members);
                combinedClass.Members.AddRange(formClass.Members);
            }
            else
            {
                var xcompileUnit = ToXCodeCompileUnit(compileUnit);
                // suppress generating the "generated code" header
                if (writer is  DocDataTextWriter)       // Form Editor
                {
                    compileUnit.SetNoHeader();
                }
                base.GenerateCodeFromCompileUnit(compileUnit, writer, options);
                writer.Flush();
                // Designer gave us these informations
                // Now, we must re-read it and parse again
                if (writer is DocDataTextWriter)
                {
                    CodeTypeDeclaration formClass = compileUnit.GetFirstClass();
                    IServiceProvider    provider  = (DocDataTextWriter)writer;
                    DocData             docData   = (DocData)provider.GetService(typeof(DocData));
                    DocDataTextReader   ddtr      = new DocDataTextReader(docData);
                    // Retrieve
                    string           generatedSource = ddtr.ReadToEnd();
                    XSharpCodeParser parser          = new XSharpCodeParser(_projectNode);
                    parser.FileName = xcompileUnit.FileName;
                    generatedSource = _projectNode.SynchronizeKeywordCase(generatedSource, parser.FileName);
                    CodeCompileUnit     resultCcu   = parser.Parse(generatedSource);
                    CodeTypeDeclaration resultClass = resultCcu.GetFirstClass();
                    // just to be sure...
                    if (resultClass != null)
                    {
                        // Now push all elements from resultClass to formClass
                        formClass.Members.Clear();
                        foreach (CodeTypeMember ctm in resultClass.Members)
                        {
                            formClass.Members.Add(ctm);
                        }
                    }
                }
            }
        }