Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

VS 2013 SDK: Indentation issues with selected text

Scenario

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.


Problem

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:

enter image description here

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:

enter image description here


Question

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.


Code

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

Research

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...

like image 304
ElektroStudios Avatar asked Oct 18 '25 19:10

ElektroStudios


1 Answers

// 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());
like image 81
Hadi Brais Avatar answered Oct 21 '25 10:10

Hadi Brais