private string LeadingWhitespaceFromInfo(LineCommentInfo info) { var leadingWhitespace = string.Empty; if (info.MarkerSpan.Start > info.Line.Start) { // We no longer use the existing line as a template, because we // should really be respecting the "add tabs as spaces" setting // regardless of what the current line has. (Or, should that be // an option the user can set?) var convertTabs = this.view.Options.IsConvertTabsToSpacesEnabled(); if (convertTabs) { leadingWhitespace = new string(' ', info.MarkerColumnStart); } else { var tabSize = this.view.Options.GetTabSize(); leadingWhitespace = new string('\t', info.MarkerColumnStart / tabSize); // Add spaces if the marker-start isn't a multiple of // the tab size. if (info.MarkerColumnStart % tabSize != 0) { leadingWhitespace = string.Concat( leadingWhitespace, new string(' ', info.MarkerColumnStart % tabSize)); } } } return leadingWhitespace; }
private IList<LineCommentInfo> GetMatchingComments( ITextSnapshot snapshot, LineCommentInfo toMatch, int lineNumberStart, int lineNumberLimit) { var list = new List<LineCommentInfo>(); var up = lineNumberLimit >= lineNumberStart; var delta = up ? 1 : -1; for ( var lineNumber = lineNumberStart; up ? lineNumber < lineNumberLimit : lineNumber >= lineNumberLimit; lineNumber += delta) { var line = snapshot.GetLineFromLineNumber(lineNumber); var info = LineCommentInfo.FromLine(line, this.view.Options, this.classifier); // TODO: treat lines with code (non-comment) as non-matching so // that behavior is better? if (!toMatch.Matches(info)) { break; } list.Add(info); } if (!up) { list.Reverse(); } return list; }
/// <summary> /// Returns whether another comment looks like it's a part of the same /// block as the current one. /// </summary> /// <param name="other"></param> /// <returns></returns> public bool Matches(LineCommentInfo other) { if ((other != null) && (this.Style == other.Style) && (this.MarkerSpan.Length == other.MarkerSpan.Length) && // we *only* care about the start columns, not the position // delta, because there may be mixed tabs and spaces. ////(this.MarkerSpan.Start - this.Line.Start == other.MarkerSpan.Start - other.Line.Start) && (this.MarkerColumnStart == other.MarkerColumnStart) && (this.ContentColumnStart == other.ContentColumnStart) && string.Equals(this.MarkerSpan.GetText(), other.MarkerSpan.GetText())) { // The leading info appears to match. If there's content in // both, we also want to make sure it starts in the same column. // If either line has blank content, should we consider it a // match? (No, if we want to handle "paragraph breaks"...) // Actually, just because of this, we require matching content // starts. If it doesn't, we create a new line that *does* // match, and all will be well. if ((this.ContentSpan.IsEmpty == other.ContentSpan.IsEmpty) && (this.ContentSpan.Start - this.MarkerSpan.End == other.ContentSpan.Start - other.MarkerSpan.End)) { return true; } } return false; }
private static bool ShouldWrap( GeneralOptions options, ITextChange change, ITextSnapshotLine line, LineCommentInfo info, out int commentWrapLength) { commentWrapLength = -1; if (info == null || (!info.CommentOnly && !options.CodeWrapEnabled)) { return false; } // For now, we're only supporting single-line comments. if (info.Style != CommentStyle.SingleLine) { return false; } // If we just typed whitespace at the *end* of the line, don't do // any wrapping yet. (It will cause us to trim the trailing space, // which would makeeverythingruntogetherlikethis! It also makes // newline handling weird.) if ((change.Delta > 0) && ((change.NewSpan.End >= line.End) && (change.NewSpan.End <= line.EndIncludingLineBreak)) && change.NewText.All(c => Whitespace.Contains(c))) { return false; } commentWrapLength = options.AutoWrapColumn - info.ContentColumnStart; // There's some minimum length after which wrapping becomes // pointless... if (commentWrapLength < options.MinimumWrapWidth) { return false; } return true; }
public static LineCommentInfo FromLine(ITextSnapshotLine line, IEditorOptions options, IClassifier classifier) { // Check if the line ends with a comment... var spans = classifier.GetClassificationSpans(line.Extent); // If there are no spans, or the last span isn't a comment // (multi-line issues?) return no info. var span = (spans != null) ? spans.LastOrDefault() : null; if (span == null || !span.ClassificationType.IsOfType("comment")) { return null; } var info = new LineCommentInfo(line, spans, span.Span, options); return info; }