/// <summary> /// Parses document updates from the IDE and return the class associated /// with the changes. /// </summary> /// <returns>The class declaration that changed.</returns> /// <param name="fileName">File name changed.</param> /// <param name="text">Text changed.</param> /// <param name="syntaxTree">Syntax tree.</param> /// <param name="semanticModel">Semantic model.</param> public static async Task <FormsViewClassDeclaration> ParseDocument(string fileName, string text, SyntaxTree syntaxTree, SemanticModel semanticModel) { XAMLDocument xamlDocument = null; FormsViewClassDeclaration formsViewClass = null; // FIXME: Support any kind of types, not just Xamarin.Forms views if (!fileName.EndsWith(".xaml") && !fileName.EndsWith(".xaml.cs") && !fileName.EndsWith(".cs")) { return(null); } // Check if we have already an instance of the class declaration for that file if (!FormsViewClassDeclaration.TryGetByFileName(fileName, out formsViewClass)) { if (fileName.EndsWith(".xaml")) { xamlDocument = XAMLDocument.Parse(fileName, text); // Check if we have an instance of class by namespace if (!FormsViewClassDeclaration.TryGetByFullNamespace(xamlDocument.Type, out formsViewClass)) { formsViewClass = await CreateFromXaml(xamlDocument); } } else { formsViewClass = await CreateFromCodeBehind(fileName, syntaxTree, semanticModel); } } if (formsViewClass == null) { return(null); } // The document is a XAML file if (fileName.EndsWith(".xaml") && xamlDocument == null) { xamlDocument = XAMLDocument.Parse(fileName, text); await formsViewClass.UpdateXaml(xamlDocument); } // The document is code behind or a view without XAML if (fileName.EndsWith(".cs")) { var classDeclaration = FormsViewClassDeclaration.FindClass(syntaxTree, formsViewClass.ClassName); if (formsViewClass.NeedsClassInitialization) { formsViewClass.FillClassInfo(classDeclaration, semanticModel); } formsViewClass.UpdateCode(classDeclaration, semanticModel); } return(formsViewClass); }
static async Task <FormsViewClassDeclaration> CreateFromCodeBehind(string fileName, SyntaxTree syntaxTree, SemanticModel semanticModel) { string xaml = null; string xamlFilePath = null; string codeBehindFilePath = null; string className = null; ClassDeclarationSyntax classDeclaration; XAMLDocument xamlDocument = null; codeBehindFilePath = fileName; var xamlCandidate = fileName.Substring(0, fileName.Length - 3); if (File.Exists(xamlCandidate)) { xamlFilePath = xamlCandidate; xaml = File.ReadAllText(xamlFilePath); } // FIXME: Handle XF views without XAML if (xamlFilePath != null) { // Parse the XAML file xamlDocument = XAMLDocument.Parse(xamlFilePath, xaml); className = xamlDocument.Type.Split('.').Last(); classDeclaration = FormsViewClassDeclaration.FindClass(syntaxTree, className); } else { try { classDeclaration = FormsViewClassDeclaration.FindFormsViewClass(syntaxTree, semanticModel); } catch (Exception ex) { Log.Exception(ex); Log.Error("The class is not a Xamarin.Forms View or Page"); return(null); } } var formsClass = new FormsViewClassDeclaration(classDeclaration, semanticModel, codeBehindFilePath, xamlDocument); if (xamlDocument != null) { await formsClass.UpdateXaml(xamlDocument); } return(formsClass); }
/// <summary> /// Parses document updates from the IDE and return the class associated /// with the changes. /// </summary> /// <returns>The class declaration that changed.</returns> /// <param name="fileName">File name changed.</param> /// <param name="text">Text changed.</param> /// <param name="syntaxTree">Syntax tree.</param> /// <param name="semanticModel">Semantic model.</param> public static async Task <FormsViewClassDeclaration> ParseDocument(string fileName, string text, SyntaxTree syntaxTree, SemanticModel semanticModel) { // FIXME: Support any kind of types, not just Xamarin.Forms views if (!fileName.EndsWith(".xaml") && !fileName.EndsWith(".xaml.cs")) { return(null); } if (!GetOrCreate(fileName, text, syntaxTree, semanticModel, out FormsViewClassDeclaration xamlClass, out XAMLDocument xamlDocument)) { Log.Error("Could not handle document update"); return(null); } // The document is a XAML file if (fileName.EndsWith(".xaml")) { if (xamlDocument == null) { xamlDocument = XAMLDocument.Parse(fileName, text); } await xamlClass.UpdateXaml(xamlDocument); } // The document is code behind else if (fileName.EndsWith(".xaml.cs")) { var classDeclaration = FormsViewClassDeclaration.FindClass(syntaxTree, xamlClass.ClassName); if (xamlClass.NeedsClassInitialization) { xamlClass.FillClassInfo(classDeclaration, semanticModel); } xamlClass.UpdateCode(classDeclaration); } return(xamlClass); }
static bool GetOrCreate(string fileName, string text, SyntaxTree syntaxTree, SemanticModel semanticModel, out FormsViewClassDeclaration xamlClass, out XAMLDocument xamlDocument) { string xaml = null, xamlFilePath = null, codeBehindFilePath = null; xamlDocument = null; // Check if we have already an instance of the class declaration for that file if (FormsViewClassDeclaration.TryGetByFileName(fileName, out xamlClass)) { return(true); } if (fileName.EndsWith(".xaml")) { xaml = text; xamlFilePath = fileName; var candidate = xamlFilePath + ".cs"; if (File.Exists(candidate)) { codeBehindFilePath = candidate; } } else { codeBehindFilePath = fileName; var candidate = fileName.Substring(0, fileName.Length - 3); if (File.Exists(candidate)) { xamlFilePath = candidate; xaml = File.ReadAllText(xamlFilePath); } } // FIXME: Handle XF views without XAML // Parse the XAML file xamlDocument = XAMLDocument.Parse(xamlFilePath, xaml); if (xamlDocument == null) { Log.Error("Error parsing XAML"); return(false); } // Check if we have an instance of class by namespace if (FormsViewClassDeclaration.TryGetByFullNamespace(xamlDocument.Type, out xamlClass)) { return(true); } // This is the first time we have an update for this type // Create a new class declaration instance from the syntax tree if (syntaxTree != null) { var className = xamlDocument.Type.Split('.').Last(); var classDeclaration = FormsViewClassDeclaration.FindClass(syntaxTree, className); xamlClass = new FormsViewClassDeclaration(classDeclaration, semanticModel, codeBehindFilePath, xamlDocument); } // Create a new class declaration instance from the XAML else { xamlClass = new FormsViewClassDeclaration(codeBehindFilePath, xamlDocument); } return(true); }