コード例 #1
0
        /// <summary>
        /// Creates the XML open tag string for an XElement.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns>The XML open tag. In case of an element without value, the tag is self-closing.</returns>
        private static string CreateXmlOpenTag(XElement element, IXmlTagOptions options)
        {
            var builder = new StringBuilder();
            var name    = element.Name.LocalName;

            builder.Append("<");

            builder.Append(TagCase(name, options.Case));

            if (element.HasAttributes)
            {
                foreach (var attr in element.Attributes())
                {
                    builder.Append(CodeCommentHelper.Spacer);
                    builder.Append(attr);
                }
            }

            if (element.IsEmpty)
            {
                if (options.SpaceSelfClosing)
                {
                    builder.Append(CodeCommentHelper.Spacer);
                }

                builder.Append("/");
            }

            builder.Append(">");

            var result = builder.ToString();

            return(options.KeepTogether ? CodeCommentHelper.SpaceToFake(result) : result);
        }
コード例 #2
0
        /// <summary>
        /// Reformat all comments between the specified start and end point. Comments that start
        /// within the range, even if they overlap the end are included.
        /// </summary>
        /// <param name="textDocument">The text document.</param>
        /// <param name="start">The start point.</param>
        /// <param name="end">The end point.</param>
        public bool FormatComments(TextDocument textDocument, EditPoint start, EditPoint end)
        {
            bool foundComments = false;
            int  tabSize       = CodeCommentHelper.GetTabSize(_package, textDocument);

            while (start.Line <= end.Line)
            {
                if (CodeCommentHelper.IsCommentLine(start))
                {
                    var comment = new CodeComment(start, tabSize);
                    if (comment.IsValid)
                    {
                        comment.Format();
                        foundComments = true;
                    }

                    if (comment.EndPoint != null)
                    {
                        start = comment.EndPoint.CreateEditPoint();
                    }
                }

                if (start.Line == textDocument.EndPoint.Line)
                {
                    break;
                }

                start.LineDown();
                start.StartOfLine();
            }

            return(foundComments);
        }
コード例 #3
0
        /// <summary>
        /// Reformat all comments between the specified start and end point. Comments that start
        /// within the range, even if they overlap the end are included.
        /// </summary>
        /// <param name="textDocument">The text document.</param>
        /// <param name="start">The start point.</param>
        /// <param name="end">The end point.</param>
        public bool FormatComments(TextDocument textDocument, EditPoint start, EditPoint end)
        {
            var options = new CodeCommentOptions(Settings.Default, _package, textDocument);

            bool foundComments = false;

            while (start.Line <= end.Line)
            {
                if (CodeCommentHelper.IsCommentLine(start))
                {
                    var comment = new CodeComment(start);
                    if (comment.IsValid)
                    {
                        comment.Format(options);
                        foundComments = true;
                    }

                    if (comment.EndPoint != null)
                    {
                        start = comment.EndPoint.CreateEditPoint();
                    }
                }

                if (start.Line == textDocument.EndPoint.Line)
                {
                    break;
                }

                start.LineDown();
                start.StartOfLine();
            }

            return(foundComments);
        }
コード例 #4
0
        public static string Format(string text)
        {
            var xml       = XElement.Parse(string.Format("<doc>{0}</doc>", text));
            var line      = new CommentLineXml(xml);
            var regex     = CodeCommentHelper.GetCommentRegex("CSharp", false);
            var formatter = new CommentFormatter(line, string.Empty, 4, regex);

            return(formatter.ToString());
        }
コード例 #5
0
ファイル: CodeComment.cs プロジェクト: zer09/codemaid
        /// <summary>
        /// Helper function to generate the preview in the options menu.
        /// </summary>
        public static string FormatXml(string text)
        {
            var xml       = XElement.Parse($"<doc>{text}</doc>");
            var line      = new CommentLineXml(xml);
            var regex     = CodeCommentHelper.GetCommentRegex(CodeLanguage.CSharp, false);
            var formatter = new CommentFormatter(line, "///", 4, regex);

            return(formatter.ToString());
        }
コード例 #6
0
        /// <summary>
        /// Helper function to generate the preview in the options menu.
        /// </summary>
        public static string FormatXml(string text, CodeCommentOptions options)
        {
            var xml       = XElement.Parse(string.Format("<doc>{0}</doc>", text));
            var line      = new CommentLineXml(xml, options);
            var regex     = CodeCommentHelper.GetCommentRegex("CSharp", false);
            var formatter = new CommentFormatter(line, "///", options, regex);

            return(formatter.ToString());
        }
