With Visual Studio SDk 2013, I'm trying to develop a simple extension that intends to modify the selected text to enclose it for specific XML documentation tags.
The problem I have is when replacing the selected text, it only works with very especific conditions that I would like to avoid/improve.
To expose a real comparison, notice the perfection of the way that Visual Studio manages the indentation on the selected lines when commenting uncommenting the selected lines with Ctrl + K + C and Ctrl + K + U hotkeys, no matter where the selection index starts or ends because the entire (and non-empty) selected lines will be commented and preserving the indentation level:
That is the challenge I have with my own, this is the weird results I have with my extension, it only works properly if I fully select the lines including the whitespaces at the left, if not, i get undesired results:
In VB.Net, or else C#, how can I improve the logic of my code to fix the imperfections of the comparison above?.
The imperfections are basically that my extension cannot properly handle the starting blankspaces of the selected lines like VisualStudio does to perform a right text-replacing, so I get unexpected results as I mentioned.
This is the relevant code that I'm using:
Const XmlCommentCharsVB As String = "'''"
Const XmlCommentCharsCS As String = "///"
Private Sub ModifySelectedText()
Dim viewhost As IWpfTextViewHost = Me.GetCurrentViewHost()
Dim textView As IWpfTextView = viewhost.TextView
Dim selectionSpan As VirtualSnapshotSpan = textView.Selection.StreamSelectionSpan
Dim selectedText As String = selectionSpan.SnapshotSpan.GetText
Dim language As String = textView.TextDataModel.ContentType.DisplayName
Dim xmlCommentChars As String = ""
Dim marginLength As Integer =
(From c As Char In selectedText.Split({Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries).First
Take While Char.IsWhiteSpace(c)
).Count
If String.IsNullOrEmpty(selectedText) Then
Exit Sub
End If
Dim sb As New StringBuilder
Select Case language.ToUpper
Case "BASIC"
xmlCommentChars = XmlCommentCharsVB
Case "CSHARP"
xmlCommentChars = XmlCommentCharsCS
Case Else ' VC++
' Not implemented.
End Select
With sb
.AppendLine(String.Format("{0} <example> This is a code example.", xmlCommentChars))
.AppendLine(String.Format("{0} <code>", xmlCommentChars))
For Each line As String In selectedText.Split({Environment.NewLine}, StringSplitOptions.None)
sb.AppendLine(String.Format("{0} {1}", xmlCommentChars, line.Remove(0, marginLength)))
Next
.AppendLine(String.Format("{0} </code>", xmlCommentChars))
.AppendLine(String.Format("{0} </example>", xmlCommentChars))
End With
selectionSpan.Snapshot.TextBuffer.Replace(selectionSpan.SnapshotSpan, sb.ToString)
End Sub
VisualStudio SDK does not have any of easy, really it's a nightmare to find any code-example on the MSDN reference, or non-guru explanations that let understand the end-user the purpose of "X" member of the SDK, so I should imagine by my own what could do "X" member and put it in practice to see what happens... I'm totally blind about how to solve this.
Anyways, I put my eyes on the TrackingMode
property of the ITrackingSpan
interface, it explains something about the edges of the editor... but I tested it and seems it does not refers to the blankspace edges.
Also, I think that a major problem coould be that I'm getting the selected text in this way:
viewhost.TextView.Selection.StreamSelectionSpan.SnapshotSpan.GetText
I'm just getting an String, but the SDK provides an ITextSnapshot
interface with a collection of strings in the Lines
property, however, I've tried to retrieve the propert Snapshot
for the selected text but I always get all the text of the current editor view...
// Get the selection object.
var viewHost = GetCurrentViewHost();
ITextSelection selection = viewHost.TextView.Selection;
// Get the start and end points of the selection.
VirtualSnapshotPoint start = selection.Start;
VirtualSnapshotPoint end = selection.End;
// Get the lines that contain the start and end points.
IWpfTextViewLine startLine =
viewHost.TextView.GetTextViewLineContainingBufferPosition(start.Position);
IWpfTextViewLine endLine =
viewHost.TextView.GetTextViewLineContainingBufferPosition(end.Position);
// Get the start and end points of the lines.
SnapshotPoint startLinePoint = startLine.Start;
SnapshotPoint endLinePoint = endLine.End;
// Create a SnapshotSpan for all text to be replaced.
SnapshotSpan span = new SnapshotSpan(startLinePoint, endLinePoint);
// Compute margin.
string[] lines = span.GetText().Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
int margin = lines.Select(line =>
{
int count = 0;
while (char.IsWhiteSpace(line[count++])) ;
return --count;
}).Min();
// Construct the replacement string.
StringBuilder sb = new StringBuilder();
foreach (string line in lines)
{
sb.AppendLine(String.Format("{0}{1} {2}", new string(' ', margin), "///", line.Remove(0, margin)));
}
// Perform the replacement.
span.Snapshot.TextBuffer.Replace(span, sb.ToString());
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With