duyanning avatar duyanning committed 435f8a2

use hg in the same directory as svn.

Comments (0)

Files changed (46)

+publish
+.svn
+For more information see:  http://womacs.sf.net
+
+womacs\
+        womacs-dev.docm         used to develop VBA project, DO NOT open this document directly, use develop.bat to open it.
+        install.bat             copy publish\womacs.dotm to Word\STARTUP
+        uninstall.bat           remove womacs.dotm from Word\STARTUP
+        develop.bat             open womacs.docm for developing
+        ReadMe.txt              this file
+        develop_src\            VBA code exported from womacs-dev.docm
+        publish\                staff generated to publish
+                src\            VBA code to be embodied in womacs.dotm
+                womacs.dotm     the resulting word template to publish
+
+
+Note: womacs-dev.docm (for developing) and womacs.dotm (to publish)
+have different filename extension. If womacs-dev.docm does NOT exist,
+create it and import file develop_src\DeveloperTools.bas. Run marco
+import_vba_source_code_to_this_project to import all sources from
+develop_src. If you get an error says "user-defined type not defined"
+when executing import, add a reference to Microsoft Visual Basic For
+Applications Extensibility 5.3. See also:
+http://www.cpearson.com/excel/vbe.aspx
+call uninstall.bat
+womacs-dev.docm
+call install.bat
+

develop_src/Boxing.bas

+Attribute VB_Name = "Boxing"
+Option Explicit
+
+
+Public Function BoxInteger(ByVal X As Integer) As CInteger
+    Dim i As New CInteger
+    i = X
+    Set BoxInteger = i
+End Function
+
+Public Function BoxString(ByVal X As String) As CString
+    Dim s As New CString
+    s = X
+    Set BoxString = s
+End Function
+
+

develop_src/CArray.cls

+VERSION 1.0 CLASS
+BEGIN
+  MultiUse = -1  'True
+END
+Attribute VB_Name = "CArray"
+Attribute VB_GlobalNameSpace = False
+Attribute VB_Creatable = False
+Attribute VB_PredeclaredId = False
+Attribute VB_Exposed = False
+Option Explicit
+

develop_src/CArrayList.cls

+VERSION 1.0 CLASS
+BEGIN
+  MultiUse = -1  'True
+END
+Attribute VB_Name = "CArrayList"
+Attribute VB_GlobalNameSpace = False
+Attribute VB_Creatable = False
+Attribute VB_PredeclaredId = False
+Attribute VB_Exposed = False
+' womacs
+Option Explicit
+
+Implements ICloneable
+Implements IList
+Implements ICollection
+
+Private m_data() As Object
+Private m_count As Integer
+Private m_capacity As Integer
+
+Public Property Get Capacity() As Integer
+    Let Capacity = m_capacity
+End Property
+
+Public Property Let Capacity(ByVal newcapacity As Integer)
+    If newcapacity = 0 Then newcapacity = 16
+    m_capacity = newcapacity
+    ReDim Preserve m_data(m_capacity - 1)
+End Property
+
+Public Property Get Count() As Integer
+    Let Count = actual_Count
+End Property
+
+Public Sub Clear()
+    actual_Clear
+End Sub
+
+Public Function Add(ByVal Value As Object) As Integer
+    Let Add = actual_Add(Value)
+End Function
+
+Public Property Get item(ByVal index As Integer) As Object
+Attribute item.VB_UserMemId = 0
+    Set item = actual_item(index)
+End Property
+
+Public Function NewEnum() As IUnknown
+   Set NewEnum = m_data.[_NewEnum]
+End Function
+
+Public Function Equals(Object) As Boolean
+
+End Function
+
+Private Sub actual_Insert(ByVal index As Integer, ByVal Value As Object)
+    If index < 0 Or index > m_count Then Debug.Assert False
+    
+    ' if it is inserted at end, call Add to do
+    If index = m_count Then
+        Add (Value)
+        Exit Sub
+    End If
+    
+    ' if there is no enough space
+    If m_count = m_capacity Then
+        m_capacity = m_capacity * 2
+        ReDim Preserve m_data(m_capacity - 1)
+    End If
+    
+    ' each elem from end to insertion point is moved in turn
+    Dim i As Integer
+    For i = m_count - 1 To index Step -1
+        Set m_data(i + 1) = m_data(i)
+    Next
+    
+    ' place new elem at insertion point
+    Set m_data(index) = Value
+    
+    Let m_count = m_count + 1
+End Sub
+
+Public Sub Insert(ByVal index As Integer, ByVal Value As Object)
+    actual_Insert index, Value
+End Sub
+
+Public Sub RemoveAt(ByVal index As Integer)
+    IList_RemoveAt (index)
+End Sub
+
+Public Sub TrimToSize()
+    Let m_capacity = m_count + 1
+    ReDim m_data(m_capacity - 1)
+End Sub
+
+Private Sub Class_Initialize()
+    Let m_capacity = 16
+    ReDim m_data(m_capacity - 1)
+    Let m_count = 0
+End Sub
+
+Private Function actual_Count() As Integer
+    Let actual_Count = m_count
+End Function
+
+Private Property Get ICollection_Count() As Integer
+    Let ICollection_Count = actual_Count
+End Property
+
+Private Function actual_Add(ByVal Value As Object) As Integer
+    If m_count = m_capacity Then
+        m_capacity = 2 * m_capacity
+        ReDim Preserve m_data(m_capacity - 1)
+    End If
+    
+    Set m_data(m_count) = Value
+    Let m_count = m_count + 1
+End Function
+
+Private Function IList_Add(ByVal Value As Object) As Integer
+    actual_Add Value
+End Function
+
+Private Function actual_Clone() As Object
+    Dim al As New CArrayList
+
+    Dim i As Integer
+    For i = 0 To m_count - 1
+        al.Add m_data(i)
+    Next
+
+    Set actual_Clone = al
+End Function
+
+Public Function Clone() As Object
+    Set Clone = actual_Clone
+End Function
+
+Private Function ICloneable_Clone() As Object
+    Set ICloneable_Clone = actual_Clone
+End Function
+
+Private Sub actual_Clear()
+    Dim o As Variant
+    For Each o In m_data
+        Set o = Nothing
+    Next
+    Let m_count = 0
+End Sub
+
+Private Sub IList_Clear()
+    actual_Clear
+End Sub
+
+Private Function actual_Contains(ByVal item As Object) As Boolean
+    If m_count = 0 Then
+        Let Contains = False
+        Exit Function
+    End If
+    
+    Dim i As Integer
+    For i = 0 To m_count - 1
+        If m_data(i) = obj Then
+            Contains = True
+            Exit Function
+        End If
+    Next
+        
+    Let Contains = False
+End Function
+
+Private Function IList_Contains(ByVal item As Object) As Boolean
+    actual_Contains
+End Function
+
+Private Function actual_item(ByVal index As Integer) As Object
+    If index < 0 Or index >= m_count Then Debug.Assert False
+    Set actual_item = m_data(index)
+End Function
+
+Private Property Get IList_Count() As Integer
+    IList_Count = actual_Count
+End Property
+
+Private Sub IList_Insert(ByVal index As Integer, ByVal Value As Object)
+    actual_Insert index, Value
+End Sub
+
+Private Property Get IList_item(ByVal index As Integer) As Object
+    Set IList_item = actual_item(index)
+End Property
+
+Private Sub actual_Remove(ByVal obj As Object)
+    If m_count = 0 Then Debug.Assert False
+    
+    Dim i As Integer
+    For i = 0 To m_count - 1
+        If m_data(i) = obj Then Exit For
+    Next
+    
+    If Not i = m_count Then RemoveAt (i)
+End Sub
+
+Private Sub IList_Remove(ByVal obj As Object)
+    actual_Remove obj
+End Sub
+
+Private Sub actual_RemoveAt(ByVal index As Integer)
+    If index < 0 Or index >= m_count Then Exit Sub
+    If index = m_count - 1 Then
+        Set m_data(m_count - 1) = Nothing
+        m_count = m_count - 1
+        Exit Sub
+    End If
+    
+    Dim i As Integer
+    For i = index To m_count - 2
+        Set m_data(i) = m_data(i + 1)
+    Next
+    
+    Let m_count = m_count - 1
+End Sub
+
+Private Sub IList_RemoveAt(ByVal index As Integer)
+    actual_RemoveAt index
+End Sub

develop_src/CInteger.cls

+VERSION 1.0 CLASS
+BEGIN
+  MultiUse = -1  'True
+END
+Attribute VB_Name = "CInteger"
+Attribute VB_GlobalNameSpace = False
+Attribute VB_Creatable = False
+Attribute VB_PredeclaredId = False
+Attribute VB_Exposed = False
+Option Explicit
+
+Private X As Integer
+
+Public Property Get Value() As Integer
+Attribute Value.VB_UserMemId = 0
+    Value = X
+End Property
+
+Public Property Let Value(ByVal vNewValue As Integer)
+    X = vNewValue
+End Property

develop_src/CQueue.cls

+VERSION 1.0 CLASS
+BEGIN
+  MultiUse = -1  'True
+END
+Attribute VB_Name = "CQueue"
+Attribute VB_GlobalNameSpace = False
+Attribute VB_Creatable = False
+Attribute VB_PredeclaredId = False
+Attribute VB_Exposed = False
+Option Explicit
+
+Private al As CArrayList
+
+Public Property Get Count() As Integer
+    Count = al.Count
+End Property

develop_src/CStack.cls

+VERSION 1.0 CLASS
+BEGIN
+  MultiUse = -1  'True
+END
+Attribute VB_Name = "CStack"
+Attribute VB_GlobalNameSpace = False
+Attribute VB_Creatable = False
+Attribute VB_PredeclaredId = False
+Attribute VB_Exposed = False
+Option Explicit
+
+Implements ICollection
+Implements ICloneable
+
+Private al As CArrayList
+
+Public Property Get Count() As Integer
+    Let Count = al.Count
+End Property
+
+Public Sub push(ByVal obj As Object)
+    al.Add obj
+End Sub
+
+Public Function pop() As Object
+    Dim top As Object
+    Set top = al(al.Count - 1)
+    al.RemoveAt (al.Count - 1)
+    Set pop = top
+End Function
+
+Public Sub Clear()
+    al.Clear
+End Sub
+
+Public Function Peek() As Object
+    Set Peek = al(al.Count - 1)
+End Function
+
+Private Sub Class_Initialize()
+    Set al = New CArrayList
+End Sub
+
+
+Private Function ICloneable_Clone() As Object
+    Set ICloneable_Clone = al.Clone
+End Function
+
+Private Property Get ICollection_Count() As Integer
+    ICollection_Count = al.Count
+End Property

develop_src/CString.cls

+VERSION 1.0 CLASS
+BEGIN
+  MultiUse = -1  'True
+END
+Attribute VB_Name = "CString"
+Attribute VB_GlobalNameSpace = False
+Attribute VB_Creatable = False
+Attribute VB_PredeclaredId = False
+Attribute VB_Exposed = False
+Option Explicit
+
+Private str As String
+
+Public Property Get Value() As String
+Attribute Value.VB_UserMemId = 0
+    Value = str
+End Property
+
+Public Property Let Value(ByVal vNewValue As String)
+    str = vNewValue
+End Property

develop_src/DeveloperTools.bas

+Attribute VB_Name = "DeveloperTools"
+Option Explicit
+Option Private Module
+
+' for developers of womacs.dotm's use only
+
+' note:
+' path = dirname/basename
+
+
+Private Sub export_vba_source_code_from_this_project()
+    Dim src_dirname As String
+    
+    src_dirname = ThisDocument.Path & Application.PathSeparator & "develop_src"
+    
+    If Dir(src_dirname, vbDirectory) = "" Then
+        MsgBox src_dirname & " must exist before exporting!"
+        Exit Sub
+    End If
+
+    Dim c As VBComponent
+    
+    For Each c In ThisDocument.VBProject.VBComponents
+        export_vba_source_code c, src_dirname
+    Next c
+
+End Sub
+
+'---------------------------------------------------------------------------------------------------------------
+' dangerous !!!!! all changes unsaved will lost.
+Private Sub import_vba_source_code_to_this_project()
+
+    Dim answer As Integer
+    Dim c As VBComponent
+    Dim src_dirname As String
+    
+    Debug.Print ThisDocument.name
+    Debug.Assert (ThisDocument.name = "womacs-dev.docm")
+    
+    answer = MsgBox("are you sure?", vbOKCancel)
+    If answer = vbCancel Then
+        Exit Sub
+    End If
+    
+    For Each c In ThisDocument.VBProject.VBComponents
+        Debug.Print c.name
+        
+        If c.name <> "ThisDocument" And c.name <> "DeveloperTools" Then
+            ThisDocument.VBProject.VBComponents.Remove c
+        End If
+        
+    Next c
+    
+    
+    src_dirname = ThisDocument.Path & Application.PathSeparator & "develop_src"
+    
+    If Dir(src_dirname, vbDirectory) = "" Then
+        MsgBox src_dirname & " must exist before exporting!"
+        Exit Sub
+    End If
+
+    import_vba_source_code ThisDocument, src_dirname
+    
+End Sub
+'-------------------------------------------------------------------------------------------------------------------
+
+' note:
+' to substitute $WCREV$ with correct number, we MUST commit first, then call this sub
+Private Sub generate_template_for_publishing()
+    Dim publish_dirname As String
+    Dim publish_src_dirname As String
+    
+    publish_dirname = ThisDocument.Path & Application.PathSeparator & "publish"
+    publish_src_dirname = publish_dirname & Application.PathSeparator & "src"
+
+    
+    If Dir(publish_dirname, vbDirectory) = "" Then
+        MkDir publish_dirname
+    End If
+    
+    If Dir(publish_src_dirname, vbDirectory) = "" Then
+        MkDir publish_src_dirname
+    End If
+    
+    Dim Doc As Document
+    'Set doc = Documents.Add(NewTemplate:=True)
+    Set Doc = Documents.Add
+    ', Visible:=False)
+    
+    
+    
+    ' export
+    Dim c_develop As VBComponent
+    
+    Dim tag_womacs As String
+    tag_womacs = "' womacs"
+    
+    Dim tag_handy_tools As String
+    tag_handy_tools = "' handy tools"
+    
+    
+    For Each c_develop In ThisDocument.VBProject.VBComponents
+        Dim first_line As String
+        
+        first_line = c_develop.CodeModule.Lines(1, 1)
+        
+        If first_line = tag_womacs Or first_line = tag_handy_tools Then
+            export_vba_source_code c_develop, publish_src_dirname
+        End If
+    Next c_develop
+    
+    
+    ' pause to avoid bug with vba
+    MsgBox "Exporting source code"
+ 
+ 
+    
+    ' use SubWCRev.exe from TortoiseSVN to substitute $WCREV$ in Version.bas
+    ' shell is NOT asynchronous, see also http://support.microsoft.com/kb/129796
+    Dim wc_dirname As String
+    wc_dirname = ThisDocument.Path & Application.PathSeparator & "develop_src"
+    
+    Dim version_file_path As String
+    version_file_path = publish_src_dirname & Application.PathSeparator & "Version.bas"
+    
+    Dim cmd_line_to_subwcrev As String
+    cmd_line_to_subwcrev = "subwcrev " & wc_dirname & " " & version_file_path & " " & version_file_path
+    Debug.Print cmd_line_to_subwcrev
+    
+    ' womacs has been changed from sourceforge(svn) to bitbucket(hg)
+    Shell cmd_line_to_subwcrev, 1
+    
+    ' pause to wait for subwcrev.exe to exit
+    MsgBox "Please wait for subwcrev.exe to exit"
+    
+    
+    ' import
+    import_vba_source_code Doc, publish_src_dirname
+    MsgBox "Importing source code to womacs.dotm"
+    
+    
+    ' save
+    Dim publish_basename As String
+    publish_basename = "womacs.dotm"
+    
+    Dim publish_path As String
+    publish_path = publish_dirname & Application.PathSeparator & publish_basename
+
+
+    If Dir(publish_path) <> "" Then
+        Kill publish_path
+        ' pause to avoid bug with vba
+        MsgBox "Deleting old womacs.dotm"
+    End If
+
+    
+    Doc.SaveAs2 FileName:=publish_path, FileFormat:=wdFormatXMLTemplateMacroEnabled
+    'wdFormatTemplate dot
+    
+    MsgBox "Saving new womacs.dotm"
+    Doc.Close
+        
+
+    MsgBox "Finished"
+    
+End Sub
+
+'-------------------------------------------------------------------------------------------------------------------
+Sub show_all_key_bindings_in_current_doc()
+    Dim kbLoop As KeyBinding
+  
+    CustomizationContext = ThisDocument
+    For Each kbLoop In KeyBindings
+        Selection.InsertAfter kbLoop.command & vbTab _
+            & kbLoop.KeyString & vbCr
+        Selection.Collapse direction:=wdCollapseEnd
+    Next kbLoop
+End Sub
+
+'===================================================================================================================
+
+Private Sub export_vba_source_code(c As VBComponent, src_dirname As String)
+    Dim suffix As String
+    'Debug.Print c.Name, c.CodeModule.Name, c.CodeModule.CountOfLines
+    
+    Select Case c.type
+    Case vbext_ct_ClassModule
+        suffix = ".cls"
+    Case vbext_ct_MSForm
+        suffix = ".frm"
+    Case vbext_ct_StdModule
+        suffix = ".bas"
+    Case Else
+        suffix = ""
+    End Select
+    
+    If suffix <> "" Then
+        Dim src_abspath
+        
+        src_abspath = src_dirname & Application.PathSeparator & c.name & suffix
+            
+        Debug.Print src_abspath
+        
+        c.Export src_abspath
+    
+    End If
+
+End Sub
+
+
+Private Sub import_vba_source_code(Doc As Document, src_dirname As String)
+    Dim src_basename As String
+    Dim src_abspath As String
+    
+    src_basename = Dir(src_dirname & Application.PathSeparator & "*")
+    Do
+        If src_basename = "" Then
+            Exit Do
+        End If
+        
+        If src_basename <> "DeveloperTools.bas" And InStr(src_basename, ".frx") = 0 Then
+            src_abspath = src_dirname & Application.PathSeparator & src_basename
+            
+            Debug.Print src_abspath
+            Doc.VBProject.VBComponents.Import src_abspath
+        End If
+        
+        src_basename = Dir
+        
+    Loop
+
+End Sub
+

develop_src/DocString.bas

+Attribute VB_Name = "DocString"
+' womacs
+Option Explicit
+
+Public doc_string As String
+
+Sub reset_doc_string()
+    doc_string = "sorry, no information is provided!"
+End Sub

develop_src/EmacsLikeCommands.bas

+Attribute VB_Name = "EmacsLikeCommands"
+' womacs
+
+Option Explicit
+
+
+Public is_desc_key As Boolean
+Public statusbar_prefix As String
+
+Public search_fwd As Boolean
+
+' doc local
+Public womacs_on As Boolean
+Public mark_set As Boolean     ' has mark been set?
+Public mark_pos As Long        ' position of the mark
+
+
+
+
+Public num_arg As Integer  ' numeric argument
+'    While num_arg < 0
+'        do_a()
+'
+'        num_arg = num_arg + 1
+'    Wend
+'
+'    While num_arg > 0
+'        do_b()
+'
+'        num_arg = num_arg - 1
+'    Wend
+'    num_arg = 1  ' reset num_arg to 1
+
+Dim action_record_balance As Integer    ' for debug
+
+'Public kill_whole_line As Boolean
+Public delete_word As Boolean
+
+
+Sub store_doc_locals(ByVal Doc As Document)
+    push_saved_state Doc
+    
+    Doc.Variables("womacs_on") = CStr(womacs_on)
+    Doc.Variables("mark_set") = CStr(mark_set)
+    Doc.Variables("mark_pos") = CStr(mark_pos)
+    
+    pop_saved_state Doc
+End Sub
+
+
+Sub load_doc_locals(ByVal Doc As Document)
+    womacs_on = False
+    mark_set = False
+    mark_pos = -1
+
+    On Error Resume Next
+    womacs_on = CBool(Doc.Variables("womacs_on"))
+    mark_set = CBool(Doc.Variables("mark_set"))
+    mark_pos = CLng(Doc.Variables("mark_pos"))
+End Sub
+
+
+Sub delete_all_womacs_vars(ByVal Doc As Document)
+    push_saved_state Doc
+    
+    On Error Resume Next
+
+    Doc.Variables("womacs_on").Delete
+    Doc.Variables("mark_set").Delete
+    Doc.Variables("mark_pos").Delete
+    
+    pop_saved_state Doc
+
+End Sub
+
+
+Sub begin_action(name As String)
+    ' need word 2010
+    If StrComp(Application.version, "14.0") = -1 Then
+        Exit Sub
+    End If
+    
+    Debug.Assert action_record_balance = 0
+    action_record_balance = action_record_balance + 1
+    Application.UndoRecord.StartCustomRecord "Undo " & name
+End Sub
+
+
+Sub end_action()
+    ' need word 2010
+    If StrComp(Application.version, "14.0") = -1 Then
+        Exit Sub
+    End If
+    
+    Debug.Assert action_record_balance = 1
+    action_record_balance = action_record_balance - 1
+    Application.UndoRecord.EndCustomRecord
+End Sub
+
+
+Sub doc_of_set_mark_command()
+    doc_string = "Set the mark where point is."
+End Sub
+Sub set_mark_command()
+'C-SPC
+
+    Dim old_mark_pos As Long
+
+    If mark_set Then
+        select_nothing
+        ' if point has not been moved since mark is set, then cancel the mark
+        If mark_pos = Selection.Start Then
+            mark_set = False
+            Application.StatusBar = "Mark deactivated"
+            Exit Sub
+        End If
+    End If
+
+    old_mark_pos = mark_pos
+
+    mark_set = True
+    mark_pos = Selection.Start
+    'Debug.Print mark_pos
+
+    If mark_pos = old_mark_pos Then
+        Application.StatusBar = "Mark activated"
+    Else
+        Application.StatusBar = "Mark set"
+    End If
+
+
+    complete
+End Sub
+
+
+Sub select_nothing()
+    ' if there is no highlight
+    If Selection.type = wdSelectionIP Then
+        Exit Sub
+    End If
+
+    ' move cursor to make highlight disapper
+'    If mark_pos <= Selection.Start Then
+'        Selection.Collapse Direction:=wdCollapseEnd
+'    Else
+'        Selection.Collapse Direction:=wdCollapseStart
+'    End If
+    
+    If Selection.StartIsActive Then
+        Selection.Collapse direction:=wdCollapseStart
+    Else
+        Selection.Collapse direction:=wdCollapseEnd
+    End If
+    
+
+End Sub
+
+
+Sub doc_of_keyboard_quit()
+    doc_string = "Signal a `quit' condiction."
+End Sub
+Sub keyboard_quit()
+'C-g
+    Application.StatusBar = "Quit"
+
+    mark_set = False
+    select_nothing
+    
+    complete
+    
+    'restore to the global_keymap
+    Set current_keymap = global_keymap
+    global_keymap.bind ActiveDocument
+    
+    'restore the IME status
+    ImeRestoreStatus
+
+End Sub
+
+
+Sub doc_of_kill_line()
+    doc_string = "Move point right one character."
+End Sub
+Sub kill_line()
+'C-k
+
+    mark_set = False
+    select_nothing
+    
+    ' move to the end of line
+    Selection.EndKey Unit:=wdLine, Extend:=wdExtend
+
+    If Selection.type <> wdSelectionIP _
+            And Asc(Selection.Characters.Last.Text) = 13 _
+            And Asc(Selection.Characters.First.Text) <> 13 Then
+        Selection.MoveLeft Unit:=wdCharacter, Count:=1, Extend:=wdExtend
+    End If
+    
+
+    'Selection.StartIsActive = Not Selection.StartIsActive
+    
+    If Selection.type <> wdSelectionIP Then
+        Selection.Cut
+    End If
+
+
+    complete
+End Sub
+
+
+Sub doc_of_kill_region()
+    doc_string = "Kill (""cut"") text between point and mark."
+End Sub
+Sub kill_region()
+'C-w
+    On Error Resume Next
+    'Selection.Cut
+    Application.Run macroname:="EditCut"
+    
+    mark_set = False
+
+    complete
+End Sub
+
+
+Sub doc_of_delete_region()
+    doc_string = "Delete the text between point and mark."
+End Sub
+Sub delete_region()
+'C-c w
+    On Error Resume Next
+    Selection.Delete Unit:=wdCharacter, Count:=1
+    
+    mark_set = False
+
+    complete
+End Sub
+
+
+'    While num_arg < 0
+'        do_a()
+'
+'        num_arg = num_arg + 1
+'    Wend
+'
+'    While num_arg > 0
+'        do_b()
+'
+'        num_arg = num_arg - 1
+'    Wend
+Sub doc_of_kill_word()
+    doc_string = "Kill a word forward, skipping over intervening delimiters."
+End Sub
+Sub kill_word()
+'M-d
+    On Error Resume Next
+
+    mark_set = False
+    select_nothing
+    
+    begin_action "kill word"
+    
+    If delete_word Then
+        While num_arg > 0
+            Application.Run macroname:="DeleteWord"
+            num_arg = num_arg - 1
+        Wend
+    Else
+        Selection.MoveRight Unit:=wdWord, Count:=num_arg, Extend:=wdExtend
+        Selection.StartIsActive = Not Selection.StartIsActive   ' when select_nothing in undo, move point to a correct position
+        Selection.Cut
+    End If
+    
+    end_action
+    
+    complete
+End Sub
+
+
+Sub doc_of_backward_kill_word()
+    doc_string = "Kill characters backward until encountering the beginning of a word."
+End Sub
+Sub backward_kill_word()
+'M-backspace
+    begin_action "backward kill word"
+    
+    If delete_word Then
+        While num_arg > 0
+            Application.Run macroname:="DeleteBackWord"
+            num_arg = num_arg - 1
+        Wend
+    Else
+        Selection.MoveLeft Unit:=wdWord, Count:=num_arg, Extend:=wdExtend
+        Selection.StartIsActive = Not Selection.StartIsActive
+        Selection.Cut
+    End If
+    
+    end_action
+    
+    complete
+    
+End Sub
+
+
+Sub doc_of_kill_ring_save()
+    doc_string = "Copy"
+End Sub
+Sub kill_ring_save()
+'M-w
+    On Error Resume Next
+    'Selection.Copy
+    Application.Run macroname:="EditCopy"
+
+    select_nothing
+    mark_set = False
+
+
+    complete
+End Sub
+
+
+Sub doc_of_yank()
+    doc_string = "Paste"
+End Sub
+Sub yank()
+'C-y
+    mark_set = False
+    select_nothing
+    
+    'Selection.PasteAndFormat (wdFormatPlainText)
+    'Selection.PasteAndFormat (wdFormatOriginalFormatting)
+    Application.Run macroname:="EditPaste"
+
+    complete
+End Sub
+
+
+Sub doc_of_delete_char()
+    doc_string = "Delete the following one character."
+End Sub
+Sub delete_char()
+'C-d
+    mark_set = False
+    select_nothing
+    
+    Selection.Delete Unit:=wdCharacter, Count:=num_arg
+
+    complete
+End Sub
+
+
+Sub doc_of_upcase_word()
+    doc_string = "Convert following word to upper case, moving over."
+End Sub
+Sub upcase_word()
+'M-u
+    select_nothing
+    mark_set = False
+
+    begin_action "upcase word"
+    
+    If num_arg < 0 Then
+        Dim point_pos As Long
+        point_pos = Selection.Start
+        Selection.MoveLeft Unit:=wdWord, Count:=-num_arg
+
+        While Selection.Start < point_pos
+            Selection.Range.Case = wdUpperCase
+            Selection.MoveRight Unit:=wdWord, Count:=1
+        Wend
+
+
+    End If
+
+    While num_arg > 0
+        Selection.Range.Case = wdUpperCase
+        Selection.MoveRight Unit:=wdWord, Count:=1
+
+        num_arg = num_arg - 1
+    Wend
+    
+    end_action
+
+    complete
+End Sub
+
+
+Sub doc_of_downcase_word()
+    doc_string = "Convert following word to lower case, moving over."
+End Sub
+Sub downcase_word()
+'M-l
+
+    select_nothing
+    mark_set = False
+    
+    begin_action "downcase word"
+
+    If num_arg < 0 Then
+        Dim point_pos As Long
+        point_pos = Selection.Start
+        Selection.MoveLeft Unit:=wdWord, Count:=-num_arg
+
+        While Selection.Start < point_pos
+            Selection.Range.Case = wdLowerCase
+            Selection.MoveRight Unit:=wdWord, Count:=1
+        Wend
+
+
+    End If
+
+    While num_arg > 0
+        Selection.Range.Case = wdLowerCase
+        Selection.MoveRight Unit:=wdWord, Count:=1
+
+        num_arg = num_arg - 1
+    Wend
+
+    end_action
+    
+    complete
+End Sub
+
+
+Sub doc_of_capitalize_word()
+    doc_string = "Capitalize the following word (or ARG words), moving over."
+End Sub
+Sub capitalize_word()
+'M-c
+    select_nothing
+    mark_set = False
+    
+    begin_action "capitalize word"
+
+    If num_arg < 0 Then
+        Dim point_pos As Long
+        point_pos = Selection.Start
+        Selection.MoveLeft Unit:=wdWord, Count:=-num_arg
+
+        While Selection.Start < point_pos
+            Selection.Range.Case = wdTitleWord
+            Selection.MoveRight Unit:=wdWord, Count:=1
+        Wend
+
+
+    End If
+
+    While num_arg > 0
+        Selection.Range.Case = wdTitleWord
+        Selection.MoveRight Unit:=wdWord, Count:=1
+
+        num_arg = num_arg - 1
+    Wend
+
+    end_action
+    
+    complete
+End Sub
+
+
+Sub doc_of_newline()
+    doc_string = "Insert a newline."
+End Sub
+Sub newline()
+'C-m
+    select_nothing
+    mark_set = False
+    
+    begin_action "newline"
+
+    While num_arg > 0
+        Selection.TypeParagraph
+
+        num_arg = num_arg - 1
+    Wend
+
+    end_action
+    complete
+End Sub
+
+
+Sub doc_of_open_line()
+    doc_string = "Insert a newline and leave point before it."
+End Sub
+Sub open_line()
+'C-o
+    select_nothing
+    mark_set = False
+    
+    begin_action ("open line")
+
+    Dim i As Integer
+    For i = 1 To num_arg
+        Selection.TypeParagraph
+    Next i
+    
+    Selection.MoveLeft Unit:=wdCharacter, Count:=num_arg
+    
+    end_action
+
+    complete
+
+End Sub
+
+
+Sub doc_of_forward_word()
+    doc_string = "Move point forward one word."
+End Sub
+Sub forward_word()
+'M-f
+    If mark_set Then
+        Selection.MoveRight Unit:=wdWord, Count:=num_arg, Extend:=wdExtend
+    Else
+        Selection.MoveRight Unit:=wdWord, Count:=num_arg, Extend:=wdMove
+    End If
+
+    complete
+End Sub
+
+
+Sub doc_of_backward_word()
+    doc_string = "Move backward until encountering the beginning of a word."
+End Sub
+Sub backward_word()
+'M-b
+    If mark_set Then
+        Selection.MoveLeft Unit:=wdWord, Count:=num_arg, Extend:=wdExtend
+    Else
+        Selection.MoveLeft Unit:=wdWord, Count:=num_arg, Extend:=wdMove
+    End If
+
+    complete
+End Sub
+
+
+Sub doc_of_forward_char()
+    doc_string = "Move point right one character."
+End Sub
+Sub forward_char()
+'C-f
+    If mark_set Then
+        Selection.MoveRight Unit:=wdCharacter, Count:=num_arg, Extend:=wdExtend
+    Else
+        Selection.MoveRight Unit:=wdCharacter, Count:=num_arg, Extend:=wdMove
+    End If
+    
+    complete
+End Sub
+
+
+Sub doc_of_backward_char()
+    doc_string = "Move point left one character."
+End Sub
+Sub backward_char()
+'C-b
+    If mark_set Then
+        Selection.MoveLeft Unit:=wdCharacter, Count:=num_arg, Extend:=wdExtend
+    Else
+        Selection.MoveLeft Unit:=wdCharacter, Count:=num_arg, Extend:=wdMove
+    End If
+
+    complete
+End Sub
+
+
+Sub doc_of_previous_line()
+    doc_string = "Move cursor vertically up one line."
+End Sub
+Sub previous_line()
+'C-p
+    If mark_set Then
+        Selection.MoveUp Unit:=wdLine, Count:=num_arg, Extend:=wdExtend
+    Else
+        Selection.MoveUp Unit:=wdLine, Count:=num_arg, Extend:=wdMove
+    End If
+
+    complete
+End Sub
+
+
+Sub doc_of_next_line()
+    doc_string = "Move cursor vertically down one line."
+End Sub
+Sub next_line()
+'C-n
+    If mark_set Then
+        Selection.MoveDown Unit:=wdLine, Count:=num_arg, Extend:=wdExtend
+    Else
+        Selection.MoveDown Unit:=wdLine, Count:=num_arg, Extend:=wdMove
+    End If
+
+    complete
+End Sub
+
+
+' yet not support C-u
+Sub doc_of_move_beginning_of_line()
+    doc_string = "Move point to beginning of current line."
+End Sub
+Sub move_beginning_of_line()
+'C-a
+    If mark_set Then
+        Selection.HomeKey Unit:=wdLine, Extend:=wdExtend
+    Else
+        Selection.HomeKey Unit:=wdLine, Extend:=wdMove
+    End If
+
+    complete
+End Sub
+
+
+' yet not support C-u
+Sub doc_of_move_end_of_line()
+    doc_string = "Move point to end of current line."
+End Sub
+Sub move_end_of_line()
+'C-e
+    If mark_set Then
+        Selection.EndKey Unit:=wdLine, Extend:=wdExtend
+    Else
+        Selection.EndKey Unit:=wdLine, Extend:=wdMove
+    End If
+
+    complete
+End Sub
+
+
+Sub doc_of_backward_sentence()
+    doc_string = "Move backward to start of sentence."
+End Sub
+Sub backward_sentence()
+'M-a
+    If mark_set Then
+        Selection.MoveLeft Unit:=wdSentence, Count:=num_arg, Extend:=wdExtend
+    Else
+        Selection.MoveLeft Unit:=wdSentence, Count:=num_arg, Extend:=wdMove
+    End If
+    
+    complete
+End Sub
+
+
+Sub doc_of_forward_sentence()
+    doc_string = "Move forward to next end of sentence."
+End Sub
+Sub forward_sentence()
+'M-e
+    If mark_set Then
+        Selection.MoveRight Unit:=wdSentence, Count:=num_arg, Extend:=wdExtend
+    Else
+        Selection.MoveRight Unit:=wdSentence, Count:=num_arg, Extend:=wdMove
+    End If
+
+    complete
+End Sub
+
+
+Sub doc_of_beginning_of_buffer()
+    doc_string = "Move point to the beginning of the buffer."
+End Sub
+Sub beginning_of_buffer()
+'C-home
+    If mark_set Then
+        Selection.HomeKey Unit:=wdStory, Extend:=wdExtend
+    Else
+        Selection.HomeKey Unit:=wdStory
+    End If
+    
+    complete
+End Sub
+
+
+Sub doc_of_end_of_buffer()
+    doc_string = "Move point to the end of the buffer."
+End Sub
+Sub end_of_buffer()
+'C-end
+    If mark_set Then
+        Selection.EndKey Unit:=wdStory, Extend:=wdExtend
+    Else
+        Selection.EndKey Unit:=wdStory
+    End If
+    
+    complete
+End Sub
+
+
+Sub doc_of_forward_page()
+    doc_string = "Move forward to page boundary."
+End Sub
+Sub forward_page()
+'C-x ]
+    Selection.GoToNext What:=wdGoToPage
+    
+    complete
+End Sub
+
+
+Sub doc_of_backward_page()
+    doc_string = "Move backward to page boundary."
+End Sub
+Sub backward_page()
+'C-x [
+    Selection.GoToPrevious What:=wdGoToPage
+    
+    complete
+End Sub
+
+
+Sub doc_of_forward_paragraph()
+    doc_string = "Move forward to end of paragraph."
+End Sub
+Sub forward_paragraph()
+'M-}
+    If mark_set Then
+        Selection.MoveDown Unit:=wdParagraph, Count:=num_arg, Extend:=wdExtend
+    Else
+        Selection.MoveDown Unit:=wdParagraph, Count:=num_arg, Extend:=wdMove
+    End If
+
+    complete
+End Sub
+
+
+Sub doc_of_backward_paragraph()
+    doc_string = "Move backward to start of paragraph."
+End Sub
+Sub backward_paragraph()
+'M-{
+    If mark_set Then
+        Selection.MoveUp Unit:=wdParagraph, Count:=num_arg, Extend:=wdExtend
+    Else
+        Selection.MoveUp Unit:=wdParagraph, Count:=num_arg, Extend:=wdMove
+    End If
+
+    complete
+End Sub
+
+
+Sub doc_of_scroll_up_command()
+    doc_string = "Scroll text of selected window upward ARG lines; or near full screen if no ARG."
+End Sub
+Sub scroll_up_command()
+'C-v
+    If mark_set Then
+        Selection.MoveDown Unit:=wdScreen, Count:=num_arg, Extend:=wdExtend
+    Else
+        Selection.MoveDown Unit:=wdScreen, Count:=num_arg, Extend:=wdMove
+    End If
+
+    complete
+End Sub
+
+
+Sub doc_of_scroll_down_command()
+    doc_string = "Scroll text of selected window down ARG lines; or near full screen if no ARG."
+End Sub
+Sub scroll_down_command()
+'M-v
+    If mark_set Then
+        Selection.MoveUp Unit:=wdScreen, Count:=num_arg, Extend:=wdExtend
+    Else
+        Selection.MoveUp Unit:=wdScreen, Count:=num_arg, Extend:=wdMove
+    End If
+
+    complete
+End Sub
+
+
+' after LTrim
+' "NUM str"
+' "str"
+' "NUM "
+' "NUM"
+' ""
+Sub doc_of_universal_argument()
+    doc_string = "Begin a numeric argument for the following command."
+End Sub
+Sub universal_argument()
+'C-u
+    Dim raw_input
+    Dim space_pos As Long
+    Dim num_arg_part
+    Dim self_ins_part
+    Dim prompt As String
+
+    prompt = "usage:" & vbCrLf & _
+                vbTab & "N [string_to_insert]"
+
+    raw_input = LTrim(InputBox(prompt, "universal argument"))
+    Debug.Print raw_input
+
+    space_pos = InStr(raw_input, " ")
+    Debug.Assert (space_pos = 0 Or space_pos > 1)
+
+    If space_pos > 1 Then
+        num_arg_part = Left(raw_input, space_pos - 1)
+        self_ins_part = Mid(raw_input, space_pos + 1)
+    Else
+        num_arg_part = raw_input
+        self_ins_part = ""
+    End If
+
+    If num_arg_part = "" Then
+        num_arg = 4
+    Else
+        num_arg = num_arg_part
+    End If
+
+    Debug.Print num_arg
+
+    ' deal with self insert command
+    If self_ins_part <> "" Then
+        While num_arg > 0
+            Selection.TypeText Text:=self_ins_part
+
+            num_arg = num_arg - 1
+        Wend
+        num_arg = 1
+    End If
+
+End Sub
+
+
+Sub doc_of_execute_extended_command()
+    doc_string = "Read function name, then read its arguments and call it."
+End Sub
+Sub execute_extended_command()
+'M-x
+    Dim cmd As String
+    Dim arg As String
+    cmd = InputBox("enter command name", "M-x")
+    
+    cmd = Replace(cmd, "-", "_")
+
+    ' call read_args_for_XXX to prepare arg
+
+    'Application.Run(cmd, arg)
+    On Error Resume Next
+    Application.Run cmd
+End Sub
+
+
+Sub doc_of_transpose_chars()
+    doc_string = "Interchange characters around point, moving forward one character."
+End Sub
+Sub transpose_chars()
+'C-t
+
+    begin_action "transpose chars"
+
+    Dim c
+    Selection.MoveLeft Unit:=wdCharacter, Count:=1, Extend:=wdExtend
+    c = Selection
+    Selection.Delete
+    Selection.Collapse direction:=wdCollapseEnd
+    Selection.MoveRight Unit:=wdCharacter, Count:=num_arg
+    Selection.InsertAfter c
+    Selection.Collapse
+    
+    end_action
+
+    complete
+End Sub
+
+
+Sub doc_of_transpose_words()
+    doc_string = "Interchange words around point, leaving point at end of them."
+End Sub
+Sub transpose_words()
+'M-t
+
+    begin_action "transpose words"
+
+    Dim w
+    Selection.MoveLeft Unit:=wdWord, Count:=1, Extend:=wdExtend
+    w = Selection
+    Selection.Delete
+    Selection.Collapse direction:=wdCollapseEnd
+    Selection.MoveRight Unit:=wdWord, Count:=num_arg
+    Selection.InsertAfter w
+    Selection.Collapse
+    
+    end_action
+    
+    complete
+End Sub
+
+
+Sub doc_of_exchange_point_and_mark()
+    doc_string = "Put the mark where point is now, and point where the mark is now."
+End Sub
+Sub exchange_point_and_mark()
+'C-x C-x
+    
+    ' if region is not highlight, highlight it first.
+    If Selection.type = wdSelectionIP Then
+        Dim point_pos As Long
+        point_pos = Selection.Start
+        
+        If mark_pos <= point_pos Then
+            Selection.Start = mark_pos
+            Selection.StartIsActive = False
+        Else
+            Selection.End = mark_pos
+            Selection.StartIsActive = True
+            
+        End If
+        
+        mark_set = True
+    End If
+    
+    
+    Selection.StartIsActive = Not Selection.StartIsActive
+    
+    If Selection.StartIsActive Then
+        mark_pos = Selection.End
+    Else
+        mark_pos = Selection.Start
+    End If
+
+    complete
+End Sub
+
+
+Sub doc_of_downcase_region()
+    doc_string = "Convert the region to lower case."
+End Sub
+Sub downcase_region()
+'C-x C-l
+    Selection.Range.Case = wdLowerCase
+    
+    select_nothing
+    mark_set = False
+
+    complete
+End Sub
+
+
+Sub doc_of_upcase_region()
+    doc_string = "Convert the region to upper case."
+End Sub
+Sub upcase_region()
+'C-x C-u
+    Selection.Range.Case = wdUpperCase
+
+    select_nothing
+    mark_set = False
+    
+    complete
+End Sub
+
+
+Sub doc_of_mark_whole_buffer()
+    doc_string = "Put point at beginning and mark at end of buffer."
+End Sub
+Sub mark_whole_buffer()
+'C-x h
+    ' Selection.WholeStory
+    Selection.EndKey Unit:=wdStory
+    mark_set = True
+    mark_pos = Selection.Start
+    
+    Selection.HomeKey Unit:=wdStory, Extend:=wdExtend
+
+    complete
+End Sub
+
+
+Sub doc_of_save_buffer()
+    doc_string = "Save current buffer in visited file if modified."
+End Sub
+Sub save_buffer()
+'C-x C-s
+
+    On Error Resume Next
+    ActiveDocument.Save
+
+    complete
+End Sub
+
+
+Sub doc_of_recenter()
+    doc_string = "Move current buffer line to the specified window line."
+End Sub
+Sub recenter()
+'C-l
+
+    Application.ScreenUpdating = False
+    
+    ActiveWindow.ActivePane.VerticalPercentScrolled = 0
+    ActiveWindow.ScrollIntoView Selection.Range, True
+    
+    Application.ScreenUpdating = True
+    
+    complete
+End Sub
+
+
+Sub doc_of_undo()
+    doc_string = "Undo some previous changes."
+End Sub
+Sub undo()
+'C-z
+    On Error Resume Next
+    Application.Run "EditUndo"
+    select_nothing
+    complete
+End Sub
+
+
+Function other_pane_index(this_pane_index As Integer)
+    Debug.Assert this_pane_index = 1 Or this_pane_index = 2
+    If this_pane_index = 1 Then
+        other_pane_index = 2
+    Else
+        other_pane_index = 1
+    End If
+    
+End Function
+
+
+Sub doc_of_split_window_vertically()
+    doc_string = "Split the document window."
+End Sub
+Sub split_window_vertically()
+'C-x 2
+
+    Application.ScreenUpdating = False
+    
+    ' macro DocSplit is interactive
+    'Application.Run MacroName:="DocSplit"
+    
+    ActiveDocument.ActiveWindow.Split = True
+    
+    ActiveWindow.Panes(1).Activate
+    ActiveWindow.ScrollIntoView Selection.Range, True
+    
+    
+    Debug.Print Selection.Start, Selection.End
+    Dim sel_start As Long
+    Dim sel_end As Long
+    sel_start = Selection.Start
+    sel_end = Selection.End
+    
+
+    ActiveWindow.Panes(other_pane_index(ActiveWindow.ActivePane.index)).Activate
+    Selection.Start = sel_start
+    Selection.End = sel_end
+    ActiveWindow.ScrollIntoView Selection.Range, True
+    
+    
+    ActiveWindow.Panes(1).Activate
+    'ActiveWindow.ScrollIntoView Selection.Range, True
+    
+    Application.ScreenUpdating = True
+    
+
+    complete
+End Sub
+
+
+Sub doc_of_other_window()
+    doc_string = "Activate another pane."
+End Sub
+Sub other_window()
+'C-x o
+    If ActiveWindow.Panes.Count > 1 Then
+        ActiveWindow.Panes(other_pane_index(ActiveWindow.ActivePane.index)).Activate
+    End If
+    
+    complete
+End Sub
+
+
+Sub doc_of_delete_window()
+    doc_string = "Close current pane."
+End Sub
+Sub delete_window()
+'C-x 0
+    If ActiveWindow.Panes.Count > 1 Then
+        ActiveWindow.ActivePane.Close
+    End If
+    
+    complete
+End Sub
+
+
+Sub doc_of_delete_other_windows()
+    doc_string = "Remove the document window split."
+End Sub
+Sub delete_other_windows()
+'C-x 1
+    'Application.Run MacroName:="ClosePane"
+    
+'   if we use Split = Flase, we have no idea about which pane will remains.
+'    ActiveDocument.ActiveWindow.Split = False
+
+    While ActiveWindow.Panes.Count > 1
+        ActiveWindow.ActivePane.Next.Activate
+        ActiveWindow.ActivePane.Close
+    Wend
+    
+
+    complete
+End Sub
+
+
+Sub doc_of_set_justification_left()
+    doc_string = "Align text to the left."
+End Sub
+Sub set_justification_left()
+'M-j l
+    Selection.ParagraphFormat.Alignment = wdAlignParagraphLeft
+    complete
+End Sub
+
+
+Sub doc_of_set_justification_center()
+    doc_string = "Center text."
+End Sub
+Sub set_justification_center()
+'M-j c
+    Selection.ParagraphFormat.Alignment = wdAlignParagraphCenter
+    complete
+End Sub
+
+
+Sub doc_of_set_justification_right()
+    doc_string = "Align text to the right."
+End Sub
+Sub set_justification_right()
+'M-j r
+    Selection.ParagraphFormat.Alignment = wdAlignParagraphRight
+    complete
+End Sub
+
+
+Sub doc_of_set_justification_full()
+    doc_string = "Justify."
+End Sub
+Sub set_justification_full()
+'M-j b
+    Selection.ParagraphFormat.Alignment = wdAlignParagraphJustify
+    complete
+End Sub
+
+
+Sub doc_of_describe_key()
+    doc_string = "Display documentation of the function invoked by KEY."
+End Sub
+Sub describe_key()
+'C-h k
+    is_desc_key = True
+    statusbar_prefix = "Describe key: "
+    StatusBar = statusbar_prefix
+    complete
+End Sub
+
+
+Sub doc_of_describe_function()
+    doc_string = "Display the documentation of FUNCTION (a symbol)."
+End Sub
+Sub describe_function()
+'C-h f
+
+    Dim cmd As String
+    cmd = InputBox("enter function name", "Describe function")
+    
+    cmd = Replace(cmd, "-", "_")
+
+    Dim doc_string_proc_name As String
+    doc_string_proc_name = "doc_of_" & cmd
+    
+    On Error Resume Next ' there may NOT be a corresponding doc string porc
+    Application.Run macroname:=doc_string_proc_name
+    
+    'display information about this command
+    MsgBox doc_string, Title:=cmd
+    
+    reset_doc_string
+
+    complete
+End Sub
+
+
+Sub doc_of_isearch_forward()
+    doc_string = "Do incremental search forward."
+End Sub
+Sub isearch_forward()
+'C-s
+    search_fwd = True
+    frmISearch.cbWildcards = False
+    frmISearch.Show 'vbModeless
+End Sub
+
+
+Sub doc_of_isearch_backward()
+    doc_string = "Do incremental search backward."
+End Sub
+Sub isearch_backward()
+'C-r
+    search_fwd = False
+    frmISearch.cbWildcards = False
+    frmISearch.Show vbModeless
+End Sub
+
+
+Sub doc_of_isearch_forward_regexp()
+    doc_string = "Do incremental search forward for regular expression."
+End Sub
+Sub isearch_forward_regexp()
+'C-M-s
+    search_fwd = True
+    frmISearch.cbWildcards = True
+    frmISearch.Show vbModeless
+End Sub
+
+
+Sub doc_of_isearch_backward_regexp()
+    doc_string = "Do incremental search backward for regular expression."
+End Sub
+Sub isearch_backward_regexp()
+'C-M-r
+    search_fwd = False
+    frmISearch.cbWildcards = True
+    frmISearch.Show vbModeless
+End Sub
+
+
+Sub doc_of_delete_horizontal_space()
+    doc_string = "Delete all spaces and tabs around point."
+End Sub
+Sub delete_horizontal_space()
+'M-\
+    Application.ScreenUpdating = False
+    
+    Selection.MoveStartWhile cset:=" ", Count:=wdBackward
+    Selection.MoveEndWhile cset:=" ", Count:=wdForward
+    If Selection.type = wdSelectionNormal Then
+        Selection.Delete
+    End If
+    
+    Application.ScreenUpdating = True
+End Sub
+
+
+Sub doc_of_just_one_space()
+    doc_string = "Delete all spaces and tabs around point, leaving one space (or N spaces)."
+End Sub
+Sub just_one_space()
+'M-SPC
+    Application.ScreenUpdating = False
+    
+    Selection.MoveStartWhile cset:=" ", Count:=wdBackward
+    Selection.MoveEndWhile cset:=" ", Count:=wdForward
+    If Selection.type = wdSelectionNormal Then
+        Selection.Delete
+    End If
+    
+    Selection.TypeText " "
+    
+    Application.ScreenUpdating = True
+End Sub
+
+
+Sub complete()
+    num_arg = 1
+End Sub
+
+
+Sub prompt_undefined()
+    StatusBar = "key undefined"
+    
+    complete
+End Sub

develop_src/EmacsLikeKeyBindings.bas

+Attribute VB_Name = "EmacsLikeKeyBindings"
+' womacs
+
+Option Explicit
+
+
+' Key Binding Conventions
+' http://www.gnu.org/software/emacs/elisp/html_node/Key-Binding-Conventions.html
+
+
+Public current_keymap As KeyMap ' should be per doc
+
+Public global_keymap As KeyMap
+Public C_x_keymap As KeyMap
+Public C_c_keymap As KeyMap
+'Public C_c_OpenSquareBrace_keymap As KeyMap
+'Public C_c_CloseSquareBrace_keymap As KeyMap
+Public C_c_c_keymap As KeyMap
+Public M_j_keymap As KeyMap
+Public C_h_keymap As KeyMap
+
+
+'Sub build_all_keymaps()
+'    build_global_keymap
+'End Sub
+
+
+Sub use_word_key_bindings()
+    push_saved_state ActiveDocument
+    use_default_key_bindings
+    pop_saved_state ActiveDocument
+
+'    Set current_keymap = Nothing
+    
+'    MsgBox "word"
+'    Debug.Assert current_keymap Is Nothing
+
+End Sub
+
+
+Sub use_emacs_key_bindings()
+'    Debug.Assert current_keymap Is Nothing
+    Set current_keymap = global_keymap
+    global_keymap.bind ActiveDocument
+    
+End Sub
+
+
+
+Sub build_global_keymap()
+    Set global_keymap = New KeyMap
+    global_keymap.name = "global"
+    Set global_keymap.Parent = Nothing
+
+    global_keymap.Clear
+    
+    ' there may be more than one entry corresponing to a key
+    ' an entriy near the end of a keymap has higher priority than an entry near the begin
+    
+    unset_all_modified_keys global_keymap
+    
+    ' C-z
+    global_keymap.add_cmd BuildKeyCode(wdKeyControl, wdKeyZ), "undo"
+    
+    ' C-/
+    global_keymap.add_cmd BuildKeyCode(wdKeyControl, wdKeySlash), "undo"
+    
+    ' C-SPC
+    global_keymap.add_cmd BuildKeyCode(wdKeyControl, wdKeySpacebar), "set_mark_command"
+
+    ' C-@
+    global_keymap.add_cmd BuildKeyCode(wdKeyControl, wdKeyShift, wdKey2), "set_mark_command"
+
+    ' C-d
+    global_keymap.add_cmd BuildKeyCode(wdKeyControl, wdKeyD), "delete_char"
+    
+    ' M-d
+'    global_keymap.add_cmd BuildKeyCode(wdKeyAlt, wdKeyD), "DeleteWord"
+    global_keymap.add_cmd BuildKeyCode(wdKeyAlt, wdKeyD), "kill_word"
+    
+    ' M-backspace
+'    global_keymap.add_cmd BuildKeyCode(wdKeyAlt, wdKeyBackspace), "DeleteBackWord"
+    global_keymap.add_cmd BuildKeyCode(wdKeyAlt, wdKeyBackspace), "backward_kill_word"
+    
+'    ' C-g
+'    global_keymap.add_cmd BuildKeyCode(wdKeyControl, wdKeyG), "keyboard_quit"
+    
+    ' C-w
+    global_keymap.add_cmd BuildKeyCode(wdKeyControl, wdKeyW), "kill_region"
+    
+    ' M-w
+    global_keymap.add_cmd BuildKeyCode(wdKeyAlt, wdKeyW), "kill_ring_save"
+    
+    ' C-k
+    global_keymap.add_cmd BuildKeyCode(wdKeyControl, wdKeyK), "kill_line"
+    
+    ' C-y
+    global_keymap.add_cmd BuildKeyCode(wdKeyControl, wdKeyY), "yank"
+    
+    ' M-u
+    global_keymap.add_cmd BuildKeyCode(wdKeyAlt, wdKeyU), "upcase_word"
+    
+    ' M-l
+    global_keymap.add_cmd BuildKeyCode(wdKeyAlt, wdKeyL), "downcase_word"
+    
+    ' M-c
+    global_keymap.add_cmd BuildKeyCode(wdKeyAlt, wdKeyC), "capitalize_word"
+    
+    ' C-t
+    global_keymap.add_cmd BuildKeyCode(wdKeyControl, wdKeyT), "transpose_chars"
+    
+    ' M-t
+    global_keymap.add_cmd BuildKeyCode(wdKeyAlt, wdKeyT), "transpose_words"
+    
+    ' C-m
+    global_keymap.add_cmd BuildKeyCode(wdKeyControl, wdKeyM), "newline"
+    
+    ' C-u
+    global_keymap.add_cmd BuildKeyCode(wdKeyControl, wdKeyU), "universal_argument"
+    
+    ' M-x
+    global_keymap.add_cmd BuildKeyCode(wdKeyAlt, wdKeyX), "execute_extended_command"
+    
+    ' M-f
+    global_keymap.add_cmd BuildKeyCode(wdKeyAlt, wdKeyF), "forward_word"
+    
+    ' M-b
+    global_keymap.add_cmd BuildKeyCode(wdKeyAlt, wdKeyB), "backward_word"
+
+    ' C-f
+    global_keymap.add_cmd BuildKeyCode(wdKeyControl, wdKeyF), "forward_char"
+    
+    ' C-b
+    global_keymap.add_cmd BuildKeyCode(wdKeyControl, wdKeyB), "backward_char"
+    
+    ' C-n
+    global_keymap.add_cmd BuildKeyCode(wdKeyControl, wdKeyN), "next_line"
+    
+    ' C-p
+    global_keymap.add_cmd BuildKeyCode(wdKeyControl, wdKeyP), "previous_line"
+
+    ' C-e
+    global_keymap.add_cmd BuildKeyCode(wdKeyControl, wdKeyE), "move_end_of_line"
+    
+    ' C-a
+    global_keymap.add_cmd BuildKeyCode(wdKeyControl, wdKeyA), "move_beginning_of_line"
+    
+    ' M-e
+    global_keymap.add_cmd BuildKeyCode(wdKeyAlt, wdKeyE), "forward_sentence"
+    
+    ' M-a
+    global_keymap.add_cmd BuildKeyCode(wdKeyAlt, wdKeyA), "backward_sentence"
+    
+    ' C-s
+    global_keymap.add_cmd BuildKeyCode(wdKeyControl, wdKeyS), "isearch_forward"
+    
+    ' C-r
+    global_keymap.add_cmd BuildKeyCode(wdKeyControl, wdKeyR), "isearch_backward"
+    
+    ' C-M-s
+    global_keymap.add_cmd BuildKeyCode(wdKeyControl, wdKeyAlt, wdKeyS), "isearch_forward_regexp"
+    
+    ' C-M-r
+    global_keymap.add_cmd BuildKeyCode(wdKeyControl, wdKeyAlt, wdKeyR), "isearch_backward_regexp"
+    
+    
+    ' M-}
+    global_keymap.add_cmd BuildKeyCode(wdKeyAlt, wdKeyShift, wdKeyCloseSquareBrace), "forward_paragraph"
+    
+    ' M-{
+    global_keymap.add_cmd BuildKeyCode(wdKeyAlt, wdKeyShift, wdKeyOpenSquareBrace), "backward_paragraph"
+    
+    ' C-v
+    global_keymap.add_cmd BuildKeyCode(wdKeyControl, wdKeyV), "scroll_up_command"
+    
+    ' M-v
+    global_keymap.add_cmd BuildKeyCode(wdKeyAlt, wdKeyV), "scroll_down_command"
+    
+    ' C-l
+    global_keymap.add_cmd BuildKeyCode(wdKeyControl, wdKeyL), "recenter"
+        
+    ' C-o
+    global_keymap.add_cmd BuildKeyCode(wdKeyControl, wdKeyO), "open_line"
+    
+    ' C-home
+    global_keymap.add_cmd BuildKeyCode(wdKeyControl, wdKeyHome), "beginning_of_buffer"
+
+    ' C-end
+    global_keymap.add_cmd BuildKeyCode(wdKeyControl, wdKeyEnd), "end_of_buffer"
+
+    ' M-\
+    global_keymap.add_cmd BuildKeyCode(wdKeyAlt, wdKeyBackSlash), "delete_horizontal_space"
+
+    ' M-SPC
+    global_keymap.add_cmd BuildKeyCode(wdKeyAlt, wdKeySpacebar), "just_one_space"
+
+    ' C-x
+    build_C_x_keymap
+    global_keymap.add_map BuildKeyCode(wdKeyControl, wdKeyX), C_x_keymap, "key_proc_C_X"
+
+    ' C-c
+    build_C_c_keymap
+    global_keymap.add_map BuildKeyCode(wdKeyControl, wdKeyC), C_c_keymap, "key_proc_C_C"
+
+    ' M-j
+    build_M_j_keymap
+    global_keymap.add_map BuildKeyCode(wdKeyAlt, wdKeyJ), M_j_keymap, "key_proc_M_J"
+
+    ' C-h
+    build_C_h_keymap
+    global_keymap.add_map BuildKeyCode(wdKeyControl, wdKeyH), C_h_keymap, "key_proc_C_H"
+
+End Sub
+
+
+Sub build_C_x_keymap()
+
+    Set C_x_keymap = New KeyMap
+    C_x_keymap.name = "C-x"
+    Set C_x_keymap.Parent = global_keymap
+
+    C_x_keymap.Clear
+    unset_all_sigle_keys C_x_keymap
+    
+  
+'    ' C-g
+'    C_x_keymap.Add BuildKeyCode(wdKeyControl, wdKeyG), "prompt_undefined"
+    
+    ' C-l
+    C_x_keymap.add_cmd BuildKeyCode(wdKeyControl, wdKeyL), "downcase_region&quo