コード例 #7
0
        public static string Format(string text, string prefix)
        {
            var xml       = XElement.Parse($"<doc>{text}</doc>");
            var line      = new CommentLineXml(xml);
            var regex     = CodeCommentHelper.GetCommentRegex(CodeLanguage.CSharp, !string.IsNullOrEmpty(prefix));
            var formatter = new CommentFormatter(line, prefix, 4, regex);

            return(formatter.ToString());
        }
コード例 #8
0
ファイル: CommentFormatter.cs プロジェクト: zhyifei/codemaid
 private void Append(string value)
 {
     if (String.IsNullOrEmpty(value))
     {
         return;
     }
     _builder.Append(Settings.Default.Formatting_CommentXmlKeepTagsTogether ? CodeCommentHelper.FakeToSpace(value) : value);
     _currentPosition += WordLength(value);
     _isFirstWord      = false;
 }
コード例 #9
0
ファイル: CodeComment.cs プロジェクト: vavjeeva/codemaid
        /// <summary>
        /// Formats the comment.
        /// </summary>
        public TextPoint Format()
        {
            if (!IsValid)
            {
                throw new InvalidOperationException("Cannot format comment, the comment is not valid.");
            }

            var originalText = _startPoint.GetText(_endPoint);
            var matches      = _commentLineRegex.Matches(originalText).OfType <Match>().ToArray();

            var commentOptions = new CommentOptions
            {
                Prefix = matches.First(m => m.Success).Groups["prefix"].Value ?? string.Empty,
                Regex  = CodeCommentHelper.GetCommentRegex(_document.GetCodeLanguage(), false)
            };

            // Concatenate the comment lines without comment prefixes and see if the resulting bit
            // can be parsed as XML.
            ICommentLine line        = null;
            var          lineTexts   = matches.Select(m => m.Groups["line"].Value).ToArray();
            var          commentText = string.Join(Environment.NewLine, lineTexts);

            if (commentText.Contains('<'))
            {
                try
                {
                    var xml = XElement.Parse($"<doc>{commentText}</doc>");
                    line = new CommentLineXml(xml);
                }
                catch (System.Xml.XmlException)
                {
                    // If XML cannot be parsed, comment will be handled as a normal text comment.
                }
            }

            if (line == null)
            {
                line = new CommentLine(commentText);
            }

            var formatter = new CommentFormatter(
                line,
                _formatterOptions,
                commentOptions);

            if (!formatter.Equals(originalText))
            {
                var cursor = StartPoint.CreateEditPoint();
                cursor.Delete(EndPoint);
                cursor.Insert(formatter.ToString());
                _endPoint = cursor.CreateEditPoint();
            }

            return(EndPoint);
        }
コード例 #10
0
        /// <summary>
        /// Initializes a new instance of the <see cref="CodeComment" /> class.
        /// </summary>
        public CodeComment(TextPoint point)
        {
            if (point == null)
            {
                throw new ArgumentNullException("point");
            }

            _document = point.Parent;

            _commentLineRegex = CodeCommentHelper.GetCommentRegex(_document.Language, true);

            Expand(point);
        }
コード例 #11
0
        /// <summary>
        /// Called to update the current status of the command.
        /// </summary>
        protected override void OnBeforeQueryStatus()
        {
            var activeTextDocument = ActiveTextDocument;
            var enable             = false;

            if (activeTextDocument != null)
            {
                // Enable formatting if there is a comment pattern defined for this document.
                enable = CodeCommentHelper.GetCommentPrefix(activeTextDocument) != null;
            }

            Enabled = enable;
        }
コード例 #12
0
ファイル: CodeComment.cs プロジェクト: vavjeeva/codemaid
        /// <summary>
        /// Initializes a new instance of the <see cref="CodeComment" /> class.
        /// </summary>
        public CodeComment(TextPoint point, FormatterOptions options)
        {
            if (point == null)
            {
                throw new ArgumentNullException(nameof(point));
            }

            _document         = point.Parent;
            _commentLineRegex = CodeCommentHelper.GetCommentRegex(_document.GetCodeLanguage());
            _formatterOptions = options;

            Expand(point);
        }
