我编写了一个AutoHotkey脚本,该脚本允许我在Microsoft SQL Server Management Studio 2012中光标的当前位置运行SQL查询。它可以工作 - 大部分时间都是如此。
该实现使用一种增量移动来确定它何时到达SQL查询块的顶部或窗口的顶部。然后向下选择,直到它以相同的方式到达窗口的底部或块的底部。之后,按F5键运行突出显示的脚本。
这是脚本:
$F5::
; first check that current line isn't blank (the cursor has to be on some text)
Send, {Home}
hltext := SelectNextChar()
If hltext = `r`n
{
; return to current position
Send, {Left}
Return
}
; move cursor up until it gets to the top of the text block
; get first length for future comparisons
Send, {End}
Send, {Shift Down}{Home}{Shift Up}
Send, ^c
StringLen, slctSize, clipboard
; begin checking lengths to see if there is still 'movement'
Loop
{
Send, {Shift Down}{Left}{Home}{Shift Up}
Send, ^c
; if the new length is the same then we've hit the top and can break out
StringLen, temp, clipboard
IfEqual, slctSize, %temp%
{
Send, {Left}
Break
}
; if we have hit a blank space then we can stop here as well
firstChar := SubStr(clipboard, 1, 1)
If firstChar is space
{
Send, {Left}{Down}
Break
}
; if neither one of these conditions are met, continue on
slctSize = %temp%
Sleep, 50
}
; select down until blank space or end of file
Send, {Shift Down}{End}{Shift Up}
Send, ^c
StringLen, slctSize, clipboard
Loop
{
Send, {Shift Down}{Right}{End}{Shift Up}
Send, ^c
StringLen, temp, clipboard
IfEqual, slctSize, %temp%
{
Break
}
; if we have hit a blank space then we can stop here as well
lastChar := SubStr(clipboard, 0)
If lastChar is space
{
Break
}
; if neither one of these conditions are met, continue on
slctSize = %temp%
Sleep, 50
}
; execute!
Send, {F5}
; place cursor at end of last line
Send, {Right}
Return
SelectNextChar()
{
Send, {LShift Down}{Right}{LShift Up}
Send, ^c
return %clipboard%
}
这些动作 - 向上然后向下 - 有时会过早结束,导致在按下F5时不能完全选择查询。对于小型查询,这不是问题;对于跨越大约10行的大型查询,很快就会发生一些事情。
我已经测试了将Sleep, 500
置于循环中,并且似乎来执行此操作,但此脚本的重点是在运行中进行测试查询快得多。如果我等待超过2或3秒钟(希望)突出显示,那么是什么让它比我的旧策略更快,即用鼠标手动突出显示?
要明确的是,较大的查询 大部分都在运行,但过程速度不足以保证使用,并且无法保证在执行前它们会完全突出显示。我也明白我的实现本质上是O(x ^ 2)。但是,如果我在完全爆炸(SetKeyDelay, -1
)上运行脚本,那不会有问题。
有关此事的任何想法或仅仅是操作系统/程序/ AHK的限制?
另外,它只是我还是SO的语法突出显示严重破坏?
更新:这是一个包含建议修改的更新脚本:
SendMode, Input ; Very fast but gives unpredictable results at low sleep speeds
SetBatchLines, -1
$F5::
; first check that current line isn't blank (the cursor has to be on some text)
Send, {Home}
hltext := SelectNextChar()
If hltext = `r`n
{
; return to current position
Send, {Left}
Return
}
; move cursor up until it gets to the top of the text block
; get first length for future comparisons
Send, {End}
Send, {Shift Down}{Home}{Shift Up}
Send, ^c
SleepAfterCopy()
StringLen, slctSize, clipboard
; begin checking lengths to see if there is still 'movement'
Loop
{
Send, {Shift Down}{Left}{Home}{Shift Up}
Send, ^c
SleepAfterCopy()
; if the new length is the same then we've hit the top and can break out
StringLen, temp, clipboard
IfEqual, slctSize, %temp%
{
Send, {Left}
Break
}
; if we have hit a blank space then we can stop here as well
firstChar := SubStr(clipboard, 1, 1)
If firstChar is space
{
Send, {Left}{Down}
Break
}
; if neither one of these conditions are met, continue on
slctSize = %temp%
}
; select down until blank space or end of file
Send, {Shift Down}{End}{Shift Up}
Send, ^c
SleepAfterCopy()
StringLen, slctSize, clipboard
Loop
{
Send, {Shift Down}{Right}{End}{Shift Up}
Send, ^c
SleepAfterCopy()
StringLen, temp, clipboard
IfEqual, slctSize, %temp%
{
Break
}
; if we have hit a blank space then we can stop here as well
lastChar := SubStr(clipboard, 0)
If lastChar is space
{
Break
}
; if neither one of these conditions are met, continue on
slctSize = %temp%
}
; execute!
Send, {F5}
; place cursor at end of last line
Send, {Right}
Return
SelectNextChar()
{
Send, {LShift Down}{Right}{LShift Up}
Send, ^c
return %clipboard%
}
SleepAfterCopy()
{
Sleep, 50
}
更新2:以下是@Sidola中包含ClipWait
的版本。因此它尽可能快地运行。此更新还包括一些逻辑,以确保如果您事先复制了某些内容,则由于我们过度使用剪贴板而无法将其删除。最后,它考虑了行的开头/结尾处的任何缩进或空格:
SendMode, Input ; Very fast but gives unpredictable results at low sleep speeds
SetBatchLines, -1
#IfWinActive ahk_exe Ssms.exe
$F5::
; Save current clipboard material and restore it at the end
before = %clipboard%
; first check that current line isn't blank (the cursor has to be on some text)
Send, {Home}
clipboard =
hltext := SelectNextChar()
If hltext = `r`n
{
; return to current position
Send, {Left}
Return
}
; move cursor up until it gets to the top of the text block
; get first length for future comparisons
Send, {End}
Send, {Shift Down}{Home}{Home}{Shift Up}
clipboard =
Send, ^c
SleepAfterCopy()
StringLen, slctSize, clipboard
; begin checking lengths to see if there is still 'movement'
Loop
{
Send, {Shift Down}{Left}{Home}{Home}{Shift Up}
clipboard =
Send, ^c
SleepAfterCopy()
; if the new length is the same then we've hit the top and can break out
StringLen, temp, clipboard
IfEqual, slctSize, %temp%
{
Send, {Left}
Break
}
; if we have hit a blank space then we can stop here as well
firstChar := SubStr(clipboard, 1, 1)
If firstChar = `r
{
Send, {Left}{Down}
Break
}
; if neither one of these conditions are met, continue on
slctSize = %temp%
}
; select down until blank space or end of file
Send, {Shift Down}{End}{Shift Up}
clipboard =
Send, ^c
SleepAfterCopy()
StringLen, slctSize, clipboard
Loop
{
Send, {Shift Down}{Right}{End}{Shift Up}
clipboard =
Send, ^c
SleepAfterCopy()
StringLen, temp, clipboard
IfEqual, slctSize, %temp%
{
Break
}
; if we have hit a blank space then we can stop here as well
lastChar := SubStr(clipboard, 0)
If lastChar = `n
{
Break
}
; if neither one of these conditions are met, continue on
slctSize = %temp%
}
; execute!
Send, {F5}
; place cursor at end of last line
Send, {Right}
; restore clipboard
clipboard = %before%
Return
+F5::
Send, {F5}
Return
SelectNextChar()
{
Send, {LShift Down}{Right}{LShift Up}
Send, ^c
SleepAfterCopy()
return %clipboard%
}
SleepAfterCopy()
{
ClipWait
; Sleep, 30
}
答案 0 :(得分:1)
它过早结束的原因可能是由于copy-command在你开始工作之前没有足够的时间来正确更新剪贴板。
处理此问题的最佳方法是在复制任何内容之前清除剪贴板,并依赖ClipWait
告诉我们何时复制了某些内容。或者让它超时告诉我们没有任何内容被复制。
ClipWait
还允许我们检测文档的顶部和底部而不检查重复项,因为我们只是等待超时。
以下是一个尽可能快的工作示例。
但请注意:此脚本仅适用于copy-command正常运行的程序。这意味着如果您没有选择进行复制,则不会复制任在尝试这个时,我发现有些程序没有这种行为,因此这个脚本不适用于那些程序。在这些情况下,您将不得不采用某种方式检查重复项。
SendMode, Input
SetBatchLines, -1
Esc::ExitApp
$F5::
; Check if the line we're currently at is just a line break
if (isLineBreak( getFirstChar() ))
return
; Get to the top of the document
traverseText("up")
; Get to the bottom
lineCount := traverseText("down")
; Select everything
selectAllLines(lineCount)
return
; --- Only functions below ---
selectAllLines(lineCount) {
Send, {LShift Down}
Loop, % lineCount {
Send, {Up}
}
Send, {Home}
Send, {LShift Up}
}
traverseText(direction) {
Loop {
selectLine(direction)
thisLine := copyText()
; If it's just a line break, we're out
if (isLineBreak(thisLine)) {
; If we were going up we want to move down once first
if (direction = "up")
Send, {Down}
break
}
; If nothing was copied, we're out
if (!thisLine)
break
i := A_Index ; Keep track of how many lines we've moved passed
}
; If we had a line break beneath us
; we need to add one to the counter
if (thisLine)
i++
return i ; Return the amount of lines we traversed
}
isLineBreak(value) {
return value = "`r`n"
}
getFirstChar() {
Send, {Home}+{Down} ; Home, Shift + Down
char := copyText()
Send, {Left}
return char
}
selectLine(direction) {
Send, % direction = "up" ? "{Home}" : "{End}" ; Ternary operator
Send, {LShift Down}
Send, % direction = "up" ? "{Up}" : "{Down}" ; Ternary operator
Send, {LShift Up}
}
copyText() {
Clipboard := ""
Send, ^c
ClipWait, 0.2 ; Time-out after 200ms
return Clipboard
}