private async void MenuItem_BeforeQueryStatus(object sender, EventArgs e) { try { if (sender is OleMenuCommand menuCmd) { bool showCommandButton = false; var settings = CodeParserBase.GetSettings(); if (settings.IsActiveProfileSet) { var profile = settings.GetActiveProfile(); var dte = await Instance.ServiceProvider.GetServiceAsync(typeof(DTE)) as DTE; var logic = new SetDataContextCommandLogic(profile, this.Logger, new VisualStudioAbstraction(this.Logger, this.ServiceProvider, dte)); showCommandButton = logic.ShouldEnableCommand(); } menuCmd.Visible = menuCmd.Enabled = showCommandButton; } } catch (Exception exc) { this.Logger.RecordException(exc); throw; // Remove for launch. see issue #90 } }
public void ReadOnlyPropertiesMatchNotReadOnlyRatherThanFallback() { var readonlyProfile = new Profile { Name = "readonlyProfile", ProjectType = ProjectType.Uwp, ClassGrouping = "Grid", FallbackOutput = "<Fallback />", Mappings = new ObservableCollection <Mapping> { new Mapping { Type = StringPropertyName, NameContains = "", Output = "<ReadAndWrite />", IfReadOnly = false, }, }, }; var cpb = new CodeParserBase(DefaultTestLogger.Create(), readonlyProfile.ProjectType, 4, readonlyProfile); var result = cpb.GetPropertyOutput(StringPropertyName, "MyProperty", isReadOnly: true); Assert.AreEqual("<ReadAndWrite />", result); }
public void MultipleNameContainsIsIdentified() { var cpb = new CodeParserBase(DefaultTestLogger.Create(), 4, this.testProfile); var result = cpb.GetPropertyOutput("string", "EnteredPassword", isReadOnly: false); Assert.AreEqual(ReadWritePasswordStringOutput.Replace("$name$", "EnteredPassword"), result); }
public void SpecificGenericsMatchBeforeWildCard() { var wildcardGenericsProfile = new Profile { Name = "wildcardGenericsProfile", ClassGrouping = "Grid", FallbackOutput = "<Fallback />", Mappings = new ObservableCollection <Mapping> { new Mapping { Type = "List<T>", NameContains = "", Output = "<Wildcard />", IfReadOnly = false, }, new Mapping { Type = "List<string>", NameContains = "", Output = "<ListOfStrings />", IfReadOnly = false, }, }, }; var cpb = new CodeParserBase(DefaultTestLogger.Create(), 4, wildcardGenericsProfile); var result = cpb.GetPropertyOutput("List<string>", "MyProperty", isReadOnly: false); Assert.AreEqual("<ListOfStrings />", result); }
public void CanHandleMultipleNumberReplacements() { var gridProfile = new Profile { Name = "GridTestProfile", ClassGrouping = "Grid", FallbackOutput = "<TextBlock Text=\"FALLBACK_$name$\" />", SubPropertyOutput = "<TextBlock Text=\"SUBPROP_$name$\" />", Mappings = new ObservableCollection <Mapping> { new Mapping { Type = StringPropertyName, NameContains = "", Output = "<TextBlock Text=\"$name$\" Grid.Row=\"$incint$\" /><TextBlock Text=\"$name$\" Grid.Row=\"$incint$\" />", IfReadOnly = false, }, }, }; var cpb = new CodeParserBase(DefaultTestLogger.Create(), 4, gridProfile); var result = cpb.GetPropertyOutput(StringPropertyName, "MyProperty", false); var expected = "<TextBlock Text=\"MyProperty\" Grid.Row=\"1\" />" + Environment.NewLine + "<TextBlock Text=\"MyProperty\" Grid.Row=\"2\" />"; StringAssert.AreEqual(expected, result); }
public void ReadWritePropertyIsIdentified() { var cpb = new CodeParserBase(DefaultTestLogger.Create(), 4, this.testProfile); var result = cpb.GetPropertyOutput("string", "AnotherProperty", isReadOnly: true); Assert.AreEqual(ReadonlyStringOutput.Replace("$name$", "AnotherProperty"), result); }
public void GetsNonFilteredOutputIfNameDoesntMatch() { var cpb = new CodeParserBase(DefaultTestLogger.Create(), 4, this.testProfile); var result = cpb.GetPropertyOutput("string", "MyProperty", isReadOnly: false); Assert.AreEqual(ReadWriteStringOutput.Replace("$name$", "MyProperty"), result); }
public void GetFallbackIfTypeNotMapped() { var cpb = new CodeParserBase(DefaultTestLogger.Create(), 4, this.testProfile); var result = cpb.GetPropertyOutput("bool", "IsAdmin", isReadOnly: false); Assert.AreEqual(FallbackOutput, result); }
#pragma warning disable CS0628 // New protected member declared in sealed class protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress <ServiceProgressData> progress) #pragma warning restore CS0628 // New protected member declared in sealed class { // When initialized asynchronously, the current thread may be a background thread at this point. // Do any initialization that requires the UI thread after switching to the UI thread. await this.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); try { await SharedRapidXamlPackage.InitializeAsync(cancellationToken, this); SharedRapidXamlPackage.Logger.RecordNotice(StringRes.Info_LaunchVersionGeneration.WithParams(CoreDetails.GetVersion())); SharedRapidXamlPackage.Logger.RecordNotice(string.Empty); await CopyToClipboardCommand.InitializeAsync(this, SharedRapidXamlPackage.Logger); await SendToToolboxCommand.InitializeAsync(this, SharedRapidXamlPackage.Logger); await OpenOptionsCommand.InitializeAsync(this, SharedRapidXamlPackage.Logger); await RapidXamlDropHandlerProvider.InitializeAsync(this, SharedRapidXamlPackage.Logger); // Set the ServiceProvider of CodeParserBase as it's needed to get settings CodeParserBase.ServiceProvider = this; if (SharedRapidXamlPackage.Logger != null) { SharedRapidXamlPackage.Logger.UseExtendedLogging = CodeParserBase.GetSettings().ExtendedOutputEnabled; } } catch (Exception exc) { SharedRapidXamlPackage.Logger?.RecordException(exc); } }
public void ReadOnlyTakesPriorityOverContains() { var cpb = new CodeParserBase(DefaultTestLogger.Create(), 4, this.testProfile); var result = cpb.GetPropertyOutput("string", "EnteredPwd", isReadOnly: true); Assert.AreEqual(ReadonlyStringOutput.Replace("$name$", "EnteredPwd"), result); }
public void TypeNameIsCaseInsensitive() { var cpb = new CodeParserBase(DefaultTestLogger.Create(), 4, this.testProfile); var result = cpb.GetPropertyOutput("INT", "number1", isReadOnly: false); Assert.AreEqual(ReadWriteNumberIntOutput, result); }
public void SingleNameContainsIsIdentified() { var cpb = new CodeParserBase(DefaultTestLogger.Create(), 4, this.testProfile); var result = cpb.GetPropertyOutput("int", "number1", isReadOnly: false); Assert.AreEqual(ReadWriteNumberIntOutput, result); }
public void GetSelectionPropertiesName_Five() { var result = CodeParserBase.GetSelectionPropertiesName(new List <string> { "one", "two", "three", "four", "five" }); Assert.IsTrue(result.Equals("one, two and 3 other properties")); }
public void GetSelectionPropertiesName_Two() { var result = CodeParserBase.GetSelectionPropertiesName(new List <string> { "one", "two" }); Assert.IsTrue(result.Equals("one and two")); }
public void GetSelectionPropertiesName_Four() { var result = CodeParserBase.GetSelectionMemberName(new List <string> { "one", "two", "three", "four" }); Assert.IsTrue(result.Equals("one, two and 2 other members")); }
public void GetSelectionPropertiesName_One() { var result = CodeParserBase.GetSelectionMemberName(new List <string> { "one" }); Assert.IsTrue(result.Equals("one")); }
public async Task <ParserOutput> GetXamlAsync(IAsyncServiceProvider serviceProvider) { ParserOutput result = null; if (CodeParserBase.GetSettings().Profiles.Any()) { if (!(await serviceProvider.GetServiceAsync(typeof(EnvDTE.DTE)) is DTE dte)) { SharedRapidXamlPackage.Logger?.RecordError(StringRes.Error_FailedToGetDteInGetXamlAsync); } else { var activeDocument = dte.ActiveDocument; var textView = await GetTextViewAsync(serviceProvider); var selection = textView.Selection; bool isSelection = selection.Start.Position != selection.End.Position; var caretPosition = textView.Caret.Position.BufferPosition; var document = caretPosition.Snapshot.GetOpenDocumentInCurrentContextWithChanges(); var semanticModel = await document.GetSemanticModelAsync(); var vs = new VisualStudioAbstraction(this.Logger, this.AsyncPackage, dte); var xamlIndent = await vs.GetXamlIndentAsync(); var proj = dte.Solution.GetProjectContainingFile(document.FilePath); if (proj == null) { // Default to the "active project" if file is not part of a known project proj = ((Array)dte.ActiveSolutionProjects).GetValue(0) as Project; } var projType = vs.GetProjectType(proj); this.Logger?.RecordInfo(StringRes.Info_DetectedProjectType.WithParams(projType.GetDescription())); IDocumentParser parser = null; if (activeDocument.Language == "CSharp") { parser = new CSharpParser(this.Logger, projType, xamlIndent); } else if (activeDocument.Language == "Basic") { parser = new VisualBasicParser(this.Logger, projType, xamlIndent); } result = isSelection ? parser?.GetSelectionOutput(await document.GetSyntaxRootAsync(), semanticModel, selection.Start.Position, selection.End.Position) : parser?.GetSingleItemOutput(await document.GetSyntaxRootAsync(), semanticModel, caretPosition.Position); } }
public void RecordInfo(string message) { ThreadHelper.ThrowIfNotOnUIThread(); if (CodeParserBase.GetSettings().ExtendedOutputEnabled) { RxtOutputPane.Instance.Write(TimeStampMessage(message)); } }
public void RecordError(string message) { ThreadHelper.ThrowIfNotOnUIThread(); // Activate the pane (bring to front) so errors are obvious if (CodeParserBase.GetSettings().ExtendedOutputEnabled) { RxtOutputPane.Instance.Write(TimeStampMessage(message)); RxtOutputPane.Instance.Activate(); } else { GeneralOutputPane.Instance.Write(TimeStampMessage(message)); GeneralOutputPane.Instance.Activate(); } }
public void CorrectlySplitCamelCasePropertyNames() { var profile = TestProfile.CreateEmpty(); profile.Mappings.Add(new Mapping { Type = "string", IfReadOnly = false, NameContains = string.Empty, Output = "$namewithspaces$", }); var cpb = new CodeParserBase(DefaultTestLogger.Create(), 4, profile); var result = cpb.GetPropertyOutput("string", "MyProperty", isReadOnly: false); Assert.AreEqual("My Property", result); }
public async Task <ParserOutput> GetXamlAsync(IAsyncServiceProvider serviceProvider) { ParserOutput result = null; if (CodeParserBase.GetSettings().Profiles.Any()) { if (!(await serviceProvider.GetServiceAsync(typeof(EnvDTE.DTE)) is DTE dte)) { RapidXamlPackage.Logger?.RecordError("Failed to get DTE in GetXamlFromCodeWindowBaseCommand.GetXamlAsync"); } else { var activeDocument = dte.ActiveDocument; var textView = await GetTextViewAsync(serviceProvider); var selection = textView.Selection; bool isSelection = selection.Start.Position != selection.End.Position; var caretPosition = textView.Caret.Position.BufferPosition; var document = caretPosition.Snapshot.GetOpenDocumentInCurrentContextWithChanges(); var semanticModel = await document.GetSemanticModelAsync(); var vs = new VisualStudioAbstraction(this.Logger, this.ServiceProvider, dte); var xamlIndent = await vs.GetXamlIndentAsync(); IDocumentParser parser = null; if (activeDocument.Language == "CSharp") { parser = new CSharpParser(this.Logger, xamlIndent); } else if (activeDocument.Language == "Basic") { parser = new VisualBasicParser(this.Logger, xamlIndent); } result = isSelection ? parser?.GetSelectionOutput(await document.GetSyntaxRootAsync(), semanticModel, selection.Start.Position, selection.End.Position) : parser?.GetSingleItemOutput(await document.GetSyntaxRootAsync(), semanticModel, caretPosition.Position); } }
private void MenuItem_BeforeQueryStatus(object sender, EventArgs e) { try { if (sender is OleMenuCommand menuCmd) { menuCmd.Visible = menuCmd.Enabled = false; if (!CodeParserBase.GetSettings().IsActiveProfileSet) { menuCmd.Visible = menuCmd.Enabled = true; } } } catch (Exception exc) { this.Logger.RecordException(exc); throw; // Remove for launch. see issue #90 } }
private async void MenuItem_BeforeQueryStatus(object sender, EventArgs e) { try { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); if (sender is OleMenuCommand menuCmd) { menuCmd.Visible = menuCmd.Enabled = false; if (!this.IsSingleProjectItemSelection(out var hierarchy, out var itemid)) { this.SelectedFileName = null; return; } ((IVsProject)hierarchy).GetMkDocument(itemid, out var itemFullPath); var transformFileInfo = new FileInfo(itemFullPath); // Save the name of the selected file so we have it when the command is executed this.SelectedFileName = transformFileInfo.FullName; if (transformFileInfo.Name.EndsWith(".cs") || transformFileInfo.Name.EndsWith(".vb")) { if (CodeParserBase.GetSettings().IsActiveProfileSet) { menuCmd.Visible = menuCmd.Enabled = true; } } } } catch (Exception exc) { this.Logger.RecordException(exc); } }
public void WriteablePropertiesMatchFallbackIfOnlySpecificReadOnlyDefined() { var readonlyProfile = new Profile { Name = "readonlyProfile", ClassGrouping = "Grid", FallbackOutput = "<Fallback />", Mappings = new ObservableCollection <Mapping> { new Mapping { Type = StringPropertyName, NameContains = "", Output = "<ReadOnly />", IfReadOnly = true, }, }, }; var cpb = new CodeParserBase(DefaultTestLogger.Create(), 4, readonlyProfile); var result = cpb.GetPropertyOutput(StringPropertyName, "MyProperty", isReadOnly: false); Assert.AreEqual("<Fallback />", result); }
private async void Execute(object sender, EventArgs e) { try { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); this.Logger?.RecordFeatureUsage(nameof(SetDatacontextCommand)); var settings = CodeParserBase.GetSettings(); var profile = settings.GetActiveProfile(); if (!(await Instance.ServiceProvider.GetServiceAsync(typeof(DTE)) is DTE dte)) { RapidXamlPackage.Logger?.RecordError("Failed to get DTE in SetDatacontextCommand.Execute"); } else { var vs = new VisualStudioAbstraction(this.Logger, this.ServiceProvider, dte); var logic = new SetDataContextCommandLogic(profile, this.Logger, vs); var inXamlDoc = dte.ActiveDocument.Name.EndsWith(".xaml", StringComparison.InvariantCultureIgnoreCase); var(viewName, viewModelName, vmNamespace) = logic.InferViewModelNameFromFileName(dte.ActiveDocument.Name); if (inXamlDoc) { if (profile.Datacontext.SetsXamlPageAttribute) { var(add, lineNo, content) = logic.GetPageAttributeToAdd(viewModelName, vmNamespace); if (add) { if (dte.ActiveDocument.Object("TextDocument") is TextDocument objectDoc) { objectDoc.Selection.GotoLine(lineNo); objectDoc.Selection.EndOfLine(); objectDoc.Selection.Insert(content); } } } if (profile.Datacontext.SetsAnyCodeBehindContent) { if (profile.Datacontext.SetsCodeBehindPageContent) { // TODO: ISSUE#22 - set the DC in the CB file (C# or VB) may be open and unsaved } if (profile.Datacontext.SetsCodeBehindConstructorContent) { // TODO: ISSUE#22 - set the DC in the CB file (C# or VB) may be open and unsaved } } } else { if (profile.Datacontext.SetsXamlPageAttribute) { // TODO: ISSUE#22 - set the DC in the XAML file (C# or VB) may be open and unsaved } if (profile.Datacontext.SetsAnyCodeBehindContent) { if (dte.ActiveDocument.Object("TextDocument") is TextDocument objectDoc) { var textView = await GetTextViewAsync(Instance.ServiceProvider); var caretPosition = textView.Caret.Position.BufferPosition; var document = caretPosition.Snapshot.GetOpenDocumentInCurrentContextWithChanges(); var documentTree = await document.GetSyntaxTreeAsync(); var documentRoot = documentTree.GetRoot(); var toAdd = logic.GetCodeBehindContentToAdd(viewName, viewModelName, vmNamespace, documentRoot); foreach (var(anything, lineNo, contentToAdd) in toAdd) { if (anything) { objectDoc.Selection.GotoLine(lineNo); objectDoc.Selection.EndOfLine(); objectDoc.Selection.Insert(contentToAdd); } } } } } this.SuppressAnyException(() => dte.FormatDocument(profile)); } }
public void GetSelectionPropertiesName_Null() { var result = CodeParserBase.GetSelectionMemberName(null); Assert.IsTrue(string.IsNullOrEmpty(result)); }
public async Task ExecuteAsync(string selectedFileName) { var vmProj = this.vs.GetActiveProject(); var fileExt = this.fileSystem.GetFileExtension(selectedFileName); var fileContents = this.fileSystem.GetAllFileText(selectedFileName); CodeParserBase parser = null; var codeBehindExt = string.Empty; var indent = await this.vs.GetXamlIndentAsync(); switch (fileExt) { case ".cs": parser = new CSharpParser(this.logger, indent, this.profileOverride); codeBehindExt = ((CSharpParser)parser).FileExtension; break; case ".vb": parser = new VisualBasicParser(this.logger, indent, this.profileOverride); codeBehindExt = ((VisualBasicParser)parser).FileExtension; break; } this.CreateView = false; if (parser != null) { // IndexOf is allowing for "class " in C# and "Class " in VB var cursorPos = fileContents.IndexOf("lass "); if (cursorPos == -1 && codeBehindExt == "vb") { // If not a class, there may be a module cursorPos = fileContents.IndexOf("odule "); } if (cursorPos < 0) { this.logger.RecordInfo(StringRes.Info_CouldNotFindClassInFile.WithParams(selectedFileName)); return; } (var syntaxTree, var semModel) = await this.vs.GetDocumentModelsAsync(selectedFileName); var syntaxRoot = await syntaxTree.GetRootAsync(); var parserOutput = ((IDocumentParser)parser).GetSingleItemOutput(syntaxRoot, semModel, cursorPos); var config = parser.Profile.ViewGeneration; var vmClassName = parserOutput.Name; var baseClassName = vmClassName; if (vmClassName.EndsWith(config.ViewModelFileSuffix)) { baseClassName = vmClassName.Substring(0, vmClassName.LastIndexOf(config.ViewModelFileSuffix, StringComparison.InvariantCulture)); } var viewClassName = $"{baseClassName}{config.XamlFileSuffix}"; var vmProjName = vmProj.Name; string viewProjName; this.ViewProject = null; if (config.AllInSameProject) { this.ViewProject = vmProj; viewProjName = this.ViewProject.Name; } else { var expectedViewProjectName = vmProjName.Replace(config.ViewModelProjectSuffix, config.XamlProjectSuffix); this.ViewProject = this.vs.GetProject(expectedViewProjectName); if (this.ViewProject == null) { this.logger.RecordError(StringRes.Error_UnableToFindProjectInSolution.WithParams(expectedViewProjectName)); } viewProjName = this.ViewProject?.Name; } if (this.ViewProject != null) { var folder = this.fileSystem.GetDirectoryName(this.ViewProject.FileName); this.ViewFolder = this.fileSystem.PathCombine(folder, config.XamlFileDirectoryName); // We assume that the type name matches the file name. this.XamlFileName = this.fileSystem.PathCombine(this.ViewFolder, $"{viewClassName}.xaml"); this.CodeFileName = this.fileSystem.PathCombine(this.ViewFolder, $"{viewClassName}.xaml.{codeBehindExt}"); if (this.fileSystem.FileExists(this.XamlFileName)) { this.logger.RecordInfo(StringRes.Info_FileExists.WithParams(this.XamlFileName)); var overwrite = this.vs.UserConfirms(StringRes.Prompt_FileExistsTitle, StringRes.Propt_FileExistsMessage); if (overwrite) { this.CreateView = true; this.logger.RecordInfo(StringRes.Info_OverwritingFile.WithParams(this.XamlFileName)); } else { this.logger.RecordInfo(StringRes.Info_NotOverwritingFile.WithParams(this.XamlFileName)); } } else { this.CreateView = true; } if (this.CreateView) { // Allow for different namespace conventions var viewNamespace = parser is CSharpParser ? $"{viewProjName}.{config.XamlFileDirectoryName}".TrimEnd('.') : $"{config.XamlFileDirectoryName}".TrimEnd('.'); var vmNamespace = $"{vmProjName}.{config.ViewModelDirectoryName}".TrimEnd('.'); var replacementValues = (viewProjName, viewNamespace, vmNamespace, viewClassName, vmClassName); this.XamlFileContents = this.ReplacePlaceholders(config.XamlPlaceholder, replacementValues); var placeholderPos = this.XamlFileContents.IndexOf(Placeholder.GeneratedXAML); var startOfPlaceholderLine = this.XamlFileContents.Substring(0, placeholderPos).LastIndexOf(Environment.NewLine); var insertIndent = placeholderPos - startOfPlaceholderLine - Environment.NewLine.Length; this.XamlFileContents = this.XamlFileContents.Replace(Placeholder.GeneratedXAML, parserOutput.Output.Replace(Environment.NewLine, Environment.NewLine + new string(' ', insertIndent)).Trim()); this.CodeFileContents = this.ReplacePlaceholders(config.CodePlaceholder, replacementValues); } } } }
public void GetSelectionPropertiesName_Empty() { var result = CodeParserBase.GetSelectionPropertiesName(new List <string>()); Assert.IsTrue(string.IsNullOrEmpty(result)); }