コード例 #13
0
ファイル: CodeComment.cs プロジェクト: zer09/codemaid
        /// <summary>
        /// Initializes a new instance of the <see cref="CodeComment" /> class.
        /// </summary>
        public CodeComment(TextPoint point, int tabSize)
        {
            if (point == null)
            {
                throw new ArgumentNullException(nameof(point));
            }

            _document         = point.Parent;
            _commentLineRegex = CodeCommentHelper.GetCommentRegex(_document.GetCodeLanguage());
            _tabSize          = tabSize;

            Expand(point);
        }
コード例 #14
0
        /// <summary>
        /// Called to execute the command.
        /// </summary>
        protected override void OnExecute()
        {
            base.OnExecute();

            var activeTextDocument = ActiveTextDocument;

            if (activeTextDocument != null && activeTextDocument.Selection != null)
            {
                var prefix = CodeCommentHelper.GetCommentPrefix(activeTextDocument);
                if (prefix != null)
                {
                    var selection = activeTextDocument.Selection;

                    EditPoint start;
                    EditPoint end;

                    if (selection.IsEmpty)
                    {
                        start = selection.ActivePoint.CreateEditPoint();
                        end   = start.CreateEditPoint();
                        end.EndOfLine();
                    }
                    else
                    {
                        start = selection.TopPoint.CreateEditPoint();
                        start.StartOfLine();
                        end = selection.BottomPoint.CreateEditPoint();
                        end.EndOfLine();
                    }

                    bool foundComments = false;
                    _undoTransactionHelper.Run(() => foundComments = _commentFormatLogic.FormatComments(activeTextDocument, start, end));

                    if (foundComments)
                    {
                        Package.IDE.StatusBar.Text = Resources.CodeMaidFinishedFormattingTheComment;
                    }
                    else
                    {
                        Package.IDE.StatusBar.Text = string.Format(
                            foundComments
                                ? Resources.CodeMaidFinishedFormattingTheComments0
                                : Resources.CodeMaidDidNotFindANonCodeComment0ToReformat,
                            selection.IsEmpty ? Resources.UnderTheCursor : Resources.InTheSelection
                            );
                    }
                }
            }
        }
コード例 #15
0
        /// <summary>
        /// Called to execute the command.
        /// </summary>
        protected override void OnExecute()
        {
            base.OnExecute();

            var activeTextDocument = ActiveTextDocument;

            if (activeTextDocument != null && activeTextDocument.Selection != null)
            {
                var prefix = CodeCommentHelper.GetCommentPrefix(activeTextDocument);
                if (prefix != null)
                {
                    var selection = activeTextDocument.Selection;

                    EditPoint start;
                    EditPoint end;

                    if (selection.IsEmpty)
                    {
                        start = selection.ActivePoint.CreateEditPoint();
                        end   = start.CreateEditPoint();
                        end.EndOfLine();
                    }
                    else
                    {
                        start = selection.TopPoint.CreateEditPoint();
                        start.StartOfLine();
                        end = selection.BottomPoint.CreateEditPoint();
                        end.EndOfLine();
                    }

                    bool foundComments = false;
                    _undoTransactionHelper.Run(() => foundComments = _commentFormatLogic.FormatComments(activeTextDocument, start, end));

                    if (foundComments)
                    {
                        Package.IDE.StatusBar.Text = "CodeMaid finished formatting the comment.";
                    }
                    else
                    {
                        Package.IDE.StatusBar.Text = string.Format(
                            foundComments
                                ? "CodeMaid finished formatting the comments {0}."
                                : "CodeMaid did not find a non-code comment {0} to reformat.",
                            selection.IsEmpty ? "under the cursor" : "in the selection"
                            );
                    }
                }
            }
        }
コード例 #16
0
        /// <summary>
        /// Called to update the current status of the command.
        /// </summary>
        protected override void OnBeforeQueryStatus()
        {
            var activeTextDocument = ActiveTextDocument;
            var enable             = false;

            // Disable comment formatting if using POSIX Regular Expressions (i.e. pre-Visual Studio
            // 11 versions) since not supported.
            if (activeTextDocument != null && !Package.UsePOSIXRegEx)
            {
                // Enable formatting if there is a comment pattern defined for this document.
                enable = CodeCommentHelper.GetCommentPrefix(activeTextDocument) != null;
            }

            Enabled = enable;
        }
