/// <summary> /// Constructs instance of inner markup parsing context /// </summary> /// <param name="sourceCode">Source code</param> public InnerMarkupParsingContext(string sourceCode) { _sourceCode = sourceCode; _position = 0; _nodeCoordinates = new SourceCodeNodeCoordinates(1, 1); _peekedCharOffset = 0; }
/// <summary> /// Constructs instance of HTML attribute /// </summary> /// <param name="name">Name</param> /// <param name="value">Value</param> /// <param name="type">Type</param> /// <param name="nameCoordinates">Coordinates of name</param> /// <param name="valueCoordinates">Coordinates of value</param> public HtmlAttribute(string name, string value, HtmlAttributeType type, SourceCodeNodeCoordinates nameCoordinates, SourceCodeNodeCoordinates valueCoordinates) { Name = name; Value = value; Type = type; NameCoordinates = nameCoordinates; ValueCoordinates = valueCoordinates; }
/// <summary> /// Calculates a absolute node coordinates /// </summary> /// <param name="baseNodeCoordinates">Base node coordinates</param> /// <param name="relativeNodeCoordinates">Relative node coordinates</param> /// <returns>Absolute node coordinates</returns> public static SourceCodeNodeCoordinates CalculateAbsoluteNodeCoordinates( SourceCodeNodeCoordinates baseNodeCoordinates, SourceCodeNodeCoordinates relativeNodeCoordinates) { int relativeLineNumber = relativeNodeCoordinates.LineNumber; int relativeColumnNumber = relativeNodeCoordinates.ColumnNumber; int absoluteLineNumber; int absoluteColumnNumber; if (!baseNodeCoordinates.IsEmpty) { int baseLineNumber = baseNodeCoordinates.LineNumber; int baseColumnNumber = baseNodeCoordinates.ColumnNumber; absoluteLineNumber = baseLineNumber; absoluteColumnNumber = baseColumnNumber; if (relativeLineNumber > 0) { if (relativeLineNumber == 1) { if (relativeColumnNumber > 0) { absoluteColumnNumber = baseColumnNumber + relativeColumnNumber - 1; } } else { absoluteLineNumber = baseLineNumber + relativeLineNumber - 1; absoluteColumnNumber = relativeColumnNumber; } } } else { absoluteLineNumber = relativeLineNumber; absoluteColumnNumber = relativeColumnNumber; } var absoluteNodeCoordinates = new SourceCodeNodeCoordinates(absoluteLineNumber, absoluteColumnNumber); return absoluteNodeCoordinates; }
/// <summary> /// Increases a current parsing position /// </summary> /// <param name="increment">Increment</param> public void IncreasePosition(int increment) { int oldPosition = _position; int newPosition = oldPosition + increment; int fragmentStartPosition = oldPosition; int fragmentLength = increment; int lineBreakCount; int charRemainderCount; SourceCodeNavigator.CalculateLineBreakCount(_sourceCode, fragmentStartPosition, fragmentLength, out lineBreakCount, out charRemainderCount); SourceCodeNodeCoordinates currentNodeCoordinates = _nodeCoordinates; _nodeCoordinates = SourceCodeNavigator.CalculateAbsoluteNodeCoordinates(currentNodeCoordinates, lineBreakCount, charRemainderCount); _position = newPosition; }
/// <summary> /// Calculates a absolute node coordinates /// </summary> /// <param name="baseNodeCoordinates">Base node coordinates</param> /// <param name="additionalContent">Additional content</param> /// <returns>Absolute node coordinates</returns> public static SourceCodeNodeCoordinates CalculateAbsoluteNodeCoordinates( SourceCodeNodeCoordinates baseNodeCoordinates, string additionalContent) { int lineBreakCount = 0; int charRemainderCount = 0; if (!string.IsNullOrEmpty(additionalContent)) { CalculateLineBreakCount(additionalContent, out lineBreakCount, out charRemainderCount); } int absoluteLineNumber; int absoluteColumnNumber; if (!baseNodeCoordinates.IsEmpty) { int baseLineNumber = baseNodeCoordinates.LineNumber; int baseColumnNumber = baseNodeCoordinates.ColumnNumber; if (lineBreakCount > 0) { absoluteLineNumber = baseLineNumber + lineBreakCount; absoluteColumnNumber = charRemainderCount + 1; } else { absoluteLineNumber = baseLineNumber; absoluteColumnNumber = baseColumnNumber + charRemainderCount; } } else { absoluteLineNumber = lineBreakCount + 1; absoluteColumnNumber = charRemainderCount + 1; } var absoluteNodeCoordinates = new SourceCodeNodeCoordinates(absoluteLineNumber, absoluteColumnNumber); return absoluteNodeCoordinates; }
/// <summary> /// Initializes a new instance of the <see cref="XmlParsingException"/> class /// with a specified error message, node coordinates, source fragment /// and reference to the inner exception that is the cause of this exception /// </summary> /// <param name="message">Error message that explains the reason for the exception</param> /// <param name="nodeCoordinates">Node coordinates</param> /// <param name="sourceFragment">Source fragment</param> /// <param name="innerException">Exception that is the cause of the current exception</param> public XmlParsingException(string message, SourceCodeNodeCoordinates nodeCoordinates, string sourceFragment, Exception innerException) : base(message, nodeCoordinates, sourceFragment, innerException) { }
/// <summary> /// Initializes a new instance of the <see cref="CodeProcessingException"/> class /// with a specified error message, node coordinates and source fragment /// </summary> /// <param name="message">Error message that explains the reason for the exception</param> /// <param name="nodeCoordinates">Node coordinates</param> /// <param name="sourceFragment">Source fragment</param> protected CodeProcessingException(string message, SourceCodeNodeCoordinates nodeCoordinates, string sourceFragment) : this(message, nodeCoordinates, sourceFragment, null) { }
/// <summary> /// Initializes a new instance of the <see cref="CodeProcessingException"/> class /// with a specified error message, node coordinates, source fragment /// and reference to the inner exception that is the cause of this exception /// </summary> /// <param name="message">Error message that explains the reason for the exception</param> /// <param name="nodeCoordinates">Node coordinates</param> /// <param name="sourceFragment">Source fragment</param> /// <param name="innerException">Exception that is the cause of the current exception</param> protected CodeProcessingException(string message, SourceCodeNodeCoordinates nodeCoordinates, string sourceFragment, Exception innerException) : this(message, nodeCoordinates.LineNumber, nodeCoordinates.ColumnNumber, sourceFragment, innerException) { }
/// <summary> /// Initializes a new instance of the <see cref="MarkupParsingException"/> class /// with a specified error message, node coordinates and source fragment /// </summary> /// <param name="message">Error message that explains the reason for the exception</param> /// <param name="nodeCoordinates">Node coordinates</param> /// <param name="sourceFragment">Source fragment</param> public MarkupParsingException(string message, SourceCodeNodeCoordinates nodeCoordinates, string sourceFragment) : base(message, nodeCoordinates, sourceFragment) { }
/// <summary> /// Constructs instance of stacked XML tag /// </summary> /// <param name="name">Name</param> /// <param name="coordinates">Coordinates of tag</param> public StackedXmlTag(string name, SourceCodeNodeCoordinates coordinates) { Name = name; Coordinates = coordinates; }
/// <summary> /// Process a attributes /// </summary> /// <returns>List of attributes</returns> private List <HtmlAttribute> ProcessAttributes() { string content = _innerContext.SourceCode; int currentPosition = _innerContext.Position; SourceCodeNodeCoordinates currentCoordinates = _innerContext.NodeCoordinates; Match match = _attributeRegex.Match(content, currentPosition, _innerContext.RemainderLength); while (match.Success) { GroupCollection groups = match.Groups; Group attributeNameGroup = groups["attributeName"]; Group attributeEqualSignGroup = groups["attributeEqualSign"]; Group attributeValueGroup = groups["attributeValue"]; string attributeName = attributeNameGroup.Value; string attributeNameInLowercase = attributeName; if (Utils.ContainsUppercaseCharacters(attributeName)) { attributeNameInLowercase = attributeName.ToLowerInvariant(); } string attributeValue = null; if (attributeEqualSignGroup.Success) { if (attributeValueGroup.Success) { attributeValue = attributeValueGroup.Value; if (!string.IsNullOrWhiteSpace(attributeValue)) { attributeValue = HtmlAttributeValueHelpers.Decode(attributeValue); } } else { attributeValue = string.Empty; } } var attributeNameCoordinates = SourceCodeNodeCoordinates.Empty; int attributeNamePosition = -1; if (attributeNameGroup.Success) { attributeNamePosition = attributeNameGroup.Index; } if (attributeNamePosition != -1) { int lineBreakCount; int charRemainderCount; SourceCodeNavigator.CalculateLineBreakCount(content, currentPosition, attributeNamePosition - currentPosition, out lineBreakCount, out charRemainderCount); attributeNameCoordinates = SourceCodeNavigator.CalculateAbsoluteNodeCoordinates( currentCoordinates, lineBreakCount, charRemainderCount); currentPosition = attributeNamePosition; currentCoordinates = attributeNameCoordinates; } var attributeValueCoordinates = SourceCodeNodeCoordinates.Empty; int attributeValuePosition = -1; if (attributeValueGroup.Success) { attributeValuePosition = attributeValueGroup.Index; } if (attributeValuePosition != -1) { int lineBreakCount; int charRemainderCount; SourceCodeNavigator.CalculateLineBreakCount(content, currentPosition, attributeValuePosition - currentPosition, out lineBreakCount, out charRemainderCount); attributeValueCoordinates = SourceCodeNavigator.CalculateAbsoluteNodeCoordinates( currentCoordinates, lineBreakCount, charRemainderCount); currentPosition = attributeValuePosition; currentCoordinates = attributeValueCoordinates; } var attribute = new HtmlAttribute(attributeName, attributeNameInLowercase, attributeValue, HtmlAttributeType.Unknown, attributeNameCoordinates, attributeValueCoordinates); _tempAttributes.Add(attribute); _innerContext.IncreasePosition(match.Length); match = _attributeRegex.Match(content, _innerContext.Position, _innerContext.RemainderLength); } int attributeCount = _tempAttributes.Count; var attributes = new List <HtmlAttribute>(attributeCount); for (int attributeIndex = 0; attributeIndex < attributeCount; attributeIndex++) { attributes.Add(_tempAttributes[attributeIndex]); } _tempAttributes.Clear(); return(attributes); }
/// <summary> /// Formats a line of source code /// </summary> /// <param name="line">Line content</param> /// <param name="nodeCoordinates">Node coordinates</param> /// <param name="lineNumberSize">Number of symbols in the line number caption</param> /// <param name="fragmentStartPosition">Start position of source fragment</param> /// <param name="fragmentLength">Length of source fragment</param> /// <param name="tabSize">Number of spaces in the tab</param> /// <returns>Formatted line</returns> private static string FormatSourceCodeLine(string line, SourceCodeNodeCoordinates nodeCoordinates, int lineNumberSize, int fragmentStartPosition = 0, int fragmentLength = 0, byte tabSize = 4) { const string ellipsisSymbol = "…"; const byte leftPaddingSize = 7; int lineNumber = nodeCoordinates.LineNumber; int columnNumber = nodeCoordinates.ColumnNumber; int lineLength = line.Length; string processedLine; if ((fragmentStartPosition == 0 && fragmentLength == lineLength)) { processedLine = line; } else if (fragmentStartPosition >= lineLength) { processedLine = string.Empty; } else { int fragmentEndPosition = fragmentStartPosition + fragmentLength - 1; bool beginningCutOff = (fragmentStartPosition > 0); bool endingCutOff = (fragmentEndPosition <= lineLength); if (fragmentEndPosition + 1 == lineLength) { endingCutOff = false; } if (fragmentEndPosition >= lineLength) { endingCutOff = false; fragmentEndPosition = lineLength - 1; fragmentLength = fragmentEndPosition - fragmentStartPosition + 1; } processedLine = line.Substring(fragmentStartPosition, fragmentLength); if (beginningCutOff) { processedLine = ellipsisSymbol + processedLine; } if (endingCutOff) { processedLine = processedLine + ellipsisSymbol; } } string result = string.Format("Line {0}: {1}", lineNumber.ToString(CultureInfo.InvariantCulture).PadLeft(lineNumberSize), processedLine.TabsToSpaces(tabSize)); if (columnNumber > 0) { int cursorOffset = columnNumber - fragmentStartPosition; if (fragmentStartPosition > 0) { cursorOffset++; } result += Environment.NewLine + string.Empty .PadRight(processedLine.Substring(0, cursorOffset - 1) .TabsToSpaces(tabSize).Length + lineNumberSize + leftPaddingSize) .Replace(" ", "-") + "^" ; } return result; }
/// <summary> /// Gets a source fragment /// </summary> /// <param name="sourceCode">Source code</param> /// <param name="nodeCoordinates">Node coordinates</param> /// <param name="tabSize">Number of spaces in the tab</param> /// <param name="maxFragmentLength">Maximum length of the source fragment</param> /// <returns>Source fragment</returns> public static string GetSourceFragment(string sourceCode, SourceCodeNodeCoordinates nodeCoordinates, byte tabSize = DEFAULT_TAB_SIZE, int maxFragmentLength = DEFAULT_MAX_FRAGMENT_LENGTH) { string sourceFragment = string.Empty; int lineNumber = nodeCoordinates.LineNumber; int columnNumber = nodeCoordinates.ColumnNumber; if (!string.IsNullOrEmpty(sourceCode)) { int previousLineNumber = lineNumber - 1; int currentLineNumber = lineNumber; int nextLineNumber = lineNumber + 1; string previousLine = string.Empty; string currentLine = string.Empty; string nextLine = string.Empty; int lineCount = 0; int lineBreakPosition = int.MinValue; int lineBreakLength = 0; do { string line; int startLinePosition = (lineBreakPosition == int.MinValue) ? 0 : lineBreakPosition + lineBreakLength; FindNextLineBreak(sourceCode, startLinePosition, out lineBreakPosition, out lineBreakLength); if (lineBreakPosition != -1) { line = sourceCode.Substring(startLinePosition, lineBreakPosition - startLinePosition); } else { line = sourceCode.Substring(startLinePosition); } lineCount++; if (lineCount == previousLineNumber) { previousLine = line; } else if (lineCount == currentLineNumber) { currentLine = line; } else if (lineCount == nextLineNumber) { nextLine = line; } } while (lineBreakPosition != -1 && lineCount <= nextLineNumber); int lineNumberSize = (nextLineNumber).ToString(CultureInfo.InvariantCulture).Length; if (currentLineNumber == lineCount) { lineNumberSize = currentLineNumber.ToString(CultureInfo.InvariantCulture).Length; } int fragmentStartPosition; int fragmentLength; CalculateCutPositions(currentLine, columnNumber, maxFragmentLength, out fragmentStartPosition, out fragmentLength); var sourceFragmentBuilder = new StringBuilder(); if (currentLine.Length > 0) { if (previousLine.Length > 0) { sourceFragmentBuilder.AppendLine(FormatSourceCodeLine(previousLine, new SourceCodeNodeCoordinates(previousLineNumber, 0), lineNumberSize, fragmentStartPosition, fragmentLength, tabSize)); } sourceFragmentBuilder.AppendLine(FormatSourceCodeLine(currentLine, new SourceCodeNodeCoordinates(currentLineNumber, columnNumber), lineNumberSize, fragmentStartPosition, fragmentLength, tabSize)); if (nextLine.Length > 0) { sourceFragmentBuilder.AppendLine(FormatSourceCodeLine(nextLine, new SourceCodeNodeCoordinates(nextLineNumber, 0), lineNumberSize, fragmentStartPosition, fragmentLength, tabSize)); } } sourceFragment = sourceFragmentBuilder.ToString(); } return sourceFragment; }
/// <summary> /// Calculates a node coordinates /// </summary> /// <param name="sourceCode">Source code</param> /// <param name="nodePosition">Current node position</param> /// <returns>Node coordinates</returns> public static SourceCodeNodeCoordinates CalculateNodeCoordinates(string sourceCode, int nodePosition) { if (string.IsNullOrEmpty(sourceCode) || nodePosition >= sourceCode.Length) { return SourceCodeNodeCoordinates.Empty; } int fragmentLength = nodePosition + 1; int lineBreakCount; int charRemainderCount; CalculateLineBreakCount(sourceCode, 0, fragmentLength, out lineBreakCount, out charRemainderCount); var nodeCoordinates = new SourceCodeNodeCoordinates(lineBreakCount + 1, charRemainderCount + 1); return nodeCoordinates; }
/// <summary> /// Calculates a absolute node coordinates /// </summary> /// <param name="baseNodeCoordinates">Base node coordinates</param> /// <param name="lineBreakCount">Number of line breaks</param> /// <param name="charRemainderCount">Number of characters left</param> /// <returns>Absolute node coordinates</returns> public static SourceCodeNodeCoordinates CalculateAbsoluteNodeCoordinates( SourceCodeNodeCoordinates baseNodeCoordinates, int lineBreakCount, int charRemainderCount) { int absoluteLineNumber; int absoluteColumnNumber; if (!baseNodeCoordinates.IsEmpty) { int baseLineNumber = baseNodeCoordinates.LineNumber; int baseColumnNumber = baseNodeCoordinates.ColumnNumber; if (lineBreakCount > 0) { absoluteLineNumber = baseLineNumber + lineBreakCount; absoluteColumnNumber = charRemainderCount + 1; } else { absoluteLineNumber = baseLineNumber; absoluteColumnNumber = baseColumnNumber + charRemainderCount; } } else { absoluteLineNumber = lineBreakCount + 1; absoluteColumnNumber = charRemainderCount + 1; } var absoluteNodeCoordinates = new SourceCodeNodeCoordinates(absoluteLineNumber, absoluteColumnNumber); return absoluteNodeCoordinates; }