diff --git a/VimWord.dotm b/VimWord.dotm index ece63a4..15a183a 100755 Binary files a/VimWord.dotm and b/VimWord.dotm differ diff --git a/frmGrabKeys.frm b/frmGrabKeys.frm index c662816..9786908 100755 --- a/frmGrabKeys.frm +++ b/frmGrabKeys.frm @@ -23,6 +23,10 @@ Attribute VB_Exposed = False ' 2018-05-02 chrisw Refactored motion code into ProcessMotion_ ' 2018-05-07 chrisw Added ninja-feet; refactored regex ' 2018-05-12 chrisw Added x X . +' 2018-06-07 chrisw Added VSpace. Also, changed IsEmpty checks to +' Len>0 checks. I had a situation in which a non-match +' returned "" rather than Empty. +' Added special-case code for 0 after nonempty count2. ' NOTE: the consolidated reference is in :help normal-index @@ -299,6 +303,7 @@ Public VOperatorCount As Long Public VMotionCount As Long Public VArg As String Public VNinja As VimNinja +Public VSpace As Boolean Private DotCount_ As Long ' Count on a `.` @@ -306,7 +311,9 @@ Private DotCount_ As Long ' Count on a `.` Private RE_ACT As VBScript_RegExp_55.RegExp ' Submatch numbers - see vim-regex.txt +Private RESM_SPACEONE As Long Private RESM_COUNT1 As Long +Private RESM_SPACETWO As Long Private RESM_IVERB As Long Private RESM_IMOTION As Long Private RESM_ITEXT As Long @@ -331,7 +338,8 @@ Private Sub UserForm_Initialize() VMotionCount = 1 VArg = "" VNinja = vnUndef - + VSpace = False + DotCount_ = 1 Dim RE_PAT As String @@ -341,25 +349,26 @@ Private Sub UserForm_Initialize() ' DO NOT MODIFY HERE. If you need to change it, modify vim-regex.txt ' and re-run re2vba.pl. - RE_PAT = _ - "^(([1-9][0-9]*)?((([HMLGhjklwbWB\x28\x29\x7b\x7d]|g?[eE0\^\$" & _ - "]|[fFtT](.))|(gW)?g?[\*#]|g?[pP])|([cdyv])([1-9][0-9]*)?(([\" & _ - "[\]])?([ai])([wWsp])|[fFtT](.)|[HMLGhjklwbWB\x28\x29\x7b\x7d" & _ - "]|g?[eE0\^\$])|([xX\.])))$" & _ + "^(([ ]?)([1-9][0-9]*)?(([ ]?)(([HMLGhjklwbWB\x28\x29\x7b\x7d" & _ + "]|g?[eE0\^\$]|[fFtT](.))|(gW)?g?[\*#]|g?[pP])|([cdyv])([1-9]" & _ + "[0-9]*)?(([\[\]])?([ai])([wWsp])|[fFtT](.)|[HMLGhjklwbWB\x28" & _ + "\x29\x7b\x7d]|g?[eE0\^\$])|([xX\.])))$" & _ "" - RESM_COUNT1 = 1 - RESM_IVERB = 3 - RESM_IMOTION = 4 - RESM_ITEXT = 5 - RESM_TVERB = 7 - RESM_COUNT2 = 8 - RESM_TARGET = 9 - RESM_NINJA = 10 - RESM_TOBJ_RANGE = 11 - RESM_OBJTYPE = 12 - RESM_TTEXT = 13 - RESM_TVERBABBR = 14 + RESM_SPACEONE = 1 + RESM_COUNT1 = 2 + RESM_SPACETWO = 4 + RESM_IVERB = 5 + RESM_IMOTION = 6 + RESM_ITEXT = 7 + RESM_TVERB = 9 + RESM_COUNT2 = 10 + RESM_TARGET = 11 + RESM_NINJA = 12 + RESM_TOBJ_RANGE = 13 + RESM_OBJTYPE = 14 + RESM_TTEXT = 15 + RESM_TVERBABBR = 16 ' === End of generated code === @@ -451,7 +460,8 @@ Private Function ProcessHit_(hit As VBScript_RegExp_55.Match) As Boolean VMotionCount = 1 VArg = "" VNinja = vnUndef - + VSpace = False + ' Don't change DotCount_, which is set by Update() ' Internal variables so we can alias, e.g., `x` to `dl` @@ -461,11 +471,17 @@ Private Function ProcessHit_(hit As VBScript_RegExp_55.Match) As Boolean ' Special-case "0" in code so that I don't have to special-case it in the ' regex. A non-empty count preceding a "0" command means that the "0" ' should actually be part of the count, so wait for more keys. - If (Not IsEmpty(hit.SubMatches(RESM_COUNT1))) And _ - (hit.SubMatches(RESM_IMOTION) = "0") _ + If ((Len(hit.SubMatches(RESM_COUNT1)) > 0) And (hit.SubMatches(RESM_IMOTION) = "0")) Or _ + ((Len(hit.SubMatches(RESM_COUNT2)) > 0) And (hit.SubMatches(RESM_TARGET) = "0")) _ Then ' ^ Empty decays to "" Exit Function End If + + ' Check for indicators + If (Len(hit.SubMatches(RESM_SPACEONE)) > 0) Or _ + (Len(hit.SubMatches(RESM_SPACETWO)) > 0) Then + VSpace = True + End If ' Count before the command, if any If Len(hit.SubMatches(RESM_COUNT1)) = 0 Then @@ -475,7 +491,7 @@ Private Function ProcessHit_(hit As VBScript_RegExp_55.Match) As Boolean VOperatorCount = CLng(hit.SubMatches(RESM_COUNT1)) End If - If Not IsEmpty(hit.SubMatches(RESM_TVERBABBR)) Then ' transitive, abbreviated + If Len(hit.SubMatches(RESM_TVERBABBR)) > 0 Then ' transitive, abbreviated Select Case hit.SubMatches(RESM_TVERBABBR) ' `.`: succeed early - VCommand and VOperatorCount are the only things that matter Case ".": @@ -498,12 +514,12 @@ Private Function ProcessHit_(hit As VBScript_RegExp_55.Match) As Boolean VOperatorCount = VOperatorCount * DotCount_ DotCount_ = 1 - If Not IsEmpty(hit.SubMatches(RESM_IVERB)) Then ' intransitive + If Len(hit.SubMatches(RESM_IVERB)) > 0 Then ' intransitive - Debug.Print "Intransit.", IIf(IsEmpty(hit.SubMatches(RESM_IMOTION)), "-", hit.SubMatches(RESM_IMOTION)), _ + Debug.Print "Intransit.", IIf(Len(hit.SubMatches(RESM_IMOTION)) = 0, "-", hit.SubMatches(RESM_IMOTION)), _ hit.SubMatches(RESM_IVERB), hit.SubMatches(RESM_ITEXT) - If Not IsEmpty(hit.SubMatches(RESM_IMOTION)) Then + If Len(hit.SubMatches(RESM_IMOTION)) > 0 Then If ProcessMotion_(hit.SubMatches(RESM_IMOTION)) Then VOperator = voGo Else @@ -540,7 +556,7 @@ Private Function ProcessHit_(hit As VBScript_RegExp_55.Match) As Boolean End Select End If 'a motion else - ElseIf Not IsEmpty(tverb) Then ' transitive + ElseIf Len(tverb) > 0 Then ' transitive Debug.Print "Transitive", tverb, hit.SubMatches(RESM_COUNT2), Left(target, 1), hit.SubMatches(RESM_OBJTYPE), hit.SubMatches(RESM_TTEXT) @@ -564,7 +580,7 @@ Private Function ProcessHit_(hit As VBScript_RegExp_55.Match) As Boolean If ProcessMotion_(CStr(target)) Then ' Motion without argument ' Nothing more to do - ElseIf Not IsEmpty(hit.SubMatches(RESM_TOBJ_RANGE)) Then ' Text object + ElseIf Len(hit.SubMatches(RESM_TOBJ_RANGE)) > 0 Then ' Text object Select Case hit.SubMatches(RESM_TOBJ_RANGE) Case "a": Select Case hit.SubMatches(RESM_OBJTYPE) @@ -587,7 +603,7 @@ Private Function ProcessHit_(hit As VBScript_RegExp_55.Match) As Boolean Case Else: Exit Function End Select - If Not IsEmpty(hit.SubMatches(RESM_NINJA)) Then + If Len(hit.SubMatches(RESM_NINJA)) > 0 Then VNinja = IIf(hit.SubMatches(RESM_NINJA) = "[", vnLeft, vnRight) End If @@ -617,7 +633,7 @@ Private Sub Update() Dim done As Boolean: done = False Dim times_through As Long: times_through = 0 'deadman - lblKeys.Caption = Keys + lblKeys.Caption = Replace(Keys, " ", ChrW(&H2423)) ' Make spaces visible ' parse Vim commands to see if one is done Dim matches As VBScript_RegExp_55.MatchCollection diff --git a/frmGrabKeys.frx b/frmGrabKeys.frx index aa2d25b..9265c14 100755 Binary files a/frmGrabKeys.frx and b/frmGrabKeys.frx differ diff --git a/mVimWord.bas b/mVimWord.bas index c58d6c5..36534c8 100755 --- a/mVimWord.bas +++ b/mVimWord.bas @@ -11,6 +11,7 @@ Attribute VB_Name = "mVimWord" ' 2018-05-04 chrisw Changed paste behaviour per Word ' 2018-05-07 chrisw gp/gP now paste unformatted text; added ninja-feet ' 2018-05-10 chrisw Fixed whitespace classes used for text objects +' 2018-06-07 chrisw Hack in voDelete/voChange for strange Word behaviour. ' General comment: Word puts the cursor between characters; Vim puts the ' cursor on characters. This makes quite a difference. I may need @@ -26,7 +27,7 @@ Public VimLastCommand_ As String ' Public Sub VimDoCommand_About() - MsgBox "VimWord version 0.2.11, 2018-05-12. Copyright (c) 2018 Christopher White. " & _ + MsgBox "VimWord version 0.2.12, 2018-06-07. Copyright (c) 2018 Christopher White. " & _ "All Rights Reserved. Licensed CC-BY-NC-SA 4.0 (or later).", _ vbOKOnly + vbInformation, "About VimWord" End Sub 'VimDoCommand_About @@ -73,7 +74,8 @@ Private Sub VDCInternal(LoopIt As Boolean) Dim cmdstr As String: cmdstr = "" Dim arg As String: arg = "" Dim ninja As VimNinja: ninja = vnUndef - + Dim space As Boolean: space = False + If Not frm.WasCancelled Then cmdstr = frm.Keys oper = frm.VOperator @@ -83,13 +85,14 @@ Private Sub VDCInternal(LoopIt As Boolean) motionc = frm.VMotionCount arg = frm.VArg ninja = frm.VNinja + space = frm.VSpace End If Unload frm Set frm = Nothing If (cmd <> vcUndef) Or (oper <> voUndef And motion <> vmUndef) Then vimRunCommand doc, proczone, coll, atStart, oper, cmd, motion, _ - operc, motionc, cmdstr, arg, ninja + operc, motionc, cmdstr, arg, ninja, space Application.ScreenRefresh End If @@ -111,7 +114,8 @@ Private Sub vimRunCommand( _ motionc As Long, _ cmdstr As String, _ arg As String, _ - ninja As VimNinja _ + ninja As VimNinja, _ + space As Boolean _ ) Dim TITLE As String: TITLE = "Do Vim command" @@ -388,7 +392,14 @@ Private Sub vimRunCommand( _ Case vnRight proczone.Start = origpzstart End Select - + + ' Extra whitespace. Takes effect after ninja-feet. + If space And (colldir = wdCollapseEnd) Then + proczone.MoveEndWhile CSET_WS_ONELINE, wdForward + ElseIf space And (colldir = wdCollapseStart) Then + proczone.MoveStartWhile CSET_WS_ONELINE, wdBackward + End If + ' === Operator/Command ================================================== ' Process it. We have either an operator or a command. @@ -400,13 +411,26 @@ Private Sub vimRunCommand( _ If proczone.Start <> proczone.End Then proczone.Copy GoTo VRC_Finally - Case voDelete: - If proczone.Start <> proczone.End Then proczone.Cut + Case voDelete, voChange: + If proczone.Start <> proczone.End Then + ' Word doesn't always delete the whole selection! + Dim endr As Range + Set endr = proczone.Duplicate + endr.Collapse wdCollapseEnd + endr.MoveEnd wdCharacter, 1 + + proczone.Cut + + If endr.Characters.count > 1 Then ' something strange happened + If endr.Characters.First = ChrW(13) Then + endr.End = endr.Start + 1 + endr.Delete + End If + End If + + End If GoTo VRC_Finally - Case voChange: - If proczone.Start <> proczone.End Then proczone.Cut - ' voGo, voSelect handled below End Select 'operator diff --git a/re2vba.pl b/re2vba.pl index b201303..6b895b1 100755 --- a/re2vba.pl +++ b/re2vba.pl @@ -197,6 +197,10 @@ =head1 OPTIONS If given on the command line, do not print the C statements. +=item --private + +If given, use C instead of C. + =item -q, --quiet Do not print the diagnostic messages while running diff --git a/vim-regex.txt b/vim-regex.txt index 8c79644..5fcca65 100755 --- a/vim-regex.txt +++ b/vim-regex.txt @@ -4,16 +4,28 @@ # Useful command line: # ./re2vba.pl --nodim vim-regex.txt |tee >(putclip) +# Available normal-mode commands: at least Q (no Ex mode), U (Word doesn't +# save undo information per line). + # Main pattern main ^( (?# Note: registers not yet implemented) + (?[ ]?) (?[1-9][0-9]*)? (?: + (?[ ]?) (?<=intrans) |(?<=trans) |(?<=trans-abbr) ) )$ + # in or (or both; no cumulative + # effect) applied with an operator that will cause the motion to + # extend to include any further inline whitespace. E.g., df, + # will delete to the following comma, and delete any spaces or tabs + # after that comma. Likewise, db will delete one word + # backwards, and any inline whitespace before that word. + # Motions that don't take arguments (although they may take counts). # A motion of "0" is special-cased in the parsing code to keep the regex # clean. This regex, after backtracking, matches "10" as a count of "1" @@ -56,7 +68,7 @@ trans (?[cdyv]) (?# TVERB: what to do) (?<=noarg-motion) ) -# Transitive abbreviations: x, ., ... . These are the end of the entry --- +# Transitive abbreviations: x, ., ... . These are the end of the entry --- # nothing comes after them. trans-abbr (?[xX\.])