コード例 #17
0
ファイル: CommandGenerator.cs プロジェクト: reinux/ZigbeeNet
 private void AddCodeComment(CodeTypeMember codeTypeMember, IEnumerable <ICodeCommentEntity> codeComments, bool isDocComment)
 {
     if (isDocComment)
     {
         CodeCommentStatementCollection descriptionCodeComment = CodeCommentHelper.BuildCodeCommentStatementCollection(codeComments);
         codeTypeMember.Comments.AddRange(descriptionCodeComment);
     }
     else
     {
         foreach (var codeComment in codeComments)
         {
             CodeCommentStatement descriptionCodeComment = CodeCommentHelper.BuildCodeCommentStatement(codeComment, isDocComment);
             codeTypeMember.Comments.Add(descriptionCodeComment);
         }
     }
 }
コード例 #18
0
        public CommentLineXml(XElement xml, CodeCommentOptions options)
            : base(null)
        {
            TagName = xml.Name.LocalName;

            // Tags that are forced to be their own line should never be self closing. This prevents
            // empty tags from getting collapsed.
            OpenTag  = CodeCommentHelper.CreateXmlOpenTag(xml, options, false);
            Closetag = CodeCommentHelper.CreateXmlCloseTag(xml, options, false);

            Lines = new List <ICommentLine>();

            _innerText = new StringBuilder();
            ParseChildNodes(xml, options);
            CloseInnerText();
        }
        /// <summary>
        /// Reformat all comments between the specified start and end point. Comments that start
        /// within the range, even if they overlap the end are included.
        /// </summary>
        /// <param name="textDocument">The text document.</param>
        /// <param name="start">The start point.</param>
        /// <param name="end">The end point.</param>
        public bool FormatComments(TextDocument textDocument, EditPoint start, EditPoint end)
        {
            bool foundComments = false;

            var options = FormatterOptions
                          .FromSettings(Settings.Default)
                          .Set(o =>
            {
                o.TabSize      = textDocument.TabSize;
                o.IgnoreTokens = CodeCommentHelper
                                 .GetTaskListTokens(_package)
                                 .Concat(Settings.Default.Formatting_IgnoreLinesStartingWith.Cast <string>())
                                 .ToArray();
            });

            while (start.Line <= end.Line)
            {
                if (CodeCommentHelper.IsCommentLine(start))
                {
                    var comment = new CodeComment(start, options);

                    if (comment.IsValid)
                    {
                        comment.Format();
                        foundComments = true;
                    }

                    if (comment.EndPoint != null)
                    {
                        start = comment.EndPoint.CreateEditPoint();
                    }
                }

                if (start.Line == textDocument.EndPoint.Line)
                {
                    break;
                }

                start.LineDown();
                start.StartOfLine();
            }

            return(foundComments);
        }
コード例 #20
0
ファイル: CommandGenerator.cs プロジェクト: reinux/ZigbeeNet
        private void CreateStructureClass(Structure structure)
        {
            string className = structure.Name.UpperCaseFirstCharacter();

            Console.WriteLine($"Processing structure class {structure.Name}  [{className}()]");

            CreateCompileUnit(out CodeCompileUnit compileUnit, out CodeNamespace codeNamespace, _ezspStructurePackage);
            CodeTypeDeclaration protocolClass = new CodeTypeDeclaration(className)
            {
                IsClass        = true,
                TypeAttributes = System.Reflection.TypeAttributes.Public
            };

            AddNamespaceImport(codeNamespace, _serializerPackage);

            StringBuilder descriptionStringBuilder = new StringBuilder();

            descriptionStringBuilder.AppendLine($"Class to implement the Ember Structure \" {structure.Name} \".");
            if (!string.IsNullOrEmpty(structure.Description))
            {
                OutputWithLineBreak(descriptionStringBuilder, "", structure.Description);
            }
            ICodeCommentEntity descriptionCodeCommentEntity = new CodeCommentEntity
            {
                Tag = CodeCommentTag.Summary,
                DocumentationText = descriptionStringBuilder.ToString()
            };
            CodeCommentStatement descriptionCodeComment = CodeCommentHelper.BuildCodeCommentStatement(descriptionCodeCommentEntity, true);

            protocolClass.Comments.Add(descriptionCodeComment);

            codeNamespace.Types.Add(protocolClass);

            CreateStructureConstructor(protocolClass);
            CreateStructureConstructor(protocolClass, true);
            CreateParameters(codeNamespace, protocolClass, structure.Parameters);
            CreateParameterSetters(structure.Parameters, codeNamespace, protocolClass);
            CreateParameterGetter(structure.Parameters, codeNamespace, protocolClass);
            CreateStructureSerializer(structure.Parameters, protocolClass);
            CreateStructureDeserializer(structure.Parameters, protocolClass);
            CreateToStringOverride(className, structure.Parameters, protocolClass);

            GenerateCode(compileUnit, className, "Structure/");
        }
コード例 #21
0
ファイル: CodeComment.cs プロジェクト: vavjeeva/codemaid
        /// <summary>
        /// Helper function to generate the preview in the options menu.
        /// </summary>
        public static string FormatXml(string text, string prefix = "///")
        {
            var xml = XElement.Parse($"<doc>{text}</doc>");

            var formatter = new CommentFormatter(
                new CommentLineXml(xml),
                new FormatterOptions
            {
                IgnoreTokens = new[] { "TODO: " },
                TabSize      = 4
            },
                new CommentOptions
            {
                Prefix = prefix,
                Regex  = CodeCommentHelper.GetCommentRegex(CodeLanguage.CSharp, !string.IsNullOrWhiteSpace(prefix))
            });

            return(formatter.ToString());
        }
コード例 #22
0
        /// <summary>
        /// Gets a starting point adjusted for leading comments.
        /// </summary>
        /// <param name="originalPoint">The original point.</param>
        /// <returns>The adjusted starting point.</returns>
        private static EditPoint GetStartPointAdjustedForComments(TextPoint originalPoint)
        {
            var commentPrefix = CodeCommentHelper.GetCommentPrefix(originalPoint.Parent);
            var point         = originalPoint.CreateEditPoint();

            while (point.Line > 1)
            {
                string text = point.GetLines(point.Line - 1, point.Line);

                if (RegexNullSafe.IsMatch(text, @"^\s*" + commentPrefix))
                {
                    point.LineUp();
                    point.StartOfLine();
                }
                else
                {
                    break;
                }
            }

            return(point);
        }
        /// <summary>
        /// Helper function to generate the preview in the options menu.
        /// </summary>
        public static string Format(string text, string prefix = null, Action <FormatterOptions> options = null)
        {
            var xml = XElement.Parse($"<doc>{text}</doc>");

            var formatterOptions = FormatterOptions
                                   .FromSettings(Properties.Settings.Default)
                                   .Set(o => o.IgnoreTokens = new[] { "TODO: " });

            options?.Invoke(formatterOptions);

            var commentOptions = new CommentOptions
            {
                Prefix = prefix,
                Regex  = CodeCommentHelper.GetCommentRegex(CodeLanguage.CSharp, !string.IsNullOrWhiteSpace(prefix))
            };

            var formatter = new CommentFormatter(
                new CommentLineXml(xml, formatterOptions),
                formatterOptions,
                commentOptions);

            return(formatter.ToString());
        }
コード例 #24
0
        private EditPoint Expand(TextPoint point, Action <EditPoint> foundAction)
        {
            EditPoint i      = point.CreateEditPoint();
            EditPoint result = null;

            do
            {
                var line = i.Line;
                var text = i.GetLine();

                if (CodeCommentHelper.LineMatchesRegex(i, _commentLineRegex).Success)
                {
                    result = i.CreateEditPoint();
                    foundAction(i);

                    // If result and iterator line are the same, the found action (move line up or
                    // down) did nothing. This means there is no point to keep searching, it would
                    // create an infinite loop.
                    if (result.Line == i.Line)
                    {
                        break;
                    }
                }
                else
                {
                    if (i != null && result != null && CodeCommentHelper.LineMatchesRegex(i, _codeLineRegex).Success)
                    {
                        result = null;
                    }

                    i = null;
                }
            } while (i != null);

            return(result);
        }
コード例 #25
0
        private void ParseChildNodes(XElement xml, CodeCommentOptions options)
        {
            if (string.Equals(TagName, "code", StringComparison.OrdinalIgnoreCase))
            {
                // Content of code element should be read literally and preserve whitespace.
                using (var reader = xml.CreateReader())
                {
                    reader.MoveToContent();
                    Content = reader.ReadInnerXml();
                }
            }
            else
            {
                // Loop and parse all child nodes.
                var node = xml.FirstNode;
                while (node != null)
                {
                    // If the node is a sub-element, it needs to be handled seperately.
                    if (node.NodeType == XmlNodeType.Element)
                    {
                        var e = (XElement)node;

                        // All root level elements and certain special sub elements always need to
                        // be on their own line.
                        if (e.Parent == null || e.Parent.Parent == null || NewLineElementNames.Contains(e.Name.LocalName, StringComparer.OrdinalIgnoreCase))
                        {
                            CloseInnerText();
                            Lines.Add(new CommentLineXml(e, options));
                        }
                        else
                        {
                            // If the tag is not forced to be on it's own line, append it to the
                            // current content as string.
                            _innerText.Append(CodeCommentHelper.CreateXmlOpenTag(e, options));

                            if (!e.IsEmpty)
                            {
                                if (options.XmlSpaceTagContent)
                                {
                                    _innerText.Append(CodeCommentHelper.Spacer);
                                }

                                ParseChildNodes(e, options);

                                _innerText.Append(CodeCommentHelper.CreateXmlCloseTag(e, options));
                            }

                            _innerText.Append(CodeCommentHelper.Spacer);
                        }
                    }
                    else
                    {
                        // Always trim trailing
                        var value = node.ToString().TrimEnd(CodeCommentHelper.Spacer);

                        // If the parent is an element, trim the starting spaces.
                        if (node.PreviousNode == null && node.Parent.NodeType == XmlNodeType.Element && !options.XmlSpaceTagContent)
                        {
                            value = value.TrimStart(CodeCommentHelper.Spacer);
                        }

                        _innerText.Append(value);

                        // Add spacing after (almost) each word.
                        if (node.NextNode != null || node.Parent.NodeType != XmlNodeType.Element || options.XmlSpaceTagContent)
                        {
                            _innerText.Append(CodeCommentHelper.Spacer);
                        }
                    }

                    node = node.NextNode;
                }
            }
        }
コード例 #26
0
 /// <summary>
 /// Initializes a new instance of the <see cref="CodeCommentOptions" /> class.
 /// </summary>
 /// <param name="settings">The settings container.</param>
 /// <param name="package">The hosting package.</param>
 /// <param name="document">The text document.</param>
 public CodeCommentOptions(Settings settings, CodeMaidPackage package, TextDocument document)
     : this(settings, CodeCommentHelper.GetTabSize(package, document))
 {
 }
コード例 #27
0
        private void ParseChildNodes(XElement xml)
        {
            if (string.Equals(TagName, "code", StringComparison.OrdinalIgnoreCase))
            {
                // Content of code element should be read literally and preserve whitespace.
                using (var reader = xml.CreateReader())
                {
                    reader.MoveToContent();
                    Content = reader.ReadInnerXml();
                }
            }
            else
            {
                // Loop and parse all child nodes.
                var node = xml.FirstNode;
                while (node != null)
                {
                    // If the node is a sub-element, it needs to be handled seperately.
                    if (node.NodeType == XmlNodeType.Element)
                    {
                        var e = (XElement)node;

                        if (ShouldBeNewLine(e))
                        {
                            CloseInnerText();
                            Lines.Add(new CommentLineXml(e));
                        }
                        else
                        {
                            // If the tag is not forced to be on it's own line, append it to the
                            // current content as string.
                            _innerText.Append(CodeCommentHelper.CreateXmlOpenTag(e));

                            if (!e.IsEmpty)
                            {
                                if (Settings.Default.Formatting_CommentXmlSpaceTags)
                                {
                                    _innerText.Append(CodeCommentHelper.Spacer);
                                }

                                ParseChildNodes(e);

                                _innerText.Append(CodeCommentHelper.CreateXmlCloseTag(e));
                            }
                        }
                    }
                    else
                    {
                        // Always trim trailing
                        var value = node.ToString().TrimEnd(CodeCommentHelper.Spacer);

                        // If the parent is an element, trim the starting spaces.
                        if (node.PreviousNode == null && node.Parent.NodeType == XmlNodeType.Element && !Settings.Default.Formatting_CommentXmlSpaceTags)
                        {
                            value = value.TrimStart(CodeCommentHelper.Spacer);
                        }

                        // If the previous node was an XML element, put a space before the text
                        // unless the first character is interpunction.
                        if (node.PreviousNode != null && node.PreviousNode.NodeType == XmlNodeType.Element)
                        {
                            if (!StartsWithInterpunction(value))
                            {
                                _innerText.Append(CodeCommentHelper.Spacer);
                            }
                        }

                        _innerText.Append(value);

                        // Add spacing after (almost) each word.
                        if (node.NextNode != null || node.Parent.NodeType != XmlNodeType.Element || Settings.Default.Formatting_CommentXmlSpaceTags)
                        {
                            _innerText.Append(CodeCommentHelper.Spacer);
                        }
                    }

                    node = node.NextNode;
                }
            }
        }
コード例 #28
0
 private void Append(string value)
 {
     _builder.Append(_options.XmlKeepTagsTogether ? CodeCommentHelper.FakeToSpace(value) : value);
     _currentPosition += WordLength(value);
     _isFirstWord      = false;
 }
コード例 #29
0
        /// <returns>
        /// Returns <c>true</c> if the line requests a break afterwards (did not fit on a single
        /// line), otherwise <c>false</c>.
        /// </returns>
        private bool FormatXml(CommentLineXml xml)
        {
            var isLiteralContent = !string.IsNullOrEmpty(xml.Content);
            var split            = xml.TagOptions.Split;

            if (isLiteralContent)
            {
                // Tags containing literal content with multiple with should always be on their own line.
                if (xml.Content.Contains('\n'))
                {
                    split = XmlTagNewLine.Always;
                }
            }
            else if ((split == XmlTagNewLine.Default || split == XmlTagNewLine.Content) && xml.Lines.Count > 1)
            {
                // Split always if there is more than one child line.
                split = XmlTagNewLine.Always;
            }

            if (split.HasFlag(XmlTagNewLine.BeforeOpen) && !_isFirstWord)
            {
                NewLine();
            }

            Append(xml.TagOptions.KeepTogether ? CodeCommentHelper.FakeToSpace(xml.OpenTag) : xml.OpenTag);

            // Self closing tags have no content, skip all further logic and just output.
            if (xml.IsSelfClosing)
            {
                if (split.HasFlag(XmlTagNewLine.AfterClose))
                {
                    if (!xml.IsLast)
                    {
                        NewLine();
                    }
                    return(false);
                }

                return(true);
            }

            if (split.HasFlag(XmlTagNewLine.AfterOpen))
            {
                NewLine();
            }

            // Increase the indenting.
            _indentAmount += xml.TagOptions.Indent;

            if (isLiteralContent)
            {
                // If the literal content of an XML tag is set, output that content without formatting.
                var literals = xml.Content.Trim('\r', '\n').TrimEnd('\r', '\n', '\t', ' ').Split('\n');
                for (int i = 0; i < literals.Length; i++)
                {
                    if (i > 0)
                    {
                        NewLine(true);
                    }
                    Append(literals[i].TrimEnd(), true);
                }
            }
            else
            {
                // Else output the child lines.
                var xmlTagLength = WordLength(xml.OpenTag) + WordLength(xml.CloseTag) + (xml.TagOptions.SpaceContent ? 2 : 0);

                foreach (var line in xml.Lines)
                {
                    if (!Format(line, xmlTagLength, xml.TagOptions.SpaceContent))
                    {
                        split |= XmlTagNewLine.BeforeClose | XmlTagNewLine.AfterClose;
                    }
                }
            }

            // Remove the indenting.
            _indentAmount -= xml.TagOptions.Indent;

            // If opening tag was on own line, do the same for the closing tag.
            if (split.HasFlag(XmlTagNewLine.BeforeClose))
            {
                NewLine();
            }
            else if (xml.TagOptions.SpaceContent)
            {
                Append(CodeCommentHelper.Spacer);
            }

            Append(xml.CloseTag);

            if (split.HasFlag(XmlTagNewLine.AfterClose))
            {
                //if (!xml.IsLast)
                {
                    NewLine();
                }

                return(false);
            }

            return(true);
        }
コード例 #30
0
        /// <summary>
        /// Parse a comment line into individual words and write it to the buffer.
        /// </summary>
        /// <param name="line">The comment line.</param>
        /// <param name="xmlTagLength">
        /// The length of the enclosing XML tags, this is needed to calculate the line length for
        /// single line XML comments.
        /// </param>
        /// <param name="xmlSpaceParentTagContent">
        /// Set to <c>true</c> when parent is an XML tag and wants space between tags and content.
        /// </param>
        /// <returns>
        /// <c>true</c> if line fitted on single line, <c>false</c> if it wrapped on multiple lines.
        /// </returns>
        private bool Format(ICommentLine line, int xmlTagLength = 0, bool xmlSpaceParentTagContent = false)
        {
            if (line is CommentLineXml xml)
            {
                return(FormatXml(xml));
            }

            if (line.Content == null)
            {
                return(true);
            }

            var matches = _commentOptions.Regex.Matches(line.Content).OfType <Match>().Select(x => new CodeCommentMatch(x, _formatterOptions)).ToList();

            // Remove empty matches from the start and end of the comment.
            CodeCommentMatch m;

            while (((m = matches.FirstOrDefault()) != null && m.IsEmpty) || ((m = matches.LastOrDefault()) != null && m.IsEmpty))
            {
                matches.Remove(m);
            }

            // Join the comment matches into single lines where possible.
            if (matches.Count > 1)
            {
                int i = 0;
                do
                {
                    m = matches[i];
                    if (m.TryAppend(matches[i + 1]))
                    {
                        matches.RemoveAt(i + 1);
                    }
                    else
                    {
                        i++;
                    }
                } while (i < matches.Count - 1);
            }

            // Extended logic for line breaks.
            // - Break if there is more than 1 line match (eg. due to a list or child xml tags).
            // - Break if the content does not fit on a single line.
            var matchCount   = matches.Count;
            var forceBreak   = matchCount > 1;
            var fittedOnLine = true;

            if (!forceBreak && matchCount == 1 && matches[0].Words.Any())
            {
                // Calculate the length of the first line.
                var firstLineLength = _commentPrefixLength + xmlTagLength + matches[0].Length + _indentAmount;

                // If set to skip wrapping on the last word, the last word's length does not matter.
                if (_formatterOptions.SkipWrapOnLastWord)
                {
                    firstLineLength -= WordLength(matches[0].Words.Last()) + 1;
                }

                forceBreak = firstLineLength > _formatterOptions.WrapColumn;
            }

            if (_currentPosition == 0 || (!_isFirstWord && forceBreak))
            {
                NewLine();
                fittedOnLine = false;
            }
            else if (!_isFirstWord && xmlSpaceParentTagContent)
            {
                // Parent is XML tag and wants space between tags and content.
                Append(CodeCommentHelper.Spacer);
            }

            // Always consider the word after the opening tag as the first word to prevent an extra
            // space before.
            _isFirstWord = true;

            foreach (var match in matches)
            {
                if (match.IsLiteral || match.IsList)
                {
                    if (!_isFirstWord)
                    {
                        NewLine();
                        fittedOnLine = false;
                    }
                }

                if (match.IsList)
                {
                    Append(match.ListPrefix);

                    // List items include their spacing and do not require additional space, thus we
                    // are logically still on the first word.
                    _isFirstWord = true;
                }

                if (!match.IsEmpty)
                {
                    var wordCount = match.Words.Count - 1;

                    for (int i = 0; i <= wordCount; i++)
                    {
                        var word   = match.Words[i];
                        var length = WordLength(word);
                        var wrap   = false;

                        // If current position plus word length exceeds the maximum comment length,
                        // wrap to the next line. Take care not to wrap on the first word, otherwise
                        // a word that never fits a line (ie. too long) would cause endless linewrapping.
                        if (!_isFirstWord && _currentPosition + length + 1 > _formatterOptions.WrapColumn)
                        {
                            wrap = true;
                        }

                        // If this is the last word and user selected to not wrap on the last word,
                        // don't wrap.
                        if (wrap && i == wordCount && _formatterOptions.SkipWrapOnLastWord)
                        {
                            wrap = false;
                        }

                        if (wrap)
                        {
                            NewLine();
                            fittedOnLine = false;

                            // If linewrap is on a list item, add extra spacing to align the text
                            // with the previous line.
                            if (match.IsList)
                            {
                                Append(string.Empty.PadLeft(WordLength(match.ListPrefix), CodeCommentHelper.Spacer));

                                // Unset the first-word flag, because this is just padding and not a
                                // proper word.
                                _isFirstWord = true;
                            }
                        }
                        else if (!_isFirstWord)
                        {
                            Append(CodeCommentHelper.Spacer);
                        }

                        Append(CodeCommentHelper.FakeToSpace(word));
                    }
                }
                else
                {
                    // Line without words, create a blank line. First end the current line.
                    NewLine();

                    // And then force a newline creating an empty one.
                    NewLine(true);
                    fittedOnLine = false;
                }
            }

            return(fittedOnLine);
        }