Version 0.1 - readme, install files, and more
This commit is contained in:
parent
65780b1896
commit
918ea95a48
|
@ -0,0 +1,22 @@
|
|||
run_testing: testing
|
||||
killall soffice.bin || echo "No libreoffice instance found"
|
||||
lowriter "$$TESTING_ODT" --norestore &
|
||||
|
||||
testing: src/vibreoffice.vbs
|
||||
./compile.sh "src/vibreoffice.vbs" "$$TESTING_XBA"
|
||||
|
||||
extension: clean src/vibreoffice.vbs
|
||||
if [ -z "$$VIBREOFFICE_VERSION" ]; then \
|
||||
echo "VIBREOFFICE_VERSION must be set"; \
|
||||
else \
|
||||
mkdir -p build; mkdir -p dist; \
|
||||
cp -r extension/template build/template; \
|
||||
./compile.sh "src/vibreoffice.vbs" "build/template/vibreoffice/vibreoffice.xba"; \
|
||||
cd "build/template"; \
|
||||
sed -i "s/%VIBREOFFICE_VERSION%/$$VIBREOFFICE_VERSION/g" description.xml; \
|
||||
zip -r "../../dist/vibreoffice-$$VIBREOFFICE_VERSION.oxt" .; \
|
||||
fi
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf build
|
56
README.md
56
README.md
|
@ -1,10 +1,30 @@
|
|||
# vibreoffice
|
||||
A Vi/Vim Mode Extension for Libreoffice and OpenOffice (Apache OpenOffice, OpenOffice.org)
|
||||
|
||||
### Installation
|
||||
Coming soon.
|
||||
vibreoffice is an extension for Libreoffice and OpenOffice that brings some of
|
||||
your favorite key bindings from vi/vim to your favorite office suite. It is
|
||||
obviously not meant to be feature-complete, but hopefully will be useful to
|
||||
both vi/vim neophytes and experts alike.
|
||||
|
||||
### Installation/Usage
|
||||
|
||||
The easiest way to install is to download the
|
||||
[latest extension file](https://raw.github.com/seanyeh/vibreoffice/master/dist/vibreoffice-0.1.0.oxt)
|
||||
and open it with LibreOffice/OpenOffice.
|
||||
|
||||
To enable/disable vibreoffice, simply select Tools -> Add-Ons -> vibreoffice.
|
||||
|
||||
If you really want to, you can build the .oxt file yourself by running
|
||||
```shell
|
||||
# replace 0.0.0 with your desired version number
|
||||
VIBREOFFICE_VERSION="0.0.0" make extension
|
||||
```
|
||||
This will simply build the extension file from the template files in
|
||||
`extension/template`. These template files were auto-generated using
|
||||
[Extension Compiler](https://wiki.openoffice.org/wiki/Extensions_Packager#Download).
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
vibreoffice currently supports:
|
||||
- Insert (`i`, `I`, `a`, `A`, `o`, `O`), Visual (`v`), Normal modes
|
||||
- Movement keys: `hjkl`, `w`, `W`, `b`, `B`, `e`, `$`, `^`, `{}`, `()`, `C-d`, `C-u`
|
||||
|
@ -14,7 +34,35 @@ vibreoffice currently supports:
|
|||
- Deletion: `x`, `d`, `c`, `s`, `D`, `C`, `S`, `dd`, `cc`
|
||||
- Plus movement and number modifiers: e.g. `5dw`, `c3j`, `2dfe`
|
||||
- Delete a/inner block: e.g. `di(`, `da{`, `ci[`, `ci"`, `ca'`, `dit`
|
||||
- More to come!
|
||||
|
||||
### Known differences/issues
|
||||
|
||||
If you are familiar with vi/vim, then vibreoffice should give very few
|
||||
surprises. However, there are some differences, primarily due to word
|
||||
processor-text editor differences or limitations of the LibreOffice API and/or
|
||||
my patience.
|
||||
- The concept of lines in a text editor is not quite analogous to that of a
|
||||
word processor. I made my best effort to incorporate the line analogy while keeping
|
||||
the spirit of word processing.
|
||||
- Unlike vi/vim, movement keys will wrap to the next line
|
||||
- Due to line wrapping, you may find your cursor move up/down a line for
|
||||
commands that would otherwise leave you in the same position (such as `dd`)
|
||||
- Currently, I am using LibreOffice's built-in word detection for word
|
||||
movements (`w`, `W`, etc.) which differs slightly from vi's. For many
|
||||
situations I find this satisfactory, but there are some funky cases involving
|
||||
certain symbols. I may or may not change this in the future.
|
||||
- vibreoffice does not have contextual awareness. What I mean by that is that
|
||||
it does not keep track of which parentheses/braces match. Hence, you may have
|
||||
unexpected behavior (using commands such as `di(`) if your document has
|
||||
syntatically uneven parentheses/braces or nesting of such symbols. I don't
|
||||
intend to fix this for now, as I don't believe this is a critical feature for
|
||||
word processing.
|
||||
- Using `d`, `c` (or any of their variants) will temporarily bring you into
|
||||
Visual mode. This is intentional and should not have any noticeable effects.
|
||||
|
||||
vibreoffice is new, so it is bound to have plenty of bugs. Please let me know
|
||||
if you run into anything!
|
||||
|
||||
|
||||
### License
|
||||
vibreoffice is released under the MIT License.
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# "Compile" BASIC macro file to LibreOffice-compatible xba file
|
||||
|
||||
# compile SRC DESTINATION
|
||||
compile() {
|
||||
# Escape XML &<>'"
|
||||
src=`sed "s/\&/\&/g; s/</\</g; s/>/\>/g; s/'/\'/g; s/\"/\"/g" "$1"`
|
||||
|
||||
xbafile="$2"
|
||||
name="`basename -s \".xba\" "$xbafile"`"
|
||||
|
||||
XBA_TEMPLATE='<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">\n<script:module xmlns:script="http://openoffice.org/2000/script" script:name="%s" script:language="StarBasic">\n%s\n</script:module>'
|
||||
|
||||
printf "$XBA_TEMPLATE" "$name" "$src" > "$xbafile"
|
||||
}
|
||||
|
||||
if [ "$#" -ne 2 ]; then
|
||||
echo "Usage: $0 SOURCE DESTINATION"
|
||||
else
|
||||
compile "$1" "$2"
|
||||
fi
|
Binary file not shown.
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<oor:component-data xmlns:oor="http://openoffice.org/2001/registry"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
oor:name="Addons" oor:package="org.openoffice.Office">
|
||||
<node oor:name="AddonUI">
|
||||
|
||||
<node oor:name="AddonMenu">
|
||||
<node oor:name="vibreoffice.N001" oor:op="replace">
|
||||
<prop oor:name="Context" oor:type="xs:string">
|
||||
<value>com.sun.star.text.TextDocument,com.sun.star.drawing.DrawingDocument,com.sun.star.presentation.PresentationDocument</value>
|
||||
</prop>
|
||||
<prop oor:name="Title" oor:type="xs:string">
|
||||
<value xml:lang="en">vibreoffice - Toggle Vi Mode</value>
|
||||
</prop>
|
||||
<prop oor:name="URL" oor:type="xs:string">
|
||||
<value>vnd.sun.star.script:vibreoffice.vibreoffice.Main?language=Basic&location=application</value>
|
||||
</prop>
|
||||
<prop oor:name="Target" oor:type="xs:string">
|
||||
<value>_self</value>
|
||||
</prop>
|
||||
</node>
|
||||
</node>
|
||||
|
||||
</node>
|
||||
</oor:component-data>
|
|
@ -0,0 +1,2 @@
|
|||
Vi Mode Extension for LibreOffice/OpenOffice
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE manifest:manifest PUBLIC "-//OpenOffice.org//DTD Manifest 1.0//EN" "Manifest.dtd">
|
||||
<manifest:manifest xmlns:manifest="http://openoffice.org/2001/manifest">
|
||||
<manifest:file-entry manifest:media-type="application/vnd.sun.star.help"
|
||||
manifest:full-path="help" />
|
||||
<manifest:file-entry manifest:media-type="application/vnd.sun.star.basic-library"
|
||||
manifest:full-path="vibreoffice/" />
|
||||
<manifest:file-entry manifest:media-type="application/vnd.sun.star.configuration-data"
|
||||
manifest:full-path="AddonUI.xcu" />
|
||||
</manifest:manifest>
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Extension files were created by Extension Compiler - version 2.1.1 -->
|
||||
<description xmlns="http://openoffice.org/extensions/description/2006"
|
||||
xmlns:dep="http://openoffice.org/extensions/description/2006"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink" >
|
||||
<identifier value="vibreoffice" />
|
||||
<version value="%VIBREOFFICE_VERSION%" />
|
||||
<extension-description>
|
||||
<src xlink:href="Descriptions/descr-en.txt" lang="en"/>
|
||||
</extension-description>
|
||||
<dependencies>
|
||||
<OpenOffice.org-minimal-version value="3.1" dep:name="OpenOffice.org 3.1 minimum, or more recent" />
|
||||
</dependencies>
|
||||
<display-name>
|
||||
<name lang="en">Vibreoffice - Vi-Mode Extension</name>
|
||||
</display-name>
|
||||
<publisher>
|
||||
<name lang="en" xlink:href="http://www.seanyeh.com">Sean Yeh</name>
|
||||
</publisher>
|
||||
<release-notes>
|
||||
<src lang="en" xlink:href="https://github.com/seanyeh/vibreoffice"/>
|
||||
</release-notes>
|
||||
</description>
|
|
@ -0,0 +1,35 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<helpdocument version="1.0">
|
||||
<meta>
|
||||
<topic id="vibreoffice.Pagexx">
|
||||
<title id="tit" xml-lang="en">Vibreoffice - Vi-Mode Extension : Write the title here</title>
|
||||
<filename>/vibreoffice/Pagexx.xhp</filename>
|
||||
</topic>
|
||||
</meta>
|
||||
<body>
|
||||
<paragraph role="heading" level="1" xml-lang="en" id="N0001">
|
||||
Write your own help pages from here
|
||||
</paragraph>
|
||||
<paragraph role="paragraph" xml-lang="en" id="N0002">
|
||||
Language en is the default value, you should have an english version of your help if your extension is internationally available.
|
||||
</paragraph>
|
||||
<paragraph role="paragraph" xml-lang="en" id="N0003">
|
||||
|
||||
</paragraph>
|
||||
<paragraph role="paragraph" xml-lang="en" id="N0004">
|
||||
|
||||
</paragraph>
|
||||
<paragraph role="paragraph" xml-lang="en" id="N0005">
|
||||
|
||||
</paragraph>
|
||||
<paragraph role="paragraph" xml-lang="en" id="N0006">
|
||||
|
||||
</paragraph>
|
||||
<paragraph role="paragraph" xml-lang="en" id="N0007">
|
||||
|
||||
</paragraph>
|
||||
<paragraph role="paragraph" xml-lang="en" id="N0008">
|
||||
|
||||
</paragraph>
|
||||
</body>
|
||||
</helpdocument>
|
|
@ -0,0 +1,3 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE library:library PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "library.dtd">
|
||||
<library:library xmlns:library="http://openoffice.org/2000/library" library:name="vibreoffice" library:readonly="false" library:passwordprotected="false"/>
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE library:library PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "library.dtd">
|
||||
<library:library xmlns:library="http://openoffice.org/2000/library" library:name="vibreoffice" library:readonly="false" library:passwordprotected="false">
|
||||
<library:element library:name="vibreoffice"/>
|
||||
</library:library>
|
|
@ -0,0 +1,422 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
|
||||
<script:module xmlns:script="http://openoffice.org/2000/script" script:name="vibreoffice" script:language="StarBasic">
|
||||
REM ***** BASIC *****
|
||||
Option Explicit
|
||||
|
||||
' --------
|
||||
' Globals
|
||||
' --------
|
||||
global VIBREOFFICE_STARTED as boolean ' Defaults to False
|
||||
global VIBREOFFICE_ENABLED as boolean ' Defaults to False
|
||||
|
||||
global oXKeyHandler as object
|
||||
|
||||
' Global State
|
||||
global MODE as string
|
||||
global VIEW_CURSOR as object
|
||||
global MULTIPLIER as integer
|
||||
|
||||
global isRunning as boolean
|
||||
|
||||
' -----------
|
||||
' Singletons
|
||||
' -----------
|
||||
Function getCursor
|
||||
getCursor = VIEW_CURSOR
|
||||
End Function
|
||||
|
||||
Function getTextCursor
|
||||
dim oTextCursor
|
||||
oTextCursor = getCursor().getText.createTextCursorByRange(getCursor())
|
||||
' oTextCursor.gotoRange(oTextCursor.getStart(), False)
|
||||
|
||||
getTextCursor = oTextCursor
|
||||
End Function
|
||||
|
||||
' -----------------
|
||||
' Helper Functions
|
||||
' -----------------
|
||||
Sub restoreStatus 'restore original statusbar
|
||||
dim oLayout
|
||||
oLayout = thisComponent.getCurrentController.getFrame.LayoutManager
|
||||
oLayout.destroyElement("private:resource/statusbar/statusbar")
|
||||
oLayout.createElement("private:resource/statusbar/statusbar")
|
||||
End Sub
|
||||
|
||||
Sub setRawStatus(rawText)
|
||||
thisComponent.Currentcontroller.StatusIndicator.Start(rawText, 0)
|
||||
End Sub
|
||||
|
||||
Sub setStatus(statusText)
|
||||
setRawStatus(MODE & " | " & statusText)
|
||||
End Sub
|
||||
|
||||
Sub setMode(modeName)
|
||||
MODE = modeName
|
||||
setRawStatus(modeName)
|
||||
End Sub
|
||||
|
||||
Function gotoMode(sMode)
|
||||
Select Case sMode
|
||||
Case "NORMAL":
|
||||
setMode("NORMAL")
|
||||
Case "INSERT":
|
||||
setMode("INSERT")
|
||||
Case "VISUAL":
|
||||
setMode("VISUAL")
|
||||
|
||||
dim oTextCursor
|
||||
oTextCursor = getTextCursor()
|
||||
' Deselect TextCursor
|
||||
oTextCursor.gotoRange(oTextCursor.getStart(), False)
|
||||
' Show TextCursor selection
|
||||
thisComponent.getCurrentController.Select(oTextCursor)
|
||||
End Select
|
||||
End Function
|
||||
|
||||
|
||||
' --------------------
|
||||
' Multiplier functions
|
||||
' --------------------
|
||||
Sub _setMultiplier(n as integer)
|
||||
MULTIPLIER = n
|
||||
End Sub
|
||||
|
||||
Sub resetMultiplier()
|
||||
_setMultiplier(0)
|
||||
End Sub
|
||||
|
||||
Sub addToMultiplier(n as integer)
|
||||
dim sMultiplierStr as String
|
||||
dim iMultiplierInt as integer
|
||||
|
||||
' Max multiplier: 10000 (stop accepting additions after 1000)
|
||||
If MULTIPLIER <= 1000 then
|
||||
sMultiplierStr = CStr(MULTIPLIER) & CStr(n)
|
||||
_setMultiplier(CInt(sMultiplierStr))
|
||||
End If
|
||||
End Sub
|
||||
|
||||
' Should only be used if you need the raw value
|
||||
Function getRawMultiplier()
|
||||
getRawMultiplier = MULTIPLIER
|
||||
End Function
|
||||
|
||||
' Same as getRawMultiplier, but defaults to 1 if it is unset (0)
|
||||
Function getMultiplier()
|
||||
If MULTIPLIER = 0 Then
|
||||
getMultiplier = 1
|
||||
Else
|
||||
getMultiplier = MULTIPLIER
|
||||
End If
|
||||
End Function
|
||||
|
||||
|
||||
' -------------
|
||||
' Key Handling
|
||||
' -------------
|
||||
sub sStartXKeyHandler
|
||||
sStopXKeyHandler()
|
||||
|
||||
oXKeyHandler = CreateUnoListener("KeyHandler_", "com.sun.star.awt.XKeyHandler")
|
||||
ThisComponent.CurrentController.AddKeyHandler(oXKeyHandler)
|
||||
end sub
|
||||
|
||||
sub sStopXKeyHandler
|
||||
ThisComponent.CurrentController.removeKeyHandler(oXKeyHandler)
|
||||
|
||||
'oXKeyHandler = Nothing 'To know later this handler has stopped.
|
||||
end sub
|
||||
|
||||
sub XKeyHandler_Disposing(oEvent)
|
||||
end sub
|
||||
|
||||
|
||||
' --------------------
|
||||
' Main Key Processing
|
||||
' --------------------
|
||||
function KeyHandler_KeyPressed(oEvent) as boolean
|
||||
' Exit if plugin is not enabled
|
||||
If IsMissing(VIBREOFFICE_ENABLED) Or Not VIBREOFFICE_ENABLED Then
|
||||
KeyHandler_KeyPressed = False
|
||||
Exit Function
|
||||
End If
|
||||
|
||||
dim bConsumeInput, bIsMultiplier, bIsModified, oTextCursor
|
||||
bConsumeInput = True ' Block all inputs by default
|
||||
bIsMultiplier = False ' reset multiplier by default
|
||||
bIsModified = oEvent.Modifiers > 1 ' If Ctrl or Alt is held down. (Shift=1)
|
||||
|
||||
' MsgBox(oEvent.KeyCode & "," & oEvent.KeyChar & "," & oEvent.KeyFunc & "," & oEvent.Modifiers)
|
||||
|
||||
' --------------------------
|
||||
' Process global shortcuts, exit if matched (like ESC)
|
||||
If ProcessGlobalKey(oEvent) Then
|
||||
' Pass
|
||||
|
||||
ElseIf MODE = "INSERT" Then
|
||||
bConsumeInput = False ' Allow all inputs
|
||||
|
||||
' If Change Mode
|
||||
ElseIf ProcessModeKey(oEvent) Then
|
||||
REM do nothing
|
||||
|
||||
ElseIf ProcessNumberKey(oEvent) Then
|
||||
bIsMultiplier = True
|
||||
|
||||
' Normal Key
|
||||
ElseIf Not ProcessNormalKey(oEvent) and bIsModified Then
|
||||
' If is modified but doesn't match a normal command, allow input
|
||||
' (Useful for built-in shortcuts like Ctrl+s, Ctrl+w)
|
||||
bConsumeInput = False
|
||||
End If
|
||||
' --------------------------
|
||||
|
||||
|
||||
' Reset multiplier
|
||||
If not bIsMultiplier Then resetMultiplier()
|
||||
setStatus(getMultiplier())
|
||||
|
||||
' Show terminal-like cursor
|
||||
oTextCursor = getTextCursor()
|
||||
If MODE = "NORMAL" Then
|
||||
oTextCursor.gotoRange(oTextCursor.getStart(), False)
|
||||
oTextCursor.goRight(1, False)
|
||||
oTextCursor.goLeft(1, True)
|
||||
thisComponent.getCurrentController.Select(oTextCursor)
|
||||
|
||||
ElseIf MODE = "INSERT" Then
|
||||
oTextCursor.gotoRange(oTextCursor.getStart(), False)
|
||||
thisComponent.getCurrentController.Select(oTextCursor)
|
||||
End If
|
||||
|
||||
KeyHandler_KeyPressed = bConsumeInput
|
||||
End Function
|
||||
|
||||
Function KeyHandler_KeyReleased(oEvent) As boolean
|
||||
KeyHandler_KeyReleased = (MODE = "NORMAL") 'cancel KeyReleased
|
||||
End Function
|
||||
|
||||
|
||||
' ----------------
|
||||
' Processing Keys
|
||||
' ----------------
|
||||
Function ProcessGlobalKey(oEvent)
|
||||
dim bMatched
|
||||
bMatched = True
|
||||
Select Case oEvent.KeyCode
|
||||
' PRESSED ESCAPE
|
||||
Case 1281:
|
||||
' Move cursor back if was in INSERT (but stay on same line)
|
||||
If MODE <> "NORMAL" And Not getCursor().isAtStartOfLine() Then
|
||||
getCursor().goLeft(1, False)
|
||||
End If
|
||||
|
||||
gotoMode("NORMAL")
|
||||
Case Else:
|
||||
bMatched = False
|
||||
End Select
|
||||
ProcessGlobalKey = bMatched
|
||||
End Function
|
||||
|
||||
|
||||
Function ProcessNumberKey(oEvent)
|
||||
dim c
|
||||
c = CStr(oEvent.KeyChar)
|
||||
|
||||
If c >= "0" and c <= "9" Then
|
||||
addToMultiplier(CInt(c))
|
||||
ProcessNumberKey = True
|
||||
Else
|
||||
ProcessNumberKey = False
|
||||
End If
|
||||
End Function
|
||||
|
||||
|
||||
Function ProcessModeKey(oEvent)
|
||||
dim bMatched
|
||||
bMatched = True
|
||||
Select Case oEvent.KeyChar
|
||||
' Insert modes
|
||||
Case "i", "a", "I", "A":
|
||||
If oEvent.KeyChar = "a" Then getCursor().goRight(1, False)
|
||||
If oEvent.KeyChar = "I" Then ProcessMovementKey("^")
|
||||
If oEvent.KeyChar = "A" Then ProcessMovementKey("$")
|
||||
|
||||
gotoMode("INSERT")
|
||||
Case "v":
|
||||
gotoMode("VISUAL")
|
||||
Case Else:
|
||||
bMatched = False
|
||||
End Select
|
||||
ProcessModeKey = bMatched
|
||||
End Function
|
||||
|
||||
|
||||
Function ProcessNormalKey(oEvent)
|
||||
dim i, bMatched, bIsVisual
|
||||
bMatched = False
|
||||
bIsVisual = (MODE = "VISUAL") ' is this hardcoding bad? what about visual block?
|
||||
For i = 1 To getMultiplier()
|
||||
dim bMatchedMovement, bMatchedDelete
|
||||
|
||||
bMatchedMovement = ProcessMovementKey(oEvent.KeyChar, bIsVisual, oEvent.Modifiers)
|
||||
bMatchedDelete = ProcessDeleteKey(oEvent)
|
||||
bMatched = bMatched or bMatchedMovement or bMatchedDelete
|
||||
|
||||
' Special case: Break from For loop if in visual mode and has deleted,
|
||||
' since multiplier should not be applied
|
||||
If bIsVisual and bMatchedDelete Then Exit For
|
||||
Next i
|
||||
|
||||
ProcessNormalKey = bMatched
|
||||
End Function
|
||||
|
||||
Function ProcessDeleteKey(oEvent)
|
||||
dim oTextCursor, bMatched
|
||||
oTextCursor = getTextCursor()
|
||||
bMatched = True
|
||||
Select Case oEvent.KeyChar
|
||||
' Case "d":
|
||||
' setSpecial("d")
|
||||
|
||||
Case "x":
|
||||
' oTextCursor.goRight(1, True)
|
||||
thisComponent.getCurrentController.Select(oTextCursor)
|
||||
'
|
||||
oTextCursor.setString("")
|
||||
Case Else:
|
||||
bMatched = False
|
||||
|
||||
End Select
|
||||
|
||||
ProcessDeleteKey = bMatched
|
||||
End Function
|
||||
|
||||
|
||||
' -----------------------
|
||||
' Main Movement Function
|
||||
' -----------------------
|
||||
' Default: bExpand = False, keyModifiers = 0
|
||||
Function ProcessMovementKey(keyChar, Optional bExpand, Optional keyModifiers)
|
||||
dim oTextCursor, bSetCursor, bMatched
|
||||
oTextCursor = getTextCursor()
|
||||
bMatched = True
|
||||
If IsMissing(bExpand) Then bExpand = False
|
||||
If IsMissing(keyModifiers) Then keyModifiers = 0
|
||||
|
||||
|
||||
' Check for modified keys (Ctrl, Alt, not Shift)
|
||||
If keyModifiers > 1 Then
|
||||
dim isControl
|
||||
isControl = (keyModifiers = 2) or (keyModifiers = 8)
|
||||
|
||||
' Ctrl+d and Ctrl+u
|
||||
If isControl and keyChar = "d" Then
|
||||
getCursor().ScreenDown(bExpand)
|
||||
ElseIf isControl and keyChar = "u" Then
|
||||
getCursor().ScreenUp(bExpand)
|
||||
Else
|
||||
bMatched = False
|
||||
End If
|
||||
|
||||
ProcessMovementKey = bMatched
|
||||
Exit Function
|
||||
End If
|
||||
|
||||
' Set global cursor to oTextCursor's new position if moved
|
||||
bSetCursor = True
|
||||
|
||||
Select Case keyChar
|
||||
Case "l":
|
||||
oTextCursor.goRight(1, bExpand)
|
||||
Case "h":
|
||||
oTextCursor.goLeft(1, bExpand)
|
||||
|
||||
' BEGIN HACK
|
||||
' oTextCursor.goUp and oTextCursor.goDown SHOULD work, but doesn't (I dont know why).
|
||||
' So this is a weird hack
|
||||
Case "k":
|
||||
'oTextCursor.goUp(1, False)
|
||||
getCursor().goUp(1, bExpand)
|
||||
bSetCursor = False
|
||||
Case "j":
|
||||
'oTextCursor.goDown(1, False)
|
||||
getCursor().goDown(1, bExpand)
|
||||
bSetCursor = False
|
||||
' END HACK
|
||||
|
||||
Case "^":
|
||||
getCursor().gotoStartOfLine(bExpand)
|
||||
bSetCursor = False
|
||||
Case "$":
|
||||
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
|
||||
|
||||
Case "w", "W":
|
||||
oTextCursor.gotoNextWord(bExpand)
|
||||
Case "b", "B":
|
||||
oTextCursor.gotoPreviousWord(bExpand)
|
||||
Case "e":
|
||||
oTextCursor.gotoEndOfWord(bExpand)
|
||||
|
||||
Case ")":
|
||||
oTextCursor.gotoNextSentence(bExpand)
|
||||
Case "(":
|
||||
oTextCursor.gotoPreviousSentence(bExpand)
|
||||
Case "}":
|
||||
oTextCursor.gotoNextParagraph(bExpand)
|
||||
Case "{":
|
||||
oTextCursor.gotoPreviousParagraph(bExpand)
|
||||
Case Else:
|
||||
bSetCursor = False
|
||||
bMatched = False
|
||||
End Select
|
||||
|
||||
' If oTextCursor was moved, set global cursor to its position
|
||||
If bSetCursor Then
|
||||
getCursor().gotoRange(oTextCursor.getStart(), False)
|
||||
End If
|
||||
|
||||
' If oTextCursor was moved and is in VISUAL mode, update selection
|
||||
if bSetCursor and bExpand then
|
||||
thisComponent.getCurrentController.Select(oTextCursor)
|
||||
end if
|
||||
|
||||
ProcessMovementKey = bMatched
|
||||
End Function
|
||||
|
||||
|
||||
Sub initVibreoffice
|
||||
' Initializing
|
||||
VIEW_CURSOR = thisComponent.getCurrentController.getViewCursor
|
||||
resetMultiplier()
|
||||
|
||||
gotoMode("NORMAL")
|
||||
|
||||
sStartXKeyHandler()
|
||||
End Sub
|
||||
|
||||
Sub Main
|
||||
If Not VIBREOFFICE_STARTED Then
|
||||
initVibreoffice()
|
||||
VIBREOFFICE_STARTED = True
|
||||
End If
|
||||
|
||||
' Toggle enable/disable
|
||||
VIBREOFFICE_ENABLED = Not VIBREOFFICE_ENABLED
|
||||
End Sub
|
||||
</script:module>
|
Loading…
Reference in New Issue