Visual Studio: hotkeys to move line up/down and move through recent changes

前端 未结 9 2092
清酒与你
清酒与你 2020-12-07 11:53

I\'m moving from Eclipse to Visual Studio .NET and have found all my beloved hotkeys except two:

  • in Eclipse you can press ALT- and
相关标签:
9条回答
  • 2020-12-07 12:24

    I don't know if VS supports the features you're talking about natively, but I know the resharper plugin allows you to go to the previous edits by using CTRL + SHIFT + BACKSPACE. I don't think it has support for moving a line up and down tho (well not that I've found yet)

    0 讨论(0)
  • 2020-12-07 12:26

    The answers proposed work, but none of them are as nice as eclipse with regard to how they preserve the existing paste buffer, the currently selected characters, and they do not allow the user to operate upon a range of lines. Here is a solution I came up with that preserves the paste buffer, the current character selection, and works with or without a selection (that may or may not span multiple rows):

    '' Duplicates the current line (or selection of lines) and places the copy
    '' one line below or above the current cursor position (based upon the parameter)
    Sub CopyLine(ByVal movingDown As Boolean)
        DTE.UndoContext.Open("CopyLine")
        Dim objSel As TextSelection = DTE.ActiveDocument.Selection
    
        ' store the original selection and cursor position
        Dim topPoint As TextPoint = objSel.TopPoint
        Dim bottomPoint As TextPoint = objSel.BottomPoint
        Dim lTopLine As Long = topPoint.Line
        Dim lTopColumn As Long = topPoint.LineCharOffset
        Dim lBottomLine As Long = bottomPoint.Line
        Dim lBottomColumn As Long = bottomPoint.LineCharOffset()
    
        ' copy each line from the top line to the bottom line
        Dim readLine As Long = lTopLine
        Dim endLine As Long = lBottomLine + 1
        Dim selectionPresent As Boolean = ((lTopLine <> lBottomLine) Or (lTopColumn <> lBottomColumn))
        If (selectionPresent And (lBottomColumn = 1)) Then
            ' A selection is present, but the cursor is in front of the first character
            ' on the bottom line. exclude that bottom line from the copy selection.
            endLine = lBottomLine
        End If
    
        ' figure out how many lines we are copying, so we can re-position
        ' our selection after the copy is done
        Dim verticalOffset As Integer = 0
        If (movingDown) Then
            verticalOffset = endLine - lTopLine
        End If
    
        ' copy each line, one at a time.
        ' The Insert command doesn't handle multiple lines well, and we need
        ' to use Insert to avoid autocompletions
        Dim insertLine As Long = endLine
        While (readLine < endLine)
            ' move to read postion, and read the current line
            objSel.MoveToLineAndOffset(readLine, 1)
            objSel.EndOfLine(True) 'extend to EOL
            Dim lineTxt As String = objSel.Text.Clone
            ' move to the destination position, and insert the copy
            objSel.MoveToLineAndOffset(insertLine, 1)
            objSel.Insert(lineTxt)
            objSel.NewLine()
            ' adjust the read & insertion points
            readLine = readLine + 1
            insertLine = insertLine + 1
        End While
    
        ' restore the cursor to original position and selection
        objSel.MoveToLineAndOffset(lBottomLine + verticalOffset, lBottomColumn)
        objSel.MoveToLineAndOffset(lTopLine + verticalOffset, lTopColumn, True)
        DTE.UndoContext.Close()
    End Sub
    
    '' Duplicates the current line (or selection of lines) and places the copy
    '' one line below the current cursor position
    Sub CopyLineDown()
        CopyLine(True)
    End Sub
    
    '' Duplicates the current line (or selection of lines) and places the copy
    '' one line above the current cursor position
    Sub CopyLineUp()
        CopyLine(False)
    End Sub
    
    
    '' Moves the selected lines up one line. If no line is
    '' selected, the current line is moved.
    ''
    Sub MoveLineUp()
        DTE.UndoContext.Open("MoveLineUp")
        Dim objSel As TextSelection = DTE.ActiveDocument.Selection
        ' store the original selection and cursor position
        Dim topPoint As TextPoint = objSel.TopPoint
        Dim bottomPoint As TextPoint = objSel.BottomPoint
        Dim lTopLine As Long = topPoint.Line
        Dim lTopColumn As Long = topPoint.LineCharOffset
        Dim lBottomLine As Long = bottomPoint.Line
        Dim lBottomColumn As Long = bottomPoint.LineCharOffset()
    
        Dim textLineAbove As TextSelection = DTE.ActiveDocument.Selection
        textLineAbove.MoveToLineAndOffset(lTopLine - 1, 1, False)
        textLineAbove.MoveToLineAndOffset(lTopLine, 1, True)
        Dim indentChange As Integer = CountIndentations(textLineAbove.Text) * -1
    
        ' If multiple lines are selected, but the bottom line doesn't
        ' have any characters selected, don't count it as selected
        Dim lEffectiveBottomLine = lBottomLine
        If ((lBottomColumn = 1) And (lBottomLine <> lTopLine)) Then
            lEffectiveBottomLine = lBottomLine - 1
        End If
    
        ' move to the line above the top line
        objSel.MoveToLineAndOffset(lTopLine - 1, 1)
        ' and move it down, until its below the bottom line:
        Do
            DTE.ExecuteCommand("Edit.LineTranspose")
        Loop Until (objSel.BottomPoint.Line >= lEffectiveBottomLine)
        ' Since the line we are on has moved up, our location in the file has changed:
        lTopLine = lTopLine - 1
        lBottomLine = lBottomLine - 1
    
        IndentBlockAndRestoreSelection(objSel, lBottomLine, lBottomColumn, lTopLine, lTopColumn, indentChange)
    
        DTE.UndoContext.Close()
    End Sub
    
    '' Moves the selected lines down one line. If no line is
    '' selected, the current line is moved.
    ''
    Sub MoveLineDown()
        DTE.UndoContext.Open("MoveLineDown")
        Dim objSel As TextSelection = DTE.ActiveDocument.Selection
        ' store the original selection and cursor position
        Dim topPoint As TextPoint = objSel.TopPoint
        Dim bottomPoint As TextPoint = objSel.BottomPoint
        Dim lTopLine As Long = topPoint.Line
        Dim lTopColumn As Long = topPoint.LineCharOffset
        Dim lBottomLine As Long = bottomPoint.Line
        Dim lBottomColumn As Long = bottomPoint.LineCharOffset()
    
        ' If multiple lines are selected, but the bottom line doesn't
        ' have any characters selected, don't count it as selected
        Dim lEffectiveBottomLine = lBottomLine
        If ((lBottomColumn = 1) And (lBottomLine <> lTopLine)) Then
            lEffectiveBottomLine = lBottomLine - 1
        End If
    
        Dim textLineBelow As TextSelection = DTE.ActiveDocument.Selection
        textLineBelow.MoveToLineAndOffset(lEffectiveBottomLine + 1, 1, False)
        textLineBelow.MoveToLineAndOffset(lEffectiveBottomLine + 2, 1, True)
        Dim indentChange As Integer = CountIndentations(textLineBelow.Text)
    
    
        ' move to the bottom line
        objSel.MoveToLineAndOffset(lEffectiveBottomLine, 1)
        ' and move it down, which effectively moves the line below it up
        ' then move the cursor up, always staying one line above the line
        ' that is moving up, and keep moving it up until its above the top line:
        Dim lineCount As Long = lEffectiveBottomLine - lTopLine
        Do
            DTE.ExecuteCommand("Edit.LineTranspose")
            objSel.LineUp(False, 2)
            lineCount = lineCount - 1
        Loop Until (lineCount < 0)
        ' Since the line we are on has moved down, our location in the file has changed:
        lTopLine = lTopLine + 1
        lBottomLine = lBottomLine + 1
    
        IndentBlockAndRestoreSelection(objSel, lBottomLine, lBottomColumn, lTopLine, lTopColumn, indentChange)
    
        DTE.UndoContext.Close()
    End Sub
    
    '' This method takes care of indenting the selected text by the indentChange parameter
    '' It then restores the selection to the lTopLine:lTopColumn - lBottomLine:lBottomColumn parameter.
    '' It will adjust these values according to the indentChange performed
    Sub IndentBlockAndRestoreSelection(ByVal objSel As TextSelection, ByVal lBottomLine As Long, ByVal lBottomColumn As Long, ByVal lTopLine As Long, ByVal lTopColumn As Long, ByVal indentChange As Integer)
        ' restore the cursor to original position and selection
        objSel.MoveToLineAndOffset(lBottomLine, lBottomColumn)
        objSel.MoveToLineAndOffset(lTopLine, lTopColumn, True)
        If (indentChange = 0) Then
            ' If we don't change the indent, we are done
            Return
        End If
    
        If (lBottomLine = lTopLine) Then
            If (indentChange > 0) Then
                objSel.StartOfLine()
            Else
                objSel.StartOfLine()
                objSel.WordRight()
            End If
        End If
        objSel.Indent(indentChange)
    
        ' Since the selected text has changed column, adjust the columns accordingly:
        ' restore the cursor to original position and selection
        Dim lNewBottomColumn As Long = (lBottomColumn + indentChange)
        Dim lNewTopColumn As Long = (lTopColumn + indentChange)
        ' ensure that we we still on the page.
        ' The "or" clause makes it so if we were at the left edge of the line, we remain on the left edge.
        If ((lNewBottomColumn < 2) Or (lBottomColumn = 1)) Then
            ' Single line selections, or a bottomColumn that is already at 1 may still have a new BottomColumn of 1
            If ((lTopLine = lBottomLine) Or (lBottomColumn = 1)) Then
                lNewBottomColumn = 1
            Else
                ' If we have multiple lines selected, don't allow the bottom edge to touch the left column,
                ' or the next move will ignore that bottom line.
                lNewBottomColumn = 2
            End If
        End If
        If ((lNewTopColumn < 2) Or (lTopColumn = 1)) Then
            lNewTopColumn = 1
        End If
    
        ' restore the selection to the modified selection
        objSel.MoveToLineAndOffset(lBottomLine, lNewBottomColumn)
        objSel.MoveToLineAndOffset(lTopLine, lNewTopColumn, True)
    End Sub
    
    
    '' This method counts the indentation changes within the text provided as the paramter
    Function CountIndentations(ByVal text As String) As Integer
        Dim indent As Integer = 0
        While (Text.Length > 0)
            If (Text.StartsWith("//")) Then
                Dim endOfLine As Integer = Text.IndexOf("\n", 2)
                If (Equals(endOfLine, -1)) Then
                    ' The remaining text is all on one line, so the '//' terminates our search
                    ' Ignore the rest of the text
                    Exit While
                End If
                ' continue looking after the end of line
                Text = Text.Substring(endOfLine + 1)
            End If
    
            If (Text.StartsWith("/*")) Then
                Dim endComment As Integer = Text.IndexOf("*/", 2)
                If (Equals(endComment, -1)) Then
                    ' This comment continues beyond the length of this line.
                    ' Ignore the rest of the text
                    Exit While
                End If
                ' continue looking after the end of this comment block
                Text = Text.Substring(endComment + 1)
            End If
    
            If (Text.StartsWith("{")) Then
                indent = indent + 1
            Else
                If (Text.StartsWith("}")) Then
                    indent = indent - 1
                End If
            End If
            Text = Text.Substring(1)
        End While
        Return indent
    End Function
    

    I edited this post to add the UndoContext mechanism (suggested by Nicolas Dorier) at the beginning of the MoveLineUp() and MoveLineDown() methods and closing it at their end. 11/23/11 - I updated this again to allow the moved lines to indent themselves as you cross bracket boundaries

    0 讨论(0)
  • 2020-12-07 12:26

    Edit.LineTranspose but this doesn't work to move a line up... Here is the macro to move line up

    Sub LineTransposeUp()
        Dim offset As Integer
        Dim sel As TextSelection
    
        DTE.UndoContext.Open("LineTransposeUp")
    
        Try
            sel = DTE.ActiveDocument.Selection
            offset = sel.ActivePoint.LineCharOffset
            sel.LineUp()
            DTE.ExecuteCommand("Edit.LineTranspose")
            sel.LineUp()
            sel.MoveToLineAndOffset(sel.ActivePoint.Line, offset)
        Catch ex As System.Exception
        End Try
    
        DTE.UndoContext.Close()
    End Sub
    
    0 讨论(0)
提交回复
热议问题