diff --git a/MarkdownDocNet.sln b/VSDocumentGeneratorSolution.sln similarity index 50% rename from MarkdownDocNet.sln rename to VSDocumentGeneratorSolution.sln index 7c03637..d7dfd84 100644 --- a/MarkdownDocNet.sln +++ b/VSDocumentGeneratorSolution.sln @@ -1,9 +1,11 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.23107.0 +# Visual Studio 15 +VisualStudioVersion = 15.0.27130.2010 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MarkdownDocNet", "MarkdownDocNet\MarkdownDocNet.csproj", "{177B50B5-4561-443B-BAFD-A3AB19519324}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MarkdownDocNet", "src\MarkdownDocNet\MarkdownDocNet.csproj", "{177B50B5-4561-443B-BAFD-A3AB19519324}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VisualStudio.DocumentGenerator.Vsix", "src\VisualStudio.DocumentGenerator.Vsix\VisualStudio.DocumentGenerator.Vsix.csproj", "{3CF8B458-7D40-4207-9F76-3AAADCEA8344}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -15,8 +17,15 @@ Global {177B50B5-4561-443B-BAFD-A3AB19519324}.Debug|Any CPU.Build.0 = Debug|Any CPU {177B50B5-4561-443B-BAFD-A3AB19519324}.Release|Any CPU.ActiveCfg = Release|Any CPU {177B50B5-4561-443B-BAFD-A3AB19519324}.Release|Any CPU.Build.0 = Release|Any CPU + {3CF8B458-7D40-4207-9F76-3AAADCEA8344}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3CF8B458-7D40-4207-9F76-3AAADCEA8344}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3CF8B458-7D40-4207-9F76-3AAADCEA8344}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3CF8B458-7D40-4207-9F76-3AAADCEA8344}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {6C8DE249-EF2B-4C6E-A329-6794BB52C856} + EndGlobalSection EndGlobal diff --git a/MarkdownDocNet/App.config b/src/MarkdownDocNet/App.config similarity index 100% rename from MarkdownDocNet/App.config rename to src/MarkdownDocNet/App.config diff --git a/MarkdownDocNet/DocParser.cs b/src/MarkdownDocNet/DocParser.cs similarity index 100% rename from MarkdownDocNet/DocParser.cs rename to src/MarkdownDocNet/DocParser.cs diff --git a/MarkdownDocNet/MarkdownDocNet.csproj b/src/MarkdownDocNet/MarkdownDocNet.csproj similarity index 96% rename from MarkdownDocNet/MarkdownDocNet.csproj rename to src/MarkdownDocNet/MarkdownDocNet.csproj index b077b98..080aab3 100644 --- a/MarkdownDocNet/MarkdownDocNet.csproj +++ b/src/MarkdownDocNet/MarkdownDocNet.csproj @@ -5,7 +5,7 @@ Debug AnyCPU {177B50B5-4561-443B-BAFD-A3AB19519324} - Exe + Library Properties MarkdownDocNet MarkdownDocNet @@ -33,6 +33,9 @@ prompt 4 + + + diff --git a/MarkdownDocNet/Program.cs b/src/MarkdownDocNet/Program.cs similarity index 100% rename from MarkdownDocNet/Program.cs rename to src/MarkdownDocNet/Program.cs diff --git a/MarkdownDocNet/Properties/AssemblyInfo.cs b/src/MarkdownDocNet/Properties/AssemblyInfo.cs similarity index 97% rename from MarkdownDocNet/Properties/AssemblyInfo.cs rename to src/MarkdownDocNet/Properties/AssemblyInfo.cs index 1cab02f..16e765d 100644 --- a/MarkdownDocNet/Properties/AssemblyInfo.cs +++ b/src/MarkdownDocNet/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following diff --git a/src/VisualStudio.DocumentGenerator.Vsix/ActiveDocumentRestorer.cs b/src/VisualStudio.DocumentGenerator.Vsix/ActiveDocumentRestorer.cs new file mode 100644 index 0000000..03c9240 --- /dev/null +++ b/src/VisualStudio.DocumentGenerator.Vsix/ActiveDocumentRestorer.cs @@ -0,0 +1,56 @@ +using EnvDTE; +using System; + +namespace MarkdownVsix +{ + /// + /// A class that handles tracking a document and switching back to it, typically in a using + /// statement context. + /// + internal class ActiveDocumentRestorer : IDisposable + { + #region Constructors + + /// Initializes a new instance of the class. + /// The hosting package. + internal ActiveDocumentRestorer(GenerateMarkdownPackage package) + { + Package = package; + + StartTracking(); + } + + #endregion Constructors + + /// Gets or sets the hosting package. + private GenerateMarkdownPackage Package { get; set; } + + /// Gets or sets the active document. + private Document TrackedDocument { get; set; } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting + /// unmanaged resources. + /// + public void Dispose() + { + RestoreTrackedDocument(); + } + + /// Restores the tracked document if not already active. + internal void RestoreTrackedDocument() + { + if (TrackedDocument != null && Package.ActiveDocument != TrackedDocument) + { + TrackedDocument.Activate(); + } + } + + /// Starts tracking the active document. + internal void StartTracking() + { + // Cache the active document. + TrackedDocument = Package.ActiveDocument; + } + } +} \ No newline at end of file diff --git a/src/VisualStudio.DocumentGenerator.Vsix/Commands/BaseCommand.cs b/src/VisualStudio.DocumentGenerator.Vsix/Commands/BaseCommand.cs new file mode 100644 index 0000000..8af1f94 --- /dev/null +++ b/src/VisualStudio.DocumentGenerator.Vsix/Commands/BaseCommand.cs @@ -0,0 +1,59 @@ +using Microsoft.VisualStudio.Shell; +using System; +using System.ComponentModel.Design; + +namespace MarkdownVsix +{ + /// The base implementation of a command. + internal abstract class BaseCommand : OleMenuCommand + { + /// Gets the hosting package. + protected GenerateMarkdownPackage Package { get; private set; } + + /// Initializes a new instance of the class. + /// The hosting package. + /// The id for the command. + protected BaseCommand(GenerateMarkdownPackage package, CommandID id) + : base(BaseCommand_Execute, id) + { + Package = package; + + BeforeQueryStatus += BaseCommand_BeforeQueryStatus; + } + + /// Called to update the current status of the command. + protected virtual void OnBeforeQueryStatus() + { + // By default, commands are always enabled. + Enabled = true; + } + + /// Called to execute the command. + protected virtual void OnExecute() + { + //OutputWindowHelper.DiagnosticWriteLine($"{GetType().Name}.OnExecute invoked"); + } + + /// Handles the BeforeQueryStatus event of the BaseCommand control. + /// The source of the event. + /// + /// The instance containing the event data. + /// + private static void BaseCommand_BeforeQueryStatus(object sender, EventArgs e) + { + BaseCommand command = sender as BaseCommand; + command?.OnBeforeQueryStatus(); + } + + /// Handles the Execute event of the BaseCommand control. + /// The source of the event. + /// + /// The instance containing the event data. + /// + private static void BaseCommand_Execute(object sender, EventArgs e) + { + BaseCommand command = sender as BaseCommand; + command?.OnExecute(); + } + } +} \ No newline at end of file diff --git a/src/VisualStudio.DocumentGenerator.Vsix/Commands/Constants.cs b/src/VisualStudio.DocumentGenerator.Vsix/Commands/Constants.cs new file mode 100644 index 0000000..0a328ef --- /dev/null +++ b/src/VisualStudio.DocumentGenerator.Vsix/Commands/Constants.cs @@ -0,0 +1,30 @@ +using System; + +namespace MarkdownVsix +{ + public class Constants + { + public const string DocExtension = ".xml"; + + /// Caminho do diretório dos arquivos + public const string ProjectDocPath = "AutoDocs"; + + public static class PackageGuids + { + public const string PackageGuidString = ("d69f1580-274f-4d12-b13a-c365c759de66"); + + public readonly static Guid SymbolGenDocProjectNodeGroup = new Guid("1ebc1a20-d2e7-4875-a7ff-2a3219b14686"); + + public readonly static Guid SymbolGenDocSolutionFolderGroup = new Guid("1ebc1a20-d2e7-4875-a7ff-2a3219b14685"); + public readonly static Guid SymbolGenDocSolutionNodeGroup = new Guid("1ebc1a20-d2e7-4875-a7ff-2a3219b14683"); + } + + /// Helper class that exposes all GUIDs used across VS Package. + public sealed partial class PackageIds + { + public const int CmdIDSymbolGenDocProjectNodeGroup = 0x1052; + public const int CmdIDSymbolGenDocSolutionFolderGroup = 0x1051; + public const int CmdIDSymbolGenDocSolutionNodeGroup = 0x1050; + } + } +} \ No newline at end of file diff --git a/src/VisualStudio.DocumentGenerator.Vsix/Commands/CreateMarkdownProjectCommand.cs b/src/VisualStudio.DocumentGenerator.Vsix/Commands/CreateMarkdownProjectCommand.cs new file mode 100644 index 0000000..e3e67cc --- /dev/null +++ b/src/VisualStudio.DocumentGenerator.Vsix/Commands/CreateMarkdownProjectCommand.cs @@ -0,0 +1,96 @@ +using EnvDTE; +using System; +using System.Collections.Generic; +using System.ComponentModel.Design; +using System.Diagnostics; +using System.IO; +using System.Linq; +using VisualStudio.DocumentGenerate.Vsix.Format.Markdown; + +namespace MarkdownVsix +{ + /// A command that provides for cleaning up code in the selected documents. + internal class CreateMarkdownProjectCommand : BaseCommand + { + /// Gets the list of selected project items. + private IEnumerable SelectedProjectItems + { + get + { + return SolutionHelper.GetSelectedProjectItemsRecursively(Package); + } + } + + /// + /// Initializes a new instance of the class. + /// + /// The hosting package. + internal CreateMarkdownProjectCommand(GenerateMarkdownPackage package) + : this(package, new CommandID(Constants.PackageGuids.SymbolGenDocProjectNodeGroup, Constants.PackageIds.CmdIDSymbolGenDocProjectNodeGroup)) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The hosting package. + internal CreateMarkdownProjectCommand(GenerateMarkdownPackage package, CommandID command) + : base(package, command) + { + } + + /// Called to update the current status of the command. + protected override void OnBeforeQueryStatus() + { + Enabled = Package.IDE.Solution.IsOpen; + } + + /// Called to execute the command. + protected override void OnExecute() + { + base.OnExecute(); + Package.IDE.Solution.SolutionBuild.Clean(true); + // Package.IDE.Solution.SolutionBuild.Build(true); + + Console.WriteLine("Iniciando a geração de documentos"); + + if (SelectedProjectItems?.Any() == false) + { + Console.WriteLine("Não foi encontrado nenhum projeto selecionado"); + return; + } + + using (var document = new ActiveDocumentRestorer(Package)) + { + //const string documentationFile = "DocumentationFile"; + const string projectFullName = "Microsoft.VisualStudio.ProjectSystem.VS.Implementation.Package.Automation.OAProject"; + + + //&& (a.ContainingProject.Properties?.Item(documentationFile) != null) + var projects = SelectedProjectItems + .Where(a => a.ContainingProject != null && + a.ContainingProject.GetType().FullName == projectFullName) + .Select(a => new ProjectFile(a.ContainingProject)) + .Where(a => !string.IsNullOrWhiteSpace(a.DocFile) && !a.InvalidProject) + .Distinct() + .ToArray(); + + Console.WriteLine("Foram encontrados {0}/{1} arquivos xml", projects.Length, SelectedProjectItems.Count()); + + var solutionDirectory = Path.GetDirectoryName(Package.IDE.Solution.FullName); + solutionDirectory = Path.Combine(solutionDirectory, Constants.ProjectDocPath); + + foreach (var project in projects) + { + Debug.WriteLine($"Executando {project.DocName}"); + Package.IDE.StatusBar.Text = $"Executando {project.DocName}"; + + var parser = new MarkdownParse(project.DocFile, project.AssemblyFile, solutionDirectory); + Package.IDE.Solution.SolutionBuild.BuildProject("Debug", project.UniqueName, true); + parser.ParseXml(); + parser.GenerateDoc(); + } + } + } + } +} \ No newline at end of file diff --git a/src/VisualStudio.DocumentGenerator.Vsix/Commands/CreateMarkdownSolutionCommand.cs b/src/VisualStudio.DocumentGenerator.Vsix/Commands/CreateMarkdownSolutionCommand.cs new file mode 100644 index 0000000..ce410dd --- /dev/null +++ b/src/VisualStudio.DocumentGenerator.Vsix/Commands/CreateMarkdownSolutionCommand.cs @@ -0,0 +1,12 @@ +using System.ComponentModel.Design; + +namespace MarkdownVsix +{ + internal class CreateMarkdownSolutionCommand : CreateMarkdownProjectCommand + { + internal CreateMarkdownSolutionCommand(GenerateMarkdownPackage package) + : base(package, new CommandID(Constants.PackageGuids.SymbolGenDocSolutionNodeGroup, Constants.PackageIds.CmdIDSymbolGenDocSolutionNodeGroup)) + { + } + } +} \ No newline at end of file diff --git a/src/VisualStudio.DocumentGenerator.Vsix/Commands/CreateMarkdownSolutionFolderCommand.cs b/src/VisualStudio.DocumentGenerator.Vsix/Commands/CreateMarkdownSolutionFolderCommand.cs new file mode 100644 index 0000000..3a41c16 --- /dev/null +++ b/src/VisualStudio.DocumentGenerator.Vsix/Commands/CreateMarkdownSolutionFolderCommand.cs @@ -0,0 +1,12 @@ +using System.ComponentModel.Design; + +namespace MarkdownVsix +{ + internal class CreateMarkdownSolutionFolderCommand : CreateMarkdownProjectCommand + { + internal CreateMarkdownSolutionFolderCommand(GenerateMarkdownPackage package) + : base(package, new CommandID(Constants.PackageGuids.SymbolGenDocSolutionFolderGroup, Constants.PackageIds.CmdIDSymbolGenDocSolutionFolderGroup)) + { + } + } +} \ No newline at end of file diff --git a/src/VisualStudio.DocumentGenerator.Vsix/Format/DocFormat.cs b/src/VisualStudio.DocumentGenerator.Vsix/Format/DocFormat.cs new file mode 100644 index 0000000..62cf5b0 --- /dev/null +++ b/src/VisualStudio.DocumentGenerator.Vsix/Format/DocFormat.cs @@ -0,0 +1,45 @@ +using System; +using System.Reflection; +using System.Text; + +namespace VSDocument.Format.Markdown +{ + public abstract class DocFormat + { + protected virtual void WriteInfo(MethodInfo[] methods, StringBuilder output) + { + } + + protected virtual void WriteInfo(PropertyInfo[] properties, StringBuilder output) + { + } + + protected virtual void WriteInfo(FieldInfo[] fields, StringBuilder output) + { + } + + protected virtual void WriteInfo(EventInfo[] events, StringBuilder output) + { + } + + protected virtual void WriteInfo(ConstructorInfo[] events, StringBuilder output) + { + } + + protected virtual void WriteInfo(Type type, StringBuilder output) + { + } + + protected virtual void WriteStatic(FieldInfo[] staticFields, StringBuilder output) + { + } + + protected virtual void WriteStatic(MethodInfo[] staticMethods, StringBuilder output) + { + } + + protected virtual void WriteStatic(PropertyInfo[] staticProperties, StringBuilder output) + { + } + } +} \ No newline at end of file diff --git a/src/VisualStudio.DocumentGenerator.Vsix/Format/DocParser.cs b/src/VisualStudio.DocumentGenerator.Vsix/Format/DocParser.cs new file mode 100644 index 0000000..43c2617 --- /dev/null +++ b/src/VisualStudio.DocumentGenerator.Vsix/Format/DocParser.cs @@ -0,0 +1,455 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Xml; +using System.Xml.Linq; + +namespace VSDocument.Format.Markdown +{ + public class DocParser : DocFormat, IDisposable + { + protected static HashSet ignoredNamespaces = new HashSet + { + "System", + "System.Collections.Generic", + "System.Text", + "System.IO" + }; + + protected static Dictionary primitiveNames = new Dictionary + { + {typeof(byte), "byte"}, + {typeof(sbyte), "sbyte"}, + {typeof(short), "short"}, + {typeof(ushort), "ushort"}, + {typeof(int), "int"}, + {typeof(uint), "uint"}, + {typeof(long), "long"}, + {typeof(ulong), "ulong"}, + {typeof(char), "char"}, + {typeof(float), "float"}, + {typeof(double), "double"}, + {typeof(decimal), "decimal"}, + {typeof(bool), "bool"}, + {typeof(object), "object"}, + {typeof(string), "string"}, + }; + + protected Dictionary MemberDocumentations = new Dictionary(); + private Assembly AssemblyInfo; + private bool disposedValue = false; + private XDocument Doc; + protected string OutputPath { get; private set; } + + public DocParser(string docFile, string assemblyFile, string outputFile) + { + Doc = XDocument.Load(docFile, LoadOptions.SetLineInfo); + AssemblyInfo = Assembly.LoadFile(assemblyFile); + OutputPath = outputFile; + } + + public static string CommonNamespacePrefix(string fullName1, string fullName2) + { + var elements1 = fullName1.Split('.'); + var elements2 = fullName2.Split('.'); + + var potentialMatchLength = Math.Min(elements1.Length, elements2.Length); + + var output = new StringBuilder(); + bool first = true; + + for (var i = 0; i < potentialMatchLength; i++) + { + if (elements1[i].Equals(elements2[i])) + { + if (!first) + output.Append("."); + first = false; + + output.Append(elements1[i]); + } + else + break; + } + + return output.ToString(); + } + + // This code added to correctly implement the disposable pattern. + public void Dispose() + { + // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + Dispose(true); + // TODO: uncomment the following line if the finalizer is overridden above. GC.SuppressFinalize(this); + } + + public string FixValueIndentation(XNode node, string text) + { + var lineInfo = (IXmlLineInfo)node.Parent; + var indentationCount = lineInfo.LinePosition - 2; + if (indentationCount > 0) + { + var indentation = "\n" + new String(' ', indentationCount); + text = text.Replace(indentation, "\n"); + } + + return text.Trim(); + } + + public string FullNameFromDescriptor(string descriptor) + { + var descriptorElements = descriptor.Split(':'); + + if (descriptorElements.Length != 2) + throw new InvalidOperationException(String.Format("Invalid name descriptor: '{0}'", descriptor)); + + return descriptorElements[1]; + } + + public void GenerateDoc() + { + var types = AssemblyInfo.GetExportedTypes(); + + var typesSorted = types.OrderByDescending((Type a) => + { + var impA = 0; + if (MemberDocumentations.ContainsKey(a.FullName)) + impA = MemberDocumentations[a.FullName].Importance; + return impA; + }); + + var assemblyName = AssemblyInfo.GetName().Name; + CleanFolder(OutputPath + "\\" + assemblyName); + foreach (var type in typesSorted) + { + WriteFile(type); + } + } + + public string HumanNameFromDescriptor(string descriptor, string parentTypeOrNamespace = null) + { + var descriptorElements = descriptor.Split(':'); + + if (descriptorElements.Length != 2 || descriptorElements[0].Length != 1) + throw new InvalidOperationException(String.Format("Invalid name descriptor: '{0}'", descriptor)); + + var memberType = MemberDoc.TypeFromDescriptor(descriptorElements[0][0]); + var fullName = descriptorElements[1]; + + // Cut away any method signatures + var fullNameNoSig = fullName.Split(new char[] { '(' }, 2)[0]; + + if (String.IsNullOrEmpty(parentTypeOrNamespace)) + return fullName; + + var commonPrefix = ""; + var dotIndex = fullNameNoSig.LastIndexOf('.'); + if (dotIndex >= 0) + { + var possiblePrefix = fullNameNoSig.Substring(0, dotIndex); + commonPrefix = CommonNamespacePrefix(possiblePrefix, parentTypeOrNamespace); + } + + //if(memberType == MemberType.Type || memberType == MemberType.Namespace) + return fullNameNoSig.Substring(commonPrefix.Length + 1); + /*else + { + var declaringTypeName = fullNameNoSig.Substring(0, fullNameNoSig.LastIndexOf('.')); + var declaringType = AssemblyInfo.GetType(declaringTypeName); + if(declaringType == null || declaringType.FullName != parentTypeOrNamespace) + return fullNameNoSig.Substring(commonPrefix.Length + 1); + else + { + // So the given descriptor + var memberName = fullName.Substring(commonPrefix.Length + 1); + + // For everything except methods, just return the member name + if (memberType != MemberType.Method) + return memberName; + + // Try to find the exact matching method so we can print the correct signature + var possibleMatches = declaringType.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); + foreach(var match in possibleMatches) + { + var memberId = FullNameFromMember(match); + if (memberId == fullName) + return match.Name + MakeSignature(match, true); + } + + return memberName; + } + } + */ + } + + public string LinkFromDescriptor(string descriptor, string contextMemberName, string linkName = null) + { + var link = FullNameFromDescriptor(descriptor); + + if (linkName == null) + return " [" + HumanNameFromDescriptor(descriptor, contextMemberName) + "](#" + link + ") "; + else + return " [" + linkName + "](#" + link + ") "; + } + + /// + /// Parses the text inside a given XML node and returns a Markdown version of it. + /// + public string ParseDocText(XNode node, string contextMemberName) + { + if (node.NodeType == XmlNodeType.Text) + { + var text = ((XText)node).Value; + return FixValueIndentation(node, text); + } + else if (node.NodeType == XmlNodeType.Element) + { + var element = (XElement)node; + if (element.Name == "see") + { + var descriptor = element.Attribute("cref").Value; + string linkName = null; + if (!String.IsNullOrEmpty(element.Value)) + linkName = element.Value; + return LinkFromDescriptor(descriptor, contextMemberName, linkName); + } + else if (element.Name == "code") + { + var code = FixValueIndentation(element, element.Value); + ParseDocText(element.FirstNode, contextMemberName); + return "\n```csharp\n" + code + "\n```\n"; + } + else + { + var output = new StringBuilder(); + foreach (var child in element.Nodes()) + { + if (child.NodeType == XmlNodeType.Element || child.NodeType == XmlNodeType.Text) + output.Append(ParseDocText(child, contextMemberName)); + } + return output.ToString(); + } + } + else + return ""; + } + + /// + /// Parsed a single member node from the xml documentation and returns the corresponding + /// MemberDoc object. + /// + public MemberDoc ParseMember(XElement member) + { + var memberInfo = new MemberDoc(); + + string nameDescriptor = member.Attribute("name").Value; + var descriptorElements = nameDescriptor.Split(':'); + + if (descriptorElements.Length != 2) + throw new InvalidOperationException(String.Format( + "Invalid name descriptor in line {0}: '{1}'", + ((IXmlLineInfo)member).LineNumber, + nameDescriptor + )); + + memberInfo.Type = MemberDoc.TypeFromDescriptor(descriptorElements[0][0]); + + memberInfo.FullName = descriptorElements[1]; + memberInfo.LocalName = memberInfo.FullName; + + var xImportance = member.Element("importance"); + if (xImportance != null) + { + int importance = 0; + if (int.TryParse(xImportance.Value, out importance)) + memberInfo.Importance = importance; + } + + var xSummary = member.Element("summary"); + if (xSummary != null) + memberInfo.Summary = ParseDocText(xSummary, memberInfo.FullName); + + var xRemarks = member.Element("remarks"); + if (xRemarks != null) + memberInfo.Remarks = ParseDocText(xRemarks, memberInfo.FullName); + + var xReturns = member.Element("returns"); + if (xReturns != null) + memberInfo.Returns = ParseDocText(xReturns, memberInfo.FullName); + + var xExample = member.Element("example"); + if (xExample != null) + memberInfo.Example = ParseDocText(xExample, memberInfo.FullName); + + var xException = member.Element("exception"); + if (xException != null) + memberInfo.Exception = ParseDocText(xException, memberInfo.FullName); + + var xParams = member.Elements("param"); + foreach (var param in xParams) + { + var name = param.Attribute("name").Value; + memberInfo.ParameterDescriptionsByName[name] = ParseDocText(param, memberInfo.FullName); + } + + return memberInfo; + } + + public void ParseXml() + { + var members = Doc.Element("doc").Element("members").Elements("member"); + foreach (var member in members) + { + var memberInfo = ParseMember(member); + MemberDocumentations[memberInfo.FullName] = memberInfo; + } + } + + + public void WriteConcreteType(Type type, StringBuilder output) + { + if (type == null || (!type.IsClass && !type.IsValueType) || !MemberDocumentations.ContainsKey(type.FullName)) + { + return; + } + // Print overview of all members + var constructors = type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly); + var events = type.GetEvents(BindingFlags.Instance | BindingFlags.Public); + var fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly); + var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly); + var methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly) + .Where(a => !a.IsSpecialName) + .ToArray(); + + var staticFields = type.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly); + var staticProperties = type.GetProperties(BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly); + var staticMethods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly) + .Where(a => !a.IsSpecialName) + .ToArray(); + + WriteInfo(type, output); + WriteStatic(staticFields, output); + WriteInfo(fields, output); + WriteInfo(properties, output); + WriteInfo(events, output); + WriteInfo(constructors, output); + WriteInfo(methods, output); + WriteStatic(staticProperties, output); + WriteStatic(staticMethods, output); + output.AppendLine(""); + + + } + + public void WriteInterfacesType(Type type, StringBuilder output) + { + if (!type.IsInterface) + { + return; + } + + // Print overview of all members + var constructors = type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly); + var events = type.GetEvents(BindingFlags.Instance | BindingFlags.Public); + var fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly); + var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly); + var methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly) + .Where(a => !a.IsSpecialName) + .ToArray(); + + WriteInfo(type, output); + WriteInfo(fields, output); + WriteInfo(properties, output); + WriteInfo(events, output); + WriteInfo(constructors, output); + WriteInfo(methods, output); + output.AppendLine(""); + + } + + public void WriteFile(Type type) + { + if (type == null || !MemberDocumentations.ContainsKey(type.FullName)) + { + return; + } + var output = new StringBuilder(); + if (type.BaseType == typeof(System.MulticastDelegate)) + { + // Todo: Docs for delegate types + } + else if (type.IsEnum) + { + // Only print members that are documented + var staticFields = type.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly); + + WriteInfo(type, output); + WriteStatic(staticFields, output); + + } + else + { + WriteConcreteType(type, output); + WriteInterfacesType(type, output); + } + if (output.Length > 0) + { + + var assemblyName = type.Assembly.GetName().Name; + var path = $"{OutputPath}\\{assemblyName}\\"; + if (!string.Equals(assemblyName, type.Namespace, StringComparison.CurrentCultureIgnoreCase)) + path += type.Namespace; + + output.AppendLine(""); + output.AppendLine("---"); + output.AppendLine(""); + Directory.CreateDirectory(path); + var file = $"{path}\\{type.Name}.md"; + File.WriteAllText(file, output.ToString()); + } + } + + void CleanFolder(string folder) + { + try + { + var dir = new DirectoryInfo(folder); + dir.Delete(true); + } + catch (UnauthorizedAccessException) + { + //TODO: Implementar casos que o o arquivo esta marcado como readonly + } + catch (DirectoryNotFoundException) + { + //Caso o diretorio não exista não precisa apagar + + } + + } + + + // To detect redundant calls + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + // TODO: dispose managed state (managed objects). + } + + // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below. + this.AssemblyInfo = null; + this.Doc = null; + GC.ReRegisterForFinalize(this); + // TODO: set large fields to null. + + disposedValue = true; + } + } + } +} \ No newline at end of file diff --git a/src/VisualStudio.DocumentGenerator.Vsix/Format/Markdown/MarkdownParse.cs b/src/VisualStudio.DocumentGenerator.Vsix/Format/Markdown/MarkdownParse.cs new file mode 100644 index 0000000..f2bbaf2 --- /dev/null +++ b/src/VisualStudio.DocumentGenerator.Vsix/Format/Markdown/MarkdownParse.cs @@ -0,0 +1,359 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using VSDocument.Format.Markdown; + +namespace VisualStudio.DocumentGenerate.Vsix.Format.Markdown +{ + public class MarkdownParse : DocParser + { + public MarkdownParse(string docFile, string assemblyFile, string outputFile) : base(docFile, assemblyFile, outputFile) + { + } + + /// Returns the name of the given type as it would be notated in C# + public string CSharpName(Type type) + { + //FullName is null when type is Generic with TResult, T e etc... + var name = ignoredNamespaces.Contains(type.Namespace) ? type.Name : type.FullName ?? type.Name; + name = name.Replace('+', '.'); + + if ((type.IsPrimitive || type == typeof(string)) && primitiveNames.ContainsKey(type)) + return primitiveNames[type]; + + if (!type.IsGenericType) + return name; + + var output = new StringBuilder(); + output.Append(name.Substring(0, name.IndexOf('`'))); + output.Append("<"); + output.Append(string.Join(", ", type.GetGenericArguments() + .Select(t => CSharpName(t)))); + output.Append(">"); + return output.ToString(); + } + + /// + /// Returns the full name of the given member, in the same notation that is used in the XML + /// documentation files for member ids and references. + /// + public string FullNameFromMember(MemberInfo member) + { + if (member is MethodInfo) + { + var method = (MethodInfo)member; + if (method.GetParameters().Length > 0) + return method.DeclaringType.FullName + "." + method.Name + MakeSignature(method, humanReadable: false); + else + return method.DeclaringType.FullName + "." + method.Name; + } + else + { + return member.DeclaringType.FullName + "." + member.Name; + } + } + + public string MakeSignature(MethodBase method, bool humanReadable = true) + { + var output = new StringBuilder(); + output.Append("("); + var parameters = method.GetParameters(); + bool first = true; + foreach (var p in parameters) + { + if (!first) + output.Append(humanReadable ? ", " : ","); + + if (p.IsOptional && humanReadable) + output.Append("["); + + if (humanReadable) + { + output.Append(CSharpName(p.ParameterType)); + output.Append(" "); + output.Append(p.Name); + } + else + { + output.Append(p.ParameterType.FullName); + } + + if (p.IsOptional && humanReadable) + output.Append("]"); + first = false; + } + output.Append(")"); + + return output.ToString(); + } + + public string MemberListCategory(string title, IEnumerable members) + { + var output = new StringBuilder(); + output.AppendLine(""); + if (!String.IsNullOrEmpty(title)) + { + output.AppendLine("## **" + title + "**"); + output.AppendLine(""); + } + foreach (var member in members) + { + output.AppendLine(MemberListItem(member)); + } + output.AppendLine(""); + output.AppendLine(""); + return output.ToString(); + } + + public string MemberListItem(MemberInfo member) + { + var fullName = FullNameFromMember(member); + + var output = new StringBuilder(); + output.AppendLine(""); + output.AppendLine(""); + output.Append("* "); + if (member is FieldInfo || member is PropertyInfo) + { + Type type = null; + if (member is FieldInfo) + type = ((FieldInfo)member).FieldType; + else if (member is PropertyInfo) + type = ((PropertyInfo)member).PropertyType; + + if (type != null) + output.Append("*" + CSharpName(type) + "* "); + + output.Append("**" + member.Name + "**"); + } + output.AppendLine(" "); + if (MemberDocumentations.ContainsKey(fullName)) + this.WriteDocs(member, output); + + output.AppendLine(""); + + return output.ToString(); + } + + protected override void WriteInfo(Type type, StringBuilder output) + { + output.AppendLine(""); + + var typeType = ""; + + if (type.IsValueType) + typeType = "Struct"; + else if (type.IsInterface) + typeType = "Interface"; + else if (type.IsClass) + typeType = "Class"; + else if (type.IsEnum) + typeType = "Enum"; + + // Print the type name heading + output.AppendLine("# " + typeType + " " + type.FullName); + + if (type.BaseType != typeof(object)) + output.AppendLine("*Extends " + type.BaseType.FullName + "*"); + + output.AppendLine(""); + + var doc = MemberDocumentations[type.FullName]; + // Print summary and remarks + if (!String.IsNullOrEmpty(doc.Summary)) + { + output.AppendLine(doc.Summary); + output.AppendLine(""); + } + + if (!String.IsNullOrEmpty(doc.Remarks)) + { + output.AppendLine(doc.Remarks); + output.AppendLine(""); + } + + if (!String.IsNullOrEmpty(doc.Example)) + { + output.AppendLine("**Examples**"); + output.AppendLine(""); + output.AppendLine(doc.Example); + output.AppendLine(""); + } + } + + protected override void WriteInfo(ConstructorInfo[] constructors, StringBuilder output) + { + if (constructors == null || !constructors.Any()) return; + output.AppendLine(""); + foreach (var member in constructors) + { + var fullName = FullNameFromMember(member); + output.AppendLine(""); + output.AppendLine(""); + output.Append("* "); + + var constructor = (ConstructorInfo)member; + fullName = constructor.DeclaringType.FullName + ".#ctor" + MakeSignature(constructor, false); + output.Append("**" + member.DeclaringType.Name + "** *" + MakeSignature(constructor) + "*"); + this.WriteDocs(member, output); + } + + //output.Append(MemberListCategory("Constructors", constructors)); + + output.AppendLine(""); + } + + protected override void WriteInfo(MethodInfo[] methods, StringBuilder output) + { + if (methods == null || !methods.Any()) return; + output.AppendLine("## **Methods**"); + output.AppendLine(""); + output.AppendLine(""); + + //TODO: Verificar se precisa remover IsSpecialName + foreach (var method in methods.Where(m => !m.IsConstructor)) + { + var returnValue = (method.ReturnType == null || method.ReturnType == typeof(void)) + ? "void " + : $"*{CSharpName(method.ReturnType) }* "; + + output.Append($"### {returnValue} **{method.Name}** *{MakeSignature(method)}*"); + WriteDocs(method, output); + + output.AppendLine(""); + output.AppendLine(""); + } + output.AppendLine(""); + output.AppendLine(""); + } + + protected override void WriteInfo(PropertyInfo[] properties, StringBuilder output) + { + if (properties.Length > 0) + { + output.Append(MemberListCategory("Properties", properties)); + } + } + + protected override void WriteInfo(EventInfo[] events, StringBuilder output) + { + if (events.Length > 0) + { + output.Append(MemberListCategory("Events", events)); + } + } + + protected override void WriteInfo(FieldInfo[] fields, StringBuilder output) + { + if (fields.Length > 0) + { + output.Append(MemberListCategory("Fields", fields)); + } + } + + protected override void WriteStatic(FieldInfo[] staticFields, StringBuilder output) + { + if (staticFields == null || staticFields.Length == 0) return; + + output.AppendLine("## **Static Fields**"); + output.AppendLine(""); + + foreach (var method in staticFields) + { + output.Append(MemberListItem(method)); + } + output.AppendLine(""); + } + + protected override void WriteStatic(PropertyInfo[] staticProperties, StringBuilder output) + { + if (staticProperties.Length > 0) + { + output.Append(MemberListCategory("Static Properties", staticProperties)); + } + } + + /// Metodo responsavel por escrever o summary, remarks, returns e example + /// Atributo/metodo que será documentado + /// string de saída' + private void WriteDocs(MemberInfo member, StringBuilder output) + { + string fullName = FullNameFromMember(member); + var docKey = MemberDocumentations.FirstOrDefault(d => d.Key.Replace("[^a-zA-Z0-9.]", "") == fullName.Replace("[^a-zA-Z0-9.]", "")); + if (ReferenceEquals(docKey, null) || ReferenceEquals(docKey.Value, null)) return; + var doc = docKey.Value; + + output.AppendLine(""); + + //if (!MemberDocumentations.ContainsKey(fullName)) return; + //var doc = MemberDocumentations[fullName]; + if (!String.IsNullOrEmpty(doc.Summary)) + { + output.AppendLine(""); + output.AppendLine($" Summary: {doc.Summary} "); + } + if (!String.IsNullOrEmpty(doc.Remarks)) + { + output.AppendLine(""); + output.AppendLine($" Remarks: {doc.Remarks}"); + } + if (!String.IsNullOrEmpty(doc.Returns)) + { + output.AppendLine(""); + output.AppendLine($" **Returns:** {doc.Returns}"); + } + if (!String.IsNullOrEmpty(doc.Exception)) + { + output.AppendLine(""); + output.AppendLine("Exception(s):"); + output.AppendLine($" "); + } + if (!String.IsNullOrEmpty(doc.Example)) + { + output.AppendLine(""); + output.AppendLine("**Example:** "); + output.AppendLine(""); + output.AppendLine($@"```CSharp"); + output.AppendLine(""); + var lines = doc.Example.Split(';'); + foreach (var line in lines) + { + output.AppendLine(line); + } + + + output.AppendLine(""); + output.AppendLine($@"```"); + } + + //Documenta os parametros caso exista + if (member is MethodBase method) + this.WriteParameters(method, output, doc); + output.AppendLine(""); + } + + private void WriteParameters(MethodBase method, StringBuilder output, MemberDoc doc) + { + var parameters = method?.GetParameters(); + if (parameters == null || !parameters.Any()) return; + + output.AppendLine("#### **Parameters:**"); + output.AppendLine(""); + output.AppendLine(""); + + foreach (var paramInfo in parameters) + { + output.Append("* *" + CSharpName(paramInfo.ParameterType) + "* **" + paramInfo.Name + "**"); + if (paramInfo.IsOptional) + output.Append(" *(optional, default: " + paramInfo.DefaultValue.ToString() + ")* "); + if (doc.ParameterDescriptionsByName.ContainsKey(paramInfo.Name)) + output.Append($" - (_{doc.ParameterDescriptionsByName[paramInfo.Name]}_)"); + + output.AppendLine(""); + output.AppendLine(""); + } + } + } +} \ No newline at end of file diff --git a/src/VisualStudio.DocumentGenerator.Vsix/Format/Markdown/MemberDoc.cs b/src/VisualStudio.DocumentGenerator.Vsix/Format/Markdown/MemberDoc.cs new file mode 100644 index 0000000..ee8ea9c --- /dev/null +++ b/src/VisualStudio.DocumentGenerator.Vsix/Format/Markdown/MemberDoc.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; + +namespace VSDocument.Format.Markdown +{ + public class MemberDoc + { + public string Example; + + public string Exception; + public string FullName; + + public int Importance = 0; + + public string LocalName; + + public Dictionary ParameterDescriptionsByName = new Dictionary(); + + public string ParentName; + + public string Remarks; + + public string Returns; + + public string Summary; + public MemberType Type; + + public static MemberType TypeFromDescriptor(char descriptor) + { + switch (descriptor) + { + case 'T': + return MemberType.Type; + + case 'M': + return MemberType.Method; + + case 'E': + return MemberType.Event; + + case 'F': + return MemberType.Field; + + case 'P': + return MemberType.Property; + + default: + throw new ArgumentException("Unknown member descriptor: " + descriptor); + } + } + } +} \ No newline at end of file diff --git a/src/VisualStudio.DocumentGenerator.Vsix/Format/Markdown/MemberType.cs b/src/VisualStudio.DocumentGenerator.Vsix/Format/Markdown/MemberType.cs new file mode 100644 index 0000000..3ac463f --- /dev/null +++ b/src/VisualStudio.DocumentGenerator.Vsix/Format/Markdown/MemberType.cs @@ -0,0 +1,13 @@ +namespace VSDocument.Format.Markdown +{ + public enum MemberType + { + Namespace = 0, + Type = 1, + Method = 2, + Field = 3, + Property = 4, + Event = 5, + Constructor = 6 + } +} \ No newline at end of file diff --git a/src/VisualStudio.DocumentGenerator.Vsix/Format/ProjectFile.cs b/src/VisualStudio.DocumentGenerator.Vsix/Format/ProjectFile.cs new file mode 100644 index 0000000..4cdd536 --- /dev/null +++ b/src/VisualStudio.DocumentGenerator.Vsix/Format/ProjectFile.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace MarkdownVsix +{ + public class ProjectFile : IEquatable + { + private const string assemblyName = "AssemblyName"; + private const string documentationFile = "DocumentationFile"; + private const string fullPath = "FullPath"; + public string AssemblyFile => Directory.GetFiles(Path, AssemblyName + ".dll", SearchOption.AllDirectories)?.FirstOrDefault(); + + public string AssemblyName { get; set; } + + public string DocFile => Directory.GetFiles(Path, DocName, SearchOption.AllDirectories)?.FirstOrDefault(); + + public string DocName { get; set; } + + public string Path { get; set; } + + public string UniqueName { get; private set; } + + public bool InvalidProject { get; } + + /// + /// + /// Ocorre quando project é nulo + public ProjectFile(EnvDTE.Project project) + { + if (ReferenceEquals(project, null)) + { + + Console.WriteLine("O Programa esta tentando criar a documentação para um projeto que não foi encontrado"); + InvalidProject = true; + } + + Path = project.Properties.Item(fullPath)?.Value?.ToString(); + AssemblyName = project.Properties.Item(assemblyName)?.Value?.ToString(); + DocName = AssemblyName + ".xml"; + UniqueName = project.UniqueName; + } + + public ProjectFile() + { + } + + public static bool operator !=(ProjectFile file1, ProjectFile file2) + { + return !(file1 == file2); + } + + public static bool operator ==(ProjectFile file1, ProjectFile file2) + { + return EqualityComparer.Default.Equals(file1, file2); + } + + public override bool Equals(object obj) + { + return Equals(obj as ProjectFile); + } + + public bool Equals(ProjectFile other) + { + return other != null && + AssemblyName == other.AssemblyName; + } + + public override int GetHashCode() + { + return -1184256330 + EqualityComparer.Default.GetHashCode(AssemblyName); + } + } +} \ No newline at end of file diff --git a/src/VisualStudio.DocumentGenerator.Vsix/GenerateMarkdown.cs b/src/VisualStudio.DocumentGenerator.Vsix/GenerateMarkdown.cs new file mode 100644 index 0000000..82bd223 --- /dev/null +++ b/src/VisualStudio.DocumentGenerator.Vsix/GenerateMarkdown.cs @@ -0,0 +1,111 @@ +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell.Interop; +using System; +using System.ComponentModel.Design; + +namespace MarkdownVsix +{ + /// Command handler + internal sealed class GenerateMarkdown + { + /// Command ID. + public const int CommandId = 0x0100; + + /// Command menu group (command set GUID). + public static readonly Guid CommandSet = new Guid("5813e236-e447-4319-a996-d3a2c1dacaf6"); + + public static readonly Guid SymbolGenDocProjectNodeGroup = new Guid("1ebc1a20-d2e7-4875-a7ff-2a3219b14685"); + public static readonly Guid SymbolGenDocSolutionFolderGroup = new Guid("1ebc1a20-d2e7-4875-a7ff-2a3219b14684"); + public static readonly Guid SymbolGenDocSolutionNode = new Guid("1ebc1a20-d2e7-4875-a7ff-2a3219b14683"); + + /// VS Package that provides this command, not null. + private readonly Package package; + + /// Gets the instance of the command. + public static GenerateMarkdown Instance + { + get; + private set; + } + + /// Gets the service provider from the owner package. + private IServiceProvider ServiceProvider + { + get + { + return this.package; + } + } + + /// + /// Initializes a new instance of the class. Adds our command + /// handlers for menu (commands must exist in the command table file) + /// + /// Owner package, not null. + private GenerateMarkdown(Package package) + { + this.package = package ?? throw new ArgumentNullException("package"); + + if (this.ServiceProvider.GetService(typeof(IMenuCommandService)) is OleMenuCommandService commandService) + { + var SymbolGenDocSolutionNodeCommandID = new CommandID(SymbolGenDocSolutionNode, 0x1050); + var solutionmenuItem = new MenuCommand(this.GenerateMarkdownForSolutions, SymbolGenDocSolutionNodeCommandID); + commandService.AddCommand(solutionmenuItem); + + var SymbolGenDocSolutionFolderGroupCommandID = new CommandID(SymbolGenDocSolutionFolderGroup, 0x1051); + var foldermenuItem = new MenuCommand(this.GenerateMarkdownForSolutions, SymbolGenDocSolutionFolderGroupCommandID); + commandService.AddCommand(foldermenuItem); + + var SymbolGenDocProjectNodeGroupCommandID = new CommandID(SymbolGenDocProjectNodeGroup, 0x1052); + var projectmenuItem = new MenuCommand(this.GenerateMarkdownForSolutions, SymbolGenDocProjectNodeGroupCommandID); + commandService.AddCommand(projectmenuItem); + } + } + + /// Initializes the singleton instance of the command. + /// Owner package, not null. + public static void Initialize(Package package) + { + Instance = new GenerateMarkdown(package); + } + + private void GenerateMarkdownForFolders(object sender, EventArgs e) + { + MenuItemCallback("Create Markdown for folders"); + Console.WriteLine("Create Markdown for Folders"); + } + + private void GenerateMarkdownForProject(object sender, EventArgs e) + { + MenuItemCallback("Create Markdown for project"); + Console.WriteLine("Create Markdown for project"); + } + + private void GenerateMarkdownForSolutions(object sender, EventArgs e) + { + MenuItemCallback("Create Markdown for solutions"); + Console.WriteLine("Create Markdown for Solutions"); + } + + /// + /// This function is the callback used to execute the command when the menu item is clicked. + /// See the constructor to see how the menu item is associated with this function using + /// OleMenuCommandService service and MenuCommand class. + /// + /// Event sender. + /// Event args. + private void MenuItemCallback(string message) + { + string title = "GenerateMarkdown"; + + // Show a message box to prove we were here + VsShellUtilities.ShowMessageBox( + this.ServiceProvider, + message, + title, + OLEMSGICON.OLEMSGICON_INFO, + OLEMSGBUTTON.OLEMSGBUTTON_OK, + OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST); + } + } +} \ No newline at end of file diff --git a/src/VisualStudio.DocumentGenerator.Vsix/GenerateMarkdownPackage.cs b/src/VisualStudio.DocumentGenerator.Vsix/GenerateMarkdownPackage.cs new file mode 100644 index 0000000..4c6c968 --- /dev/null +++ b/src/VisualStudio.DocumentGenerator.Vsix/GenerateMarkdownPackage.cs @@ -0,0 +1,124 @@ +using EnvDTE; +using EnvDTE80; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell.Interop; +using System; +using System.Collections.Generic; +using System.ComponentModel.Design; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Runtime.InteropServices; + +namespace MarkdownVsix +{ + /// This is the class that implements the package exposed by this assembly. + /// + /// + /// The minimum requirement for a class to be considered a valid package for Visual Studio is to + /// implement the IVsPackage interface and register itself with the shell. This package uses the + /// helper classes defined inside the Managed Package Framework (MPF) to do it: it derives from + /// the Package class that provides the implementation of the IVsPackage interface and uses the + /// registration attributes defined in the framework to register itself and its components with + /// the shell. These attributes tell the pkgdef creation utility what data to put into .pkgdef file. + /// + /// + /// To get loaded into VS, the package must be referred by <Asset + /// Type="Microsoft.VisualStudio.VsPackage" ...> in .vsixmanifest file. + /// + /// + [PackageRegistration(UseManagedResourcesOnly = true)] + [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)] + [ProvideMenuResource("Menus.ctmenu", 1)] + [Guid(Constants.PackageGuids.PackageGuidString)] + [ProvideAutoLoad("ADFC4E64-0397-11D1-9F4E-00A0C911004F")] + [ProvideBindingPath] + //[ProvideMenuResource(1000, 1)] // This attribute is needed to let the shell know that this package exposes some menus. + + [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1650:ElementDocumentationMustBeSpelledCorrectly", Justification = "pkgdef, VS and vsixmanifest are valid VS terms")] + public sealed class GenerateMarkdownPackage : Package + { + /// An internal collection of the commands registered by this package. + private readonly ICollection _commands = new List(); + + /// + /// The top level application instance of the VS IDE that is executing this package. + /// + private DTE2 _ide; + + /// Gets the currently active document, otherwise null. + public Document ActiveDocument + { + get + { + try + { + return IDE.ActiveDocument; + } + catch (Exception) + { + // If a project property page is active, accessing the ActiveDocument causes an exception. + return null; + } + } + } + + /// + /// Gets the top level application instance of the VS IDE that is executing this package. + /// + public DTE2 IDE => _ide ?? (_ide = (DTE2)GetService(typeof(DTE))); + + /// Gets the version of the running IDE instance. + public double IDEVersion => Convert.ToDouble(IDE.Version, CultureInfo.InvariantCulture); + + /// + /// Gets or sets a flag indicating if CodeMaid is running inside an AutoSave context. + /// + public bool IsAutoSaveContext { get; set; } + + /// Gets the menu command service. + public OleMenuCommandService MenuCommandService => GetService(typeof(IMenuCommandService)) as OleMenuCommandService; + + /// Gets the shell service. + private IVsShell ShellService => GetService(typeof(SVsShell)) as IVsShell; + + /// Initializes a new instance of the class. + public GenerateMarkdownPackage() + { + // Inside this method you can place any initialization code that does not require any + // Visual Studio service because at this point the package object is created but not + // sited yet inside Visual Studio environment. The place to do all the other + // initialization is the Initialize method. + } + + /// + /// Initialization of the package; this method is called right after the package is sited, so + /// this is the place where you can put all the initialization code that rely on services + /// provided by VisualStudio. + /// + protected override void Initialize() + { + Trace.WriteLine(string.Format(CultureInfo.CurrentCulture, "Entering Initialize() of: {0}", this)); + RegisterCommands(); + //GenerateMarkdown.Initialize(this); + base.Initialize(); + } + + /// Register the package commands (which must exist in the .vsct file). + private void RegisterCommands() + { + var menuCommandService = MenuCommandService; + if (menuCommandService != null) + { + _commands.Add(new CreateMarkdownProjectCommand(this)); + _commands.Add(new CreateMarkdownSolutionCommand(this)); + _commands.Add(new CreateMarkdownSolutionFolderCommand(this)); + // Add all commands to the menu command service. + foreach (var command in _commands) + { + menuCommandService.AddCommand(command); + } + } + } + } +} \ No newline at end of file diff --git a/src/VisualStudio.DocumentGenerator.Vsix/GenerateMarkdownPackage.vsct b/src/VisualStudio.DocumentGenerator.Vsix/GenerateMarkdownPackage.vsct new file mode 100644 index 0000000..97fb08c --- /dev/null +++ b/src/VisualStudio.DocumentGenerator.Vsix/GenerateMarkdownPackage.vsct @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/VisualStudio.DocumentGenerator.Vsix/Key.snk b/src/VisualStudio.DocumentGenerator.Vsix/Key.snk new file mode 100644 index 0000000..4227ea1 Binary files /dev/null and b/src/VisualStudio.DocumentGenerator.Vsix/Key.snk differ diff --git a/src/VisualStudio.DocumentGenerator.Vsix/LICENSE.txt b/src/VisualStudio.DocumentGenerator.Vsix/LICENSE.txt new file mode 100644 index 0000000..b0d397f --- /dev/null +++ b/src/VisualStudio.DocumentGenerator.Vsix/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Lukas Boersma + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/src/VisualStudio.DocumentGenerator.Vsix/Properties/AssemblyInfo.cs b/src/VisualStudio.DocumentGenerator.Vsix/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..88cb344 --- /dev/null +++ b/src/VisualStudio.DocumentGenerator.Vsix/Properties/AssemblyInfo.cs @@ -0,0 +1,27 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following set of attributes. +// Change these attribute values to modify the information associated with an assembly. +[assembly: AssemblyTitle("Document Generator")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Document Generator")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible to COM components. If you +// need to access a type in this assembly from COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// Version information for an assembly consists of the following four values: +// +// Major Version Minor Version Build Number Revision +// +// You can specify all the values or you can default the Build and Revision Numbers by using the '*' +// as shown below: [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: System.Runtime.InteropServices.Guid("6a84e990-e429-4d68-9042-9918da4ba488")] \ No newline at end of file diff --git a/src/VisualStudio.DocumentGenerator.Vsix/Readme.md b/src/VisualStudio.DocumentGenerator.Vsix/Readme.md new file mode 100644 index 0000000..68f420d --- /dev/null +++ b/src/VisualStudio.DocumentGenerator.Vsix/Readme.md @@ -0,0 +1 @@ +Em Construção \ No newline at end of file diff --git a/src/VisualStudio.DocumentGenerator.Vsix/Resources/GenerateMarkdown.png b/src/VisualStudio.DocumentGenerator.Vsix/Resources/GenerateMarkdown.png new file mode 100644 index 0000000..6089e92 Binary files /dev/null and b/src/VisualStudio.DocumentGenerator.Vsix/Resources/GenerateMarkdown.png differ diff --git a/src/VisualStudio.DocumentGenerator.Vsix/Resources/favicon.ico b/src/VisualStudio.DocumentGenerator.Vsix/Resources/favicon.ico new file mode 100644 index 0000000..d323b07 Binary files /dev/null and b/src/VisualStudio.DocumentGenerator.Vsix/Resources/favicon.ico differ diff --git a/src/VisualStudio.DocumentGenerator.Vsix/Resources/image.png b/src/VisualStudio.DocumentGenerator.Vsix/Resources/image.png new file mode 100644 index 0000000..6089e92 Binary files /dev/null and b/src/VisualStudio.DocumentGenerator.Vsix/Resources/image.png differ diff --git a/src/VisualStudio.DocumentGenerator.Vsix/Resources/logo.svg b/src/VisualStudio.DocumentGenerator.Vsix/Resources/logo.svg new file mode 100644 index 0000000..70f085f --- /dev/null +++ b/src/VisualStudio.DocumentGenerator.Vsix/Resources/logo.svg @@ -0,0 +1,42 @@ + + + + diff --git a/src/VisualStudio.DocumentGenerator.Vsix/SolutionHelper.cs b/src/VisualStudio.DocumentGenerator.Vsix/SolutionHelper.cs new file mode 100644 index 0000000..af740e3 --- /dev/null +++ b/src/VisualStudio.DocumentGenerator.Vsix/SolutionHelper.cs @@ -0,0 +1,135 @@ +using EnvDTE; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace MarkdownVsix +{ + /// A static helper class for working with the solution. + internal static class SolutionHelper + { + /// Gets an enumerable set of all items of the specified type within the solution. + /// The type of item to retrieve. + /// The solution. + /// The enumerable set of all items. + internal static IEnumerable GetAllItemsInSolution(Solution solution) + where T : class + { + var allProjects = new List(); + + if (solution != null) + { + allProjects.AddRange(GetItemsRecursively(solution)); + } + + return allProjects; + } + + /// + /// Gets items of the specified type recursively from the specified parent item. Includes the + /// parent item if it matches the specified type as well. + /// + /// The type of item to retrieve. + /// The parent item. + /// The enumerable set of items within the parent item, may be empty. + internal static IEnumerable GetItemsRecursively(object parentItem) + where T : class + { + if (parentItem == null) + { + throw new ArgumentNullException(nameof(parentItem)); + } + + // Create a collection. + var projectItems = new List(); + + // Include the parent item if it is of the desired type. + var desiredType = parentItem as T; + if (desiredType != null) + { + projectItems.Add(desiredType); + } + + // Get all children based on the type of parent item. + var children = GetChildren(parentItem); + + // Then recurse through all children. + foreach (var childItem in children) + { + projectItems.AddRange(GetItemsRecursively(childItem)); + } + + return projectItems; + } + + /// Gets an enumerable set of the selected project items. + /// The hosting package. + /// The enumerable set of selected project items. + internal static IEnumerable GetSelectedProjectItemsRecursively(GenerateMarkdownPackage package) + { + var selectedProjectItems = new List(); + var selectedUIHierarchyItems = UIHierarchyHelper.GetSelectedUIHierarchyItems(package); + + foreach (var item in selectedUIHierarchyItems.Select(uiHierarchyItem => uiHierarchyItem.Object)) + { + selectedProjectItems.AddRange(GetItemsRecursively(item)); + } + + return selectedProjectItems; + } + + /// + /// Gets an enumerable set of similar project items compared by file name, useful for shared projects. + /// + /// The hosting package. + /// The project item to match. + /// The enumerable set of similar project items. + internal static IEnumerable GetSimilarProjectItems(GenerateMarkdownPackage package, ProjectItem projectItem) + { + var allItems = GetAllItemsInSolution(package.IDE.Solution); + + return allItems + .Where(x => x.Name == projectItem.Name && x.Kind == projectItem.Kind && x.Document.FullName == projectItem.Document.FullName); + } + + /// Gets the children of the specified parent item if applicable. + /// The parent item. + /// An enumerable set of children, may be empty. + private static IEnumerable GetChildren(object parentItem) + { + // First check if the item is a solution. + var solution = parentItem as Solution; + if (solution?.Projects != null) + { + return solution.Projects.Cast().Cast().ToList(); + } + + // Next check if the item is a project. + var project = parentItem as Project; + if (project?.ProjectItems != null) + { + return project.ProjectItems.Cast().Cast().ToList(); + } + + // Next check if the item is a project item. + var projectItem = parentItem as ProjectItem; + if (projectItem != null) + { + // Standard projects. + if (projectItem.ProjectItems != null) + { + return projectItem.ProjectItems.Cast().Cast().ToList(); + } + + // Projects within a solution folder. + if (projectItem.SubProject != null) + { + return new[] { projectItem.SubProject }; + } + } + + // Otherwise return an empty array. + return new object[0]; + } + } +} \ No newline at end of file diff --git a/src/VisualStudio.DocumentGenerator.Vsix/UIHierarchyHelper.cs b/src/VisualStudio.DocumentGenerator.Vsix/UIHierarchyHelper.cs new file mode 100644 index 0000000..913249f --- /dev/null +++ b/src/VisualStudio.DocumentGenerator.Vsix/UIHierarchyHelper.cs @@ -0,0 +1,55 @@ +using EnvDTE; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace MarkdownVsix +{ + /// A static helper class for working with the UI hierarchies. + internal static class UIHierarchyHelper + { + /// Gets an enumerable set of the selected UI hierarchy items. + /// The hosting package. + /// The enumerable set of selected UI hierarchy items. + internal static IEnumerable GetSelectedUIHierarchyItems(GenerateMarkdownPackage package) + { + var solutionExplorer = GetSolutionExplorer(package); + + return ((object[])solutionExplorer.SelectedItems).Cast().ToList(); + } + + /// Gets the solution explorer for the specified hosting package. + /// The hosting package. + /// The solution explorer. + internal static UIHierarchy GetSolutionExplorer(GenerateMarkdownPackage package) + { + return package.IDE.ToolWindows.SolutionExplorer; + } + + /// Gets the top level (solution) UI hierarchy item. + /// The hosting package. + /// The top level (solution) UI hierarchy item, otherwise null. + internal static UIHierarchyItem GetTopUIHierarchyItem(GenerateMarkdownPackage package) + { + var solutionExplorer = GetSolutionExplorer(package); + + return solutionExplorer.UIHierarchyItems.Count > 0 + ? solutionExplorer.UIHierarchyItems.Item(1) + : null; + } + + /// Determines whether the specified item has any expanded children. + /// The parent item. + /// True if there are expanded children, false otherwise. + internal static bool HasExpandedChildren(UIHierarchyItem parentItem) + { + if (parentItem == null) + { + throw new ArgumentNullException(nameof(parentItem)); + } + + return parentItem.UIHierarchyItems.Cast().Any( + childItem => childItem.UIHierarchyItems.Expanded || HasExpandedChildren(childItem)); + } + } +} \ No newline at end of file diff --git a/src/VisualStudio.DocumentGenerator.Vsix/VSPackage.resx b/src/VisualStudio.DocumentGenerator.Vsix/VSPackage.resx new file mode 100644 index 0000000..05d7f36 --- /dev/null +++ b/src/VisualStudio.DocumentGenerator.Vsix/VSPackage.resx @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + GenerateMarkdown Extension + + + GenerateMarkdown Visual Studio Extension Detailed Info + + + Resources\favicon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/src/VisualStudio.DocumentGenerator.Vsix/VisualStudio.DocumentGenerator.Vsix.csproj b/src/VisualStudio.DocumentGenerator.Vsix/VisualStudio.DocumentGenerator.Vsix.csproj new file mode 100644 index 0000000..c937626 --- /dev/null +++ b/src/VisualStudio.DocumentGenerator.Vsix/VisualStudio.DocumentGenerator.Vsix.csproj @@ -0,0 +1,245 @@ + + + + + 15.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + true + + + + true + + + Key.snk + + + + + + + + Debug + AnyCPU + 2.0 + {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + {3CF8B458-7D40-4207-9F76-3AAADCEA8344} + Library + Properties + VisualStudio.DocumentGenerator.Vsix + VisualStudio.DocumentGenerator.Vsix + v4.6.1 + true + true + true + true + true + false + Program + $(DevEnvDir)devenv.exe + /rootsuffix Exp + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + bin\Release\VisualStudio.DocumentGenerator.Vsix.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + Designer + + + + + Menus.ctmenu + Designer + + + Always + true + + + Always + true + + + Always + true + + + Always + true + + + Always + true + + + + + + + False + + + False + + + False + + + False + + + + False + + + ..\..\packages\Microsoft.VisualStudio.CoreUtility.15.4.27004\lib\net45\Microsoft.VisualStudio.CoreUtility.dll + True + + + ..\..\packages\Microsoft.VisualStudio.Imaging.15.4.27004\lib\net45\Microsoft.VisualStudio.Imaging.dll + True + + + ..\packages\Microsoft.VisualStudio.OLE.Interop.7.10.6071\lib\Microsoft.VisualStudio.OLE.Interop.dll + True + + + ..\..\packages\Microsoft.VisualStudio.Shell.15.0.15.4.27004\lib\Microsoft.VisualStudio.Shell.15.0.dll + True + + + ..\..\packages\Microsoft.VisualStudio.Shell.Framework.15.4.27004\lib\net45\Microsoft.VisualStudio.Shell.Framework.dll + True + + + ..\packages\Microsoft.VisualStudio.Shell.Interop.7.10.6071\lib\Microsoft.VisualStudio.Shell.Interop.dll + True + + + True + ..\packages\Microsoft.VisualStudio.Shell.Interop.10.0.10.0.30319\lib\Microsoft.VisualStudio.Shell.Interop.10.0.dll + True + + + True + ..\packages\Microsoft.VisualStudio.Shell.Interop.11.0.11.0.61030\lib\Microsoft.VisualStudio.Shell.Interop.11.0.dll + True + + + True + ..\packages\Microsoft.VisualStudio.Shell.Interop.12.0.12.0.30110\lib\Microsoft.VisualStudio.Shell.Interop.12.0.dll + True + + + ..\..\packages\Microsoft.VisualStudio.Shell.Interop.15.3.DesignTime.15.0.26606\lib\net20\Microsoft.VisualStudio.Shell.Interop.15.3.DesignTime.dll + True + + + ..\packages\Microsoft.VisualStudio.Shell.Interop.8.0.8.0.50727\lib\Microsoft.VisualStudio.Shell.Interop.8.0.dll + True + + + ..\packages\Microsoft.VisualStudio.Shell.Interop.9.0.9.0.30729\lib\Microsoft.VisualStudio.Shell.Interop.9.0.dll + True + + + ..\packages\Microsoft.VisualStudio.TextManager.Interop.7.10.6070\lib\Microsoft.VisualStudio.TextManager.Interop.dll + True + + + ..\packages\Microsoft.VisualStudio.TextManager.Interop.8.0.8.0.50727\lib\Microsoft.VisualStudio.TextManager.Interop.8.0.dll + True + + + ..\..\packages\Microsoft.VisualStudio.Threading.15.4.4\lib\net45\Microsoft.VisualStudio.Threading.dll + True + + + ..\..\packages\Microsoft.VisualStudio.Utilities.15.4.27004\lib\net46\Microsoft.VisualStudio.Utilities.dll + True + + + ..\..\packages\Microsoft.VisualStudio.Validation.15.3.32\lib\net45\Microsoft.VisualStudio.Validation.dll + True + + + False + + + + + + + + + + + + true + VSPackage + Designer + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + \ No newline at end of file diff --git a/src/VisualStudio.DocumentGenerator.Vsix/app.config b/src/VisualStudio.DocumentGenerator.Vsix/app.config new file mode 100644 index 0000000..d8415d0 --- /dev/null +++ b/src/VisualStudio.DocumentGenerator.Vsix/app.config @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/VisualStudio.DocumentGenerator.Vsix/index.html b/src/VisualStudio.DocumentGenerator.Vsix/index.html new file mode 100644 index 0000000..00beadb --- /dev/null +++ b/src/VisualStudio.DocumentGenerator.Vsix/index.html @@ -0,0 +1,64 @@ + + + + + + + + Getting Started + + + +
+ + +
+
+

Creating a Visual Studio Extension

+ +

This project enables developers to create an extension for Visual Studio. The solution contains a VSIX project that packages the extension into a VSIX file. This file is used to install an extension for Visual Studio.

+

Add new features

+ +
    +
  1. Right-click the project node in Solution Explorer and select Add>New Item.
  2. +
  3. In the Add New Item dialog box, expand the Extensibility node under Visual C# or Visual Basic.
  4. +
  5. Choose from the available item templates: Visual Studio Package, Editor Items (Classifier, Margin, Text Adornment, Viewport Adornment), Command, Tool Window, Toolbox Control, and then click Add.
  6. +
+ +

The files for the template that you selected are added to the project. You can start adding functionality to your item template, press F5 to run the project, or add additional item templates.

+ +

Run and debug

+

To run the project, press F5. Visual Studio will:

+ +
    +
  • Build the extension from the VSIX project.
  • +
  • Create a VSIX package from the VSIX project.
  • +
  • When debugging, start an experimental instance of Visual Studio with the VSIX package installed.
  • +
+ +

In the experimental instance of Visual Studio you can test out the functionality of your extension without affecting your Visual Studio installation.

+
+
+
+

Visual Studio Extensibility Resources

+ +
    +
  1. Visual Studio documentation
    Detailed documentation and API reference material for building extensions.
  2. +
  3. Extension samples on GitHub
    Use a sample project to kickstart your development.
  4. +
  5. Extensibility chat room on Gitter
    Meet other extension developers and exchange tips and tricks for extension development.
  6. +
  7. Channel 9 videos on extensibility
    Watch videos from the product team on Visual Studio extensibility.
  8. +
  9. Extensibility Tools
    Install an optional helper tool that adds extra IDE support for extension authors.
  10. +
+

Give us feedback

+ +
+
+
+
+ + \ No newline at end of file diff --git a/src/VisualStudio.DocumentGenerator.Vsix/packages.config b/src/VisualStudio.DocumentGenerator.Vsix/packages.config new file mode 100644 index 0000000..9797709 --- /dev/null +++ b/src/VisualStudio.DocumentGenerator.Vsix/packages.config @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/VisualStudio.DocumentGenerator.Vsix/source.extension.vsixmanifest b/src/VisualStudio.DocumentGenerator.Vsix/source.extension.vsixmanifest new file mode 100644 index 0000000..f6243e5 --- /dev/null +++ b/src/VisualStudio.DocumentGenerator.Vsix/source.extension.vsixmanifest @@ -0,0 +1,25 @@ + + + + + Document Generator + An open source extension that will automate the documentation of your C# class. + LICENSE.txt + index.html + Resources/image.png + Tools;Documentation + + + + + + + + + + + + + + + diff --git a/src/VisualStudio.DocumentGenerator.Vsix/stylesheet.css b/src/VisualStudio.DocumentGenerator.Vsix/stylesheet.css new file mode 100644 index 0000000..8d0c276 --- /dev/null +++ b/src/VisualStudio.DocumentGenerator.Vsix/stylesheet.css @@ -0,0 +1,126 @@ +body { + margin: 0; + padding: 0; + border: 0; + color: #1E1E1E; + font-size: 13px; + font-family: "Segoe UI", Helvetica, Arial, sans-serif; + line-height: 1.45; + word-wrap: break-word; +} + +/* General & 'Reset' Stuff */ + +.container { + width: 980px; + margin: 0 auto; +} + +section { + display: block; + margin: 0; +} + +h1, h2, h3, h4, h5, h6 { + margin: 0; +} + +/* Header,
+ header - container + h1 - project name + h2 - project description +*/ + +#header { + color: #FFF; + background: #68217a; + position:relative; +} +#hangcloud { + width: 190px; + height: 160px; + background: url("../images/bannerart03.png"); + position: absolute; + top: 0; + right: -30px; +} +h1, h2 { + font-family: "Segoe UI Light", "Segoe UI", Helvetica, Arial, sans-serif; + line-height: 1; + margin: 0 18px; + padding: 0; +} +#header h1 { + font-size: 3.4em; + padding-top: 18px; + font-weight: normal; + margin-left: 15px; +} + +#header h2 { + font-size: 1.5em; + margin-top: 10px; + padding-bottom: 18px; + font-weight: normal; +} + +#main_content { + width: 100%; + display: flex; + flex-direction: row; +} + +h1, h2, h3, h4, h5, h6 { + font-weight: bolder; +} + +#main_content h1 { + font-size: 1.8em; + margin-top: 34px; +} + + #main_content h1:first-child { + margin-top: 30px; + } + +#main_content h2 { + font-size: 1.4em; + font-weight: bold; +} +p, ul { + margin: 11px 18px; +} + +#main_content a { + color: #06C; + text-decoration: none; +} +ul { + margin-top: 13px; + margin-left: 18px; + padding-left: 0; +} + ul li { + margin-left: 18px; + padding-left: 0; + } +#lpanel { + width: 620px; + float: left; +} +#rpanel ul { + list-style-type: none; + width: 300px; +} + #rpanel ul li { + line-height: 1.8em; + } +#rpanel { + background: #e7e7e7; + width: 360px; + float: right; +} + +#rpanel div { + width: 300px; +} \ No newline at end of file