search movement: f, F, t, T

This commit is contained in:
Sean Yeh 2014-12-18 15:10:00 -06:00
parent 802146e937
commit 0be5f4207c
2 changed files with 199 additions and 55 deletions

View File

@ -1,11 +1,15 @@
# vibreoffice # vibreoffice
A Vi/Vim Mode Extension for Libreoffice and OpenOffice (Apache OpenOffice, OpenOffice.org) A Vi/Vim Mode Extension for Libreoffice and OpenOffice (Apache OpenOffice, OpenOffice.org)
### Installation
Coming soon.
### Features ### Features
vibreoffice currently supports: vibreoffice currently supports:
- Insert (`i`, `I`, `a`, `A`), Visual (`v`), Normal modes - Insert (`i`, `I`, `a`, `A`), Visual (`v`), Normal modes
- Movement keys: `hjkl`, `w/W`, `b/B`, `e`, `$`, `^`, `{}`, `()`, `ctrl+d`, `ctrl+u` - Movement keys: `hjkl`, `w`, `W`, `b`, `B`, `e`, `$`, `^`, `{}`, `()`, `C-d`, `C-u`
- Number modifiers: e.g. `5w` - Search movement: `f`, `F`, `t`, `T`
- Number modifiers: e.g. `5w`, `4fa`
- Deletion: `x`, `d`, `c`, `dd`, `cc` - Deletion: `x`, `d`, `c`, `dd`, `cc`
- Plus movement and number modifiers: e.g. `dw`, `c$`, `5dd`, `c3j` - Plus movement and number modifiers: e.g. `dw`, `c$`, `5dd`, `c3j`
- More to come! - More to come!

View File

@ -67,7 +67,7 @@ Sub setRawStatus(rawText)
End Sub End Sub
Sub setStatus(statusText) Sub setStatus(statusText)
setRawStatus(MODE & " | " & statusText & " | special: " & getSpecial()) setRawStatus(MODE & " | " & statusText & " | special: " & getSpecial() & " | " & "modifier: " & getMovementModifier())
End Sub End Sub
Sub setMode(modeName) Sub setMode(modeName)
@ -79,6 +79,7 @@ Function gotoMode(sMode)
Select Case sMode Select Case sMode
Case "NORMAL": Case "NORMAL":
setMode("NORMAL") setMode("NORMAL")
setMovementModifier("")
Case "INSERT": Case "INSERT":
setMode("INSERT") setMode("INSERT")
Case "VISUAL": Case "VISUAL":
@ -100,6 +101,10 @@ Sub cursorReset(oTextCursor)
thisComponent.getCurrentController.Select(oTextCursor) thisComponent.getCurrentController.Select(oTextCursor)
End Sub End Sub
Function samePos(oPos1, oPos2)
samePos = oPos1.X() = oPos2.X() And oPos1.Y() = oPos2.Y()
End FUnction
' ----------------------------------- ' -----------------------------------
' Special Mode (for chained commands) ' Special Mode (for chained commands)
@ -134,6 +139,22 @@ Sub resetSpecial(Optional bForce)
End If End If
End Sub End Sub
' -----------------
' Movement Modifier
' -----------------
'f,i,a
global MOVEMENT_MODIFIER As string
Sub setMovementModifier(modifierName)
MOVEMENT_MODIFIER = modifierName
End Sub
Function getMovementModifier()
getMovementModifier = MOVEMENT_MODIFIER
End Function
' -------------------- ' --------------------
' Multiplier functions ' Multiplier functions
' -------------------- ' --------------------
@ -215,7 +236,8 @@ function KeyHandler_KeyPressed(oEvent) as boolean
bConsumeInput = False bConsumeInput = False
' If Change Mode ' If Change Mode
ElseIf MODE = "NORMAL" And Not bIsSpecial And ProcessModeKey(oEvent) Then ' ElseIf MODE = "NORMAL" And Not bIsSpecial And getMovementModifier() = "" And ProcessModeKey(oEvent) Then
ElseIf ProcessModeKey(oEvent) Then
' Pass ' Pass
' Multiplier Key ' Multiplier Key
@ -232,6 +254,11 @@ function KeyHandler_KeyPressed(oEvent) as boolean
ElseIf bIsModified Then ElseIf bIsModified Then
bConsumeInput = False bConsumeInput = False
' Movement modifier here?
ElseIf ProcessMovementModifierKey(oEvent.KeyChar) Then
' Pass
' If bIsSpecial but nothing matched, return to normal mode ' If bIsSpecial but nothing matched, return to normal mode
ElseIf bIsSpecial Then ElseIf bIsSpecial Then
gotoMode("NORMAL") gotoMode("NORMAL")
@ -242,7 +269,7 @@ function KeyHandler_KeyPressed(oEvent) as boolean
resetSpecial() resetSpecial()
' Reset multiplier if last input was not number and not in special mode ' Reset multiplier if last input was not number and not in special mode
If not bIsMultiplier and getSpecial() = "" Then If not bIsMultiplier and getSpecial() = "" and getMovementModifier() = "" Then
resetMultiplier() resetMultiplier()
End If End If
setStatus(getMultiplier()) setStatus(getMultiplier())
@ -301,6 +328,13 @@ End Function
Function ProcessModeKey(oEvent) Function ProcessModeKey(oEvent)
' Don't change modes in these circumstances
If MODE <> "NORMAL" Or getSpecial <> "" Or getMovementModifier() <> "" Then
ProcessModeKey = False
Exit Function
End If
' Mode matching
dim bMatched dim bMatched
bMatched = True bMatched = True
Select Case oEvent.KeyChar Select Case oEvent.KeyChar
@ -337,6 +371,9 @@ Function ProcessNormalKey(oEvent)
bMatched = bMatched or bMatchedMovement bMatched = bMatched or bMatchedMovement
Next i Next i
' Reset Movement Modifier
setMovementModifier("")
If bMatched Then If bMatched Then
' If Special: d/c + movement ' If Special: d/c + movement
If bMatched And (getSpecial() = "d" Or getSpecial() = "c") Then If bMatched And (getSpecial() = "d" Or getSpecial() = "c") Then
@ -466,6 +503,89 @@ Function ProcessDeleteKey(keyChar)
End Function End Function
Function ProcessMovementModifierKey(keyChar)
dim bMatched
bMatched = True
Select Case keyChar
Case "f", "t", "F", "T":
setMovementModifier(keyChar)
Case Else:
bMatched = False
End Select
ProcessMovementModifierKey = bMatched
End Function
' Returns the resulting TextCursor
Function ProcessSearchKey(oTextCursor, searchType, keyChar, bExpand)
' REALLY ugly hack to figure out corner cases for backtracking
dim iBacktrack, oPos1, oPos2, oPos3
iBacktrack = 0
' In forward searching, we start searching from the next character.
' Thus, we need to move the cursor back 1 if the search fails.
' Exception:
' iBackTrack = 0 if cursor is at the end of the document
oPos1 = getCursor().getPosition()
getCursor().goRight(1, bExpand)
oPos2 = getCursor().getPosition()
If Not samePos(oPos1, oPos2) Then
getCursor().goRight(1, bExpand)
oPos3 = getCursor().getPosition()
' Cursor is not at the end of the document
If Not samePos(oPos2, oPos3) Then
iBacktrack = 1
getCursor().goLeft(1, bExpand)
End If
getCursor().goLeft(1, bExpand)
End If
' -------------------------
'-----------
' Searching
'-----------
dim oSearchDesc, oFoundRange, bIsBackwards, oStartRange
bIsBackwards = (searchType = "F" Or searchType = "T")
If Not bIsBackwards Then
' Start searching from next character
oTextCursor.goRight(1, bExpand)
oStartRange = oTextCursor.getEnd()
Else
oStartRange = oTextCursor.getStart()
End If
oSearchDesc = thisComponent.createSearchDescriptor()
oSearchDesc.setSearchString(keyChar)
oSearchDesc.SearchCaseSensitive = True
oSearchDesc.SearchBackwards = bIsBackwards
oFoundRange = thisComponent.findNext( oStartRange, oSearchDesc )
If not IsNull(oFoundRange) Then
oTextCursor.gotoRange(oFoundRange.getStart(), bExpand)
If getMovementModifier() = "t" Then
oTextCursor.goLeft(1, bExpand)
ElseIf getMovementModifier() = "T" Then
oTextCursor.goRight(1, bExpand)
End If
Else
' Backtrack hack
dim i
For i = 1 to iBacktrack
If not bIsBackwards Then
oTextCursor.goLeft(1, bExpand)
End If
Next i
End If
End Function
' ----------------------- ' -----------------------
' Main Movement Function ' Main Movement Function
' ----------------------- ' -----------------------
@ -499,63 +619,83 @@ Function ProcessMovementKey(keyChar, Optional bExpand, Optional keyModifiers)
' Set global cursor to oTextCursor's new position if moved ' Set global cursor to oTextCursor's new position if moved
bSetCursor = True bSetCursor = True
Select Case keyChar
Case "l":
oTextCursor.goRight(1, bExpand)
Case "h":
oTextCursor.goLeft(1, bExpand)
' oTextCursor.goUp and oTextCursor.goDown SHOULD work, but doesn't (I dont know why). ' ------------------
' So this is a weird hack ' Movement matching
Case "k": ' ------------------
'oTextCursor.goUp(1, False)
getCursor().goUp(1, bExpand)
bSetCursor = False
Case "j":
'oTextCursor.goDown(1, False)
getCursor().goDown(1, bExpand)
bSetCursor = False
' ----------
Case "^": ' Special Case: Modified movements
getCursor().gotoStartOfLine(bExpand) If getMovementModifier() <> "" Then
bSetCursor = False Select Case getMovementModifier()
Case "$": ' ------------------
dim oldPos, newPos ' f,F,t,T searching
oldPos = getCursor().getPosition() ' ------------------
getCursor().gotoEndOfLine(bExpand) Case "f", "t", "F", "T":
newPos = getCursor().getPosition() processSearchKey(oTextCursor, getMovementModifier(), keyChar, bExpand)
' If the result is at the start of the line, then it must have Case Else:
' jumped down a line; goLeft to return to the previous line. bSetCursor = False
' Except for: Empty lines (check for oldPos = newPos) bMatched = False
If getCursor().isAtStartOfLine() And oldPos.Y() <> newPos.Y() Then End Select
getCursor().goLeft(1, bExpand)
End If
' maybe eventually cursorGoto... should return True/False for bsetCursor ElseIf keyChar = "l" Then
bSetCursor = False oTextCursor.goRight(1, bExpand)
Case "w", "W": ElseIf keyChar = "h" Then
oTextCursor.gotoNextWord(bExpand) oTextCursor.goLeft(1, bExpand)
Case "b", "B":
oTextCursor.gotoPreviousWord(bExpand)
Case "e":
oTextCursor.gotoEndOfWord(bExpand)
Case ")": ' oTextCursor.goUp and oTextCursor.goDown SHOULD work, but doesn't (I dont know why).
oTextCursor.gotoNextSentence(bExpand) ' So this is a weird hack
Case "(": ElseIf keyChar = "k" Then
oTextCursor.gotoPreviousSentence(bExpand) 'oTextCursor.goUp(1, False)
Case "}": getCursor().goUp(1, bExpand)
oTextCursor.gotoNextParagraph(bExpand) bSetCursor = False
Case "{":
oTextCursor.gotoPreviousParagraph(bExpand)
Case Else: ElseIf keyChar = "j" Then
bSetCursor = False 'oTextCursor.goDown(1, False)
bMatched = False getCursor().goDown(1, bExpand)
End Select bSetCursor = False
' ----------
ElseIf keyChar = "^" Then
getCursor().gotoStartOfLine(bExpand)
bSetCursor = False
ElseIf keyChar = "$" Then
dim oldPos, newPos
oldPos = getCursor().getPosition()
getCursor().gotoEndOfLine(bExpand)
newPos = getCursor().getPosition()
' If the result is at the start of the line, then it must have
' jumped down a line; goLeft to return to the previous line.
' Except for: Empty lines (check for oldPos = newPos)
If getCursor().isAtStartOfLine() And oldPos.Y() <> newPos.Y() Then
getCursor().goLeft(1, bExpand)
End If
' maybe eventually cursorGoto... should return True/False for bsetCursor
bSetCursor = False
ElseIf keyChar = "w" or keyChar = "W" Then
oTextCursor.gotoNextWord(bExpand)
ElseIf keyChar = "b" or keyChar = "B" Then
oTextCursor.gotoPreviousWord(bExpand)
ElseIf keyChar = "e" Then
oTextCursor.gotoEndOfWord(bExpand)
ElseIf keyChar = ")" Then
oTextCursor.gotoNextSentence(bExpand)
ElseIf keyChar = "(" Then
oTextCursor.gotoPreviousSentence(bExpand)
ElseIf keyChar = "}" Then
oTextCursor.gotoNextParagraph(bExpand)
ElseIf keyChar = "{" Then
oTextCursor.gotoPreviousParagraph(bExpand)
Else
bSetCursor = False
bMatched = False
End If
' If oTextCursor was moved, set global cursor to its position ' If oTextCursor was moved, set global cursor to its position
If bSetCursor Then If bSetCursor Then