public static string GetFileName(this DocDataTextReader reader) { var value = typeof(DocDataTextReader).GetProperty("DocData", BindingFlags.Instance | BindingFlags.NonPublic) .GetValue(reader) as DocData; return(value.Name); }
public static string GetDesignerFileName(this DocDataTextReader reader) { var fileName = reader.GetFileName(); var index = fileName.LastIndexOf('.'); return(fileName.Insert(index + 1, "Designer.")); }
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); } } } }
// 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); } } } } }