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
|
# vibreoffice
|
||||||
A Vi/Vim Mode Extension for Libreoffice and OpenOffice (Apache OpenOffice, OpenOffice.org)
|
|
||||||
|
|
||||||
### Installation
|
vibreoffice is an extension for Libreoffice and OpenOffice that brings some of
|
||||||
Coming soon.
|
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
|
### Features
|
||||||
|
|
||||||
vibreoffice currently supports:
|
vibreoffice currently supports:
|
||||||
- Insert (`i`, `I`, `a`, `A`, `o`, `O`), Visual (`v`), Normal modes
|
- Insert (`i`, `I`, `a`, `A`, `o`, `O`), Visual (`v`), Normal modes
|
||||||
- Movement keys: `hjkl`, `w`, `W`, `b`, `B`, `e`, `$`, `^`, `{}`, `()`, `C-d`, `C-u`
|
- 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`
|
- Deletion: `x`, `d`, `c`, `s`, `D`, `C`, `S`, `dd`, `cc`
|
||||||
- Plus movement and number modifiers: e.g. `5dw`, `c3j`, `2dfe`
|
- Plus movement and number modifiers: e.g. `5dw`, `c3j`, `2dfe`
|
||||||
- Delete a/inner block: e.g. `di(`, `da{`, `ci[`, `ci"`, `ca'`, `dit`
|
- 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
|
### License
|
||||||
vibreoffice is released under the MIT 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