/// <summary> /// Updates the XAML of the class declaration. /// </summary> /// <param name="xaml">Xaml.</param> internal async Task UpdateXaml(XAMLDocument xaml) { Xaml = xaml.XAML; LoadStyleSheets(xaml); await UpdateAutoGeneratedCodeBehind(); autoGenCodeBehindCode = null; FillAutoGenCodeBehind(); }
/// <summary> /// Initializes a new instance of the <see cref="T:XAMLator.Client.FormsViewClassDeclaration"/> class /// from a XAML document. /// </summary> /// <param name="codeBehindFilePath">Code behind file path.</param> /// <param name="xaml">XAML.</param> public FormsViewClassDeclaration(string codeBehindFilePath, XAMLDocument xaml) { this.codeBehindFilePath = codeBehindFilePath; this.xamlFilePath = xaml.FilePath; StyleSheets = new Dictionary <string, string>(); Namespace = xaml.Type.Substring(0, xaml.Type.LastIndexOf('.')); ClassName = xaml.Type.Split('.').Last(); classesCache.Add(this); UpdateXaml(xaml); }
/// <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); }
/// <summary> /// Initializes a new instance of the <see cref="T:XAMLator.Client.FormsViewClassDeclaration"/> class /// from a code behind document. /// </summary> /// <param name="classDeclarationSyntax">Class declaration syntax.</param> /// <param name="model">Model.</param> /// <param name="codeBehindFilePath">Code behind file path.</param> /// <param name="xaml">Xaml.</param> public FormsViewClassDeclaration(ClassDeclarationSyntax classDeclarationSyntax, SemanticModel model, string codeBehindFilePath, XAMLDocument xaml) { this.codeBehindFilePath = codeBehindFilePath; this.xamlFilePath = xaml.FilePath; StyleSheets = new Dictionary <string, string>(); FillClassInfo(classDeclarationSyntax, model); UpdateXaml(xaml); UpdateCode(classDeclarationSyntax); classesCache.Add(this); }
void LoadStyleSheets(XAMLDocument xaml) { foreach (var styleSheetPath in xaml.StyleSheets) { try { StyleSheets[styleSheetPath] = File.ReadAllText(ResolveStyleSheetPath(xaml, styleSheetPath)); } catch (Exception ex) { Log.Exception(ex); } } }
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); }
static async Task <FormsViewClassDeclaration> CreateFromXaml(XAMLDocument xamlDocument) { string codeBehindFilePath = xamlDocument.FilePath + ".cs"; if (!File.Exists(codeBehindFilePath)) { Log.Error("XAML file without code behind"); return(null); } var xamlClass = new FormsViewClassDeclaration(codeBehindFilePath, xamlDocument); await xamlClass.UpdateXaml(xamlDocument); return(xamlClass); }
/// <summary> /// Request to preview a xaml document. /// </summary> /// <returns>The evaluation response.</returns> /// <param name="doc">The XAML document.</param> public async Task <EvalResponse> PreviewXaml(XAMLDocument doc) { EvalRequest request = new EvalRequest { Xaml = doc.XAML, XamlType = doc.Type }; var content = new StringContent(Serializer.SerializeJson(request), Encoding.UTF8); var response = await client.PostAsync(baseUri + "/xaml", content); if (response.IsSuccessStatusCode) { return(Serializer.DeserializeJson <EvalResponse>(await response.Content.ReadAsStringAsync())); } else { return(null); } }
/// <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); }
string ResolveStyleSheetPath(XAMLDocument xaml, string styleSheetPath) { if (styleSheetPath.StartsWith(Constants.ROOT_REPLACEMENT)) { styleSheetPath = styleSheetPath.Replace(Constants.ROOT_REPLACEMENT + "/", ""); var currentDir = Path.GetDirectoryName(xaml.FilePath); do { var filePath = Path.Combine(currentDir, styleSheetPath); if (File.Exists(filePath)) { return(filePath); } currentDir = Path.GetFullPath(Path.Combine(currentDir, "..")); } while (Directory.GetFiles(currentDir).Any(f => f.EndsWith(".sln")) || currentDir == Directory.GetDirectoryRoot(currentDir)); return(null); } else { return(Path.Combine(Path.GetDirectoryName(xaml.FilePath), styleSheetPath)); } }
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); }