Visual Studio:向上/向下移动行和浏览最近更改的热键
Posted
技术标签:
【中文标题】Visual Studio:向上/向下移动行和浏览最近更改的热键【英文标题】:Visual Studio: hotkeys to move line up/down and move through recent changes 【发布时间】:2010-09-23 17:31:04 【问题描述】:我正在从 Eclipse 迁移到 Visual Studio .NET,并且找到了所有我心爱的热键,除了两个:
在 Eclipse 中,您可以按 ALT-← 和 ALT-→ 访问最近所做的更改,我经常使用它来回到我在其他文件中的位置然后返回。显然在 VS.NET 中 CTRL-- 和 CTRL-SHIFT--这样做但它们似乎并不总是有效(例如在笔记本电脑上,可能是减号的一个数字问题)并且似乎没有遵循与我在 Eclipse 中习惯的“我在哪里”相同的算法。有没有人让它工作并每天依赖它等? 在 Eclipse 中,要向上或向下移动一行,请按 ALT-uparrow 或 ALT-downarrow你只需在代码中移动它,直到你把它拿到你想要的地方,非常好。另外要复制一行,您可以按 SHIFT-ALT-uparrow 或 SHIFT-ALT-向下箭头。这两个热键甚至适用于您选择的行块。有人在 Visual Studio .NET 中发现了这些热键功能吗?
A D D E N D U M :
使用上述第二个功能的一个示例是将此处的底线向上移动到 for 循环中。在 Eclipse 中,您将光标放在 Console.WriteLine 上,然后按 ALT-(向上箭头),我一直使用它:一键上下移动线条。
for (int i = 0; i < 10; i++)
Console.WriteLine(i);
好的,用 no-selection-ctrl-c 推断 Charlie 的想法来选择一行,在 Visual Studio 中,您可以将光标放在 Console.WriteLine 上,(无选择)按 CTRL-X 然后向上移动并按 CTRL-V。
【问题讨论】:
对不起,我一开始误解了线路移动的事情,但我想我现在明白了。检查执行此操作的宏的编辑。 【参考方案1】:建议的答案有效,但在如何保存现有粘贴缓冲区、当前选择的字符以及不允许用户对一系列行进行操作方面,没有一个比 eclipse 好。这是我想出的一个解决方案,它保留了粘贴缓冲区、当前字符选择,并且可以在有或没有选择的情况下工作(可能跨越也可能不跨越多行):
'' 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
我编辑了这篇文章,在 MoveLineUp() 和 MoveLineDown() 方法的开头添加 UndoContext 机制(由 Nicolas Dorier 建议),并在其末尾关闭它。 2011 年 11 月 23 日 - 我再次更新了此内容,以允许移动的行在您越过括号边界时缩进
【讨论】:
太棒了。我希望我能不止一次投票。干得好! 这应该是答案,而不是米奇小麦的答案。干得好! 实际上,当我“懒惰地”选择行时,此脚本不起作用,即我从第 1 行中间的某处开始选择并在最后一行中间的某处结束。 Eclipse 完美地处理了这个问题。 “懒惰”选择对我有用。唯一令人不快的是弹出了 MS 的宏通知,确实应该有一种方法可以将其关闭。 太棒了!这就像一个魅力!对于不熟悉宏和害怕 VB 的人:只需打开宏资源管理器(工具 | 宏 | 宏资源管理器)并添加一个新的 Marco 项目。将上述代码复制并粘贴到一个 marco 模块文件中。然后在键盘快捷键设置(工具 | 选项 | 环境 | 键盘)中搜索 MoveLineUp 命令(或宏浏览器中显示的任何其他命令)。找到宏后,只需分配所需的快捷键(确保它们不会与任何其他键发生冲突)。【参考方案2】:对于希望在 Visual Studio 2010 中执行此操作的任何人,免费的 Visual Studio 2010 Pro Power Tools 扩展增加了上下移动线条的功能。
http://visualstudiogallery.msdn.microsoft.com/en-us/d0d33361-18e2-46c0-8ff2-4adea1e34fef
【讨论】:
这似乎是迄今为止最简单的解决方案,但公平地说 - 我想这个问题是在此解决方案可用之前提出的。【参考方案3】:如果您还没有找到,设置这些键盘快捷键的位置在工具 | 下。选项 |环境 |键盘。只需浏览列表就可以找到许多方便的命令,但不幸的是,我从未找到任何好的参考来描述每个命令的用途。
至于具体命令:
我相信您所指的前进/后退导航命令是 View.NavigateBackward 和 View.NavigateForward。如果您的键盘与 VS 键绑定不合作,您可以将它们重新映射到您首选的 Eclipse 键。不幸的是,我不知道有什么方法可以改变它用来实际决定去哪里的算法。
我认为没有用于复制行的内置命令,但是在未选择文本的情况下按 Ctrl+C 会将当前行复制到剪贴板上。鉴于此,这里有一个简单的宏,将当前行复制到下一行:
Sub CopyLineBelow()
DTE.ActiveDocument.Selection.Collapse()
DTE.ActiveDocument.Selection.Copy()
DTE.ActiveDocument.Selection.Paste()
End Sub
Sub CopyLineAbove()
DTE.ActiveDocument.Selection.Collapse()
DTE.ActiveDocument.Selection.Copy()
DTE.ActiveDocument.Selection.LineUp()
DTE.ActiveDocument.Selection.Paste()
End Sub
为了移动一行文本,Edit.LineTranspose 会将选定的行向下移动。我不认为有移动一行的命令,但这里有一个快速宏可以做到这一点:
Sub MoveLineUp()
DTE.ActiveDocument.Selection.Collapse()
DTE.ActiveDocument.Selection.Cut()
DTE.ActiveDocument.Selection.LineUp()
DTE.ActiveDocument.Selection.Paste()
DTE.ActiveDocument.Selection.LineUp()
End Sub
如果您还没有开始使用宏,它们真的很有用。工具 |宏 |宏 IDE 将带您进入编辑器,一旦定义它们,您就可以通过我上面提到的相同 UI 设置键盘快捷键。我使用非常方便的 Record Temporary Macro 命令生成了这些宏,也在工具 | 下。宏。此命令可让您记录一组键盘输入并多次重播,这对于构建高级编辑命令以及自动执行重复性任务(例如代码重新格式化)很有用。
【讨论】:
没有选择复制一行的CTRL-C,CTRL-V很好,不知道那个,谢谢。【参考方案4】:我最近做了同样的事情,当我转移到一个新项目时,我从 Eclipse 转移到了 Visual Studio。 强烈推荐Resharper add in - 它为 VS 添加了 Eclipse 所具有的一些丰富的编辑、导航和重构功能。
Resharper 还允许您使用与 InteliJ 非常相似的键盘映射方案。对于 Java 逃逸者来说非常方便...
关于您的第二个问题,Resharper 具有与 eclipse 相同的向上/向下移动代码功能,但有一些警告。首先,使用 InteliJ 键盘映射,按键组合比较曲折。
上移代码:ctrl + shift + alt + 上光标
下移代码:ctrl + shift + alt + 向下光标
其次,它并不总是只移动一行,而是实际跳转代码块。所以它不能将一行从 if 语句的外部移动到它的内部——它会将选定的行直接跳过 if 块。为此,您需要使用
移动“左”和“右”将代码移动到外部代码块中:ctrl + shift + alt + 左光标
将代码移动到下一个内部代码块:ctrl + shift + alt + 右光标
【讨论】:
【参考方案5】:在 Visual Studio 中录制宏以执行 alt-arrow 操作:
ctrl-alt-r -- record mode
ctrl-c -- copy a line
up arrow -- go up a line
home -- beginning of line (maybe there is a way to paste before the current line without this)
ctrl-v -- paste
ctrl-alt-r -- end record mode
现在您可以使用宏 ide 和键盘首选项将此宏映射到您喜欢的任何击键集。
【讨论】:
【参考方案6】:Edit.LineTranspose 但这不能向上移动一行... 这是移动队列的宏
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
【讨论】:
【参考方案7】:在 VS 2010/2012 中使用 MoveLine extension 向上或向下移动一行(或一组行)。
【讨论】:
【参考方案8】:我不知道 VS 是否支持您所说的本机功能,但我知道 resharper 插件允许您使用 CTRL + SHIFT + BACKSPACE 转到以前的编辑。我认为它不支持上下移动一条线(我还没有找到)
【讨论】:
它确实有上下移动线的快捷方式,但它与 Eclipse 中的工作方式不同 - 请参阅下面的答案。【参考方案9】:Paul Ostrowski 我试过你的工具。它几乎可以正常工作。
eclipse 所做的另一件事是将行移动到当前缩进级别。
例如:
function test()
// do stuff
Console.WriteLine("test");
在 console.writeline 上进行换档会将其更改为
function test()
// do stuff
Console.WriteLine("test");
但您的工具似乎可以这样做:
function test()
// do stuff
Console.WriteLine("test");
【讨论】:
我已将此功能添加到我的解决方案中。它不是 100% 完美,但涵盖了大多数用例。以上是关于Visual Studio:向上/向下移动行和浏览最近更改的热键的主要内容,如果未能解决你的问题,请参考以下文章
如何禁用向上/向下键在 Visual Studio 中滚动方法重载?
Visual Studio Code 快捷键大全(Windows)