├── .gitignore ├── README.md ├── _dragonall.py ├── gvim.txt ├── _python_grammar.py ├── _bash.py ├── notepad.py └── gvim.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.pyc 3 | *.dll 4 | *.pyd 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | dragonfly-macros 2 | ================ 3 | 4 | 5 | This repository contains macro files to be used together with natlink and dragonfly: 6 | 7 | https://code.google.com/p/dragonfly/ 8 | 9 | 10 | 11 | The files in this repository enable me to program by voice. The video by Tavis Rudd 12 | in the following link inspired me to create these macros: 13 | 14 | https://www.youtube.com/watch?v=8SkdfdXWYaI 15 | 16 | 17 | 18 | The video linked to below gives a nice introduction on how to use dragonfly: 19 | 20 | http://vimeo.com/9156942 21 | -------------------------------------------------------------------------------- /_dragonall.py: -------------------------------------------------------------------------------- 1 | from dragonfly import (Grammar, AppContext, MappingRule, Dictation, IntegerRef, 2 | Key, Text) 3 | 4 | 5 | grammar = Grammar("dragon") 6 | 7 | 8 | dragon_rule = MappingRule( 9 | name = "dragon", 10 | mapping = { 11 | "snore": Key("npdiv"), 12 | }, 13 | extras = [ 14 | ] 15 | ) 16 | 17 | 18 | 19 | grammar.add_rule(dragon_rule) 20 | grammar.load() 21 | 22 | # Unload function which will be called by natlink at unload time. 23 | def unload(): 24 | global grammar 25 | if grammar: grammar.unload() 26 | grammar = None 27 | 28 | -------------------------------------------------------------------------------- /gvim.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This is a config file for Dragonfly's _multiedit.py command-module. 3 | # To use this config, you must rename this file to _multiedit.txt and 4 | # place it in the same directory as the _multiedit.py file. 5 | # 6 | 7 | # Pull in all of Dragonfly's action objects so that we can use them here. 8 | 9 | from dragonfly import * 10 | 11 | 12 | #--------------------------------------------------------------------------- 13 | # Here we define the release action which releases all 14 | # modifier-keys used within this grammar. It is defined here 15 | # because this functionality is used in many different places. 16 | # Note that it is harmless to release ("...:up") a key multiple 17 | # times or when that key is not held down at all. 18 | 19 | release = Key("shift:up, ctrl:up") 20 | 21 | 22 | #--------------------------------------------------------------------------- 23 | # Here we define various functions for formatting text. 24 | # Each of these functions must have a docstring which defines its 25 | # spoken-form. This docstring must include the "" extra. 26 | # See below for various examples. 27 | 28 | # Format: some_words 29 | def format_score(dictation): # Function name must start with "format_". 30 | """ score """ # Docstring defining spoken-form. 31 | text = str(dictation) # Get written-form of dictated text. 32 | return "_".join(text.split(" ")) # Put underscores between words. 33 | 34 | # Format: some_words() 35 | def format_under_function(dictation): 36 | """ under func """ 37 | text = str(dictation) 38 | return "_".join(text.split(" ")) + "()" 39 | 40 | # Format: SomeWords 41 | def format_studley(dictation): 42 | """ studley """ 43 | text = str(dictation) 44 | words = [word.capitalize() for word in text.split(" ")] 45 | return "".join(words) 46 | 47 | # Format: somewords 48 | def format_one_word(dictation): 49 | """ [all] one word """ 50 | text = str(dictation) 51 | return "".join(text.split(" ")) 52 | 53 | # Format: SOMEWORDS 54 | def format_upper_one_word(dictation): 55 | """ one word upper """ 56 | text = str(dictation) 57 | words = [word.upper() for word in text.split(" ")] 58 | return "".join(words) 59 | 60 | # Format: SOME_WORDS 61 | def format_upper_score(dictation): 62 | """ upper score """ 63 | text = str(dictation) 64 | words = [word.upper() for word in text.split(" ")] 65 | return "_".join(words) 66 | 67 | # Format: someWords 68 | def format_java_method(dictation): 69 | """ Java method """ 70 | text = str(dictation) 71 | words = text.split(" ") 72 | return words[0] + "".join(w.capitalize() for w in words[1:]) 73 | -------------------------------------------------------------------------------- /_python_grammar.py: -------------------------------------------------------------------------------- 1 | # Author:Brandon Lovrien 2 | # This script is to be used for programming in the Python programming language 3 | 4 | from dragonfly import (Grammar, CompoundRule, Dictation, Text, Key, AppContext, MappingRule) 5 | 6 | class PythonEnabler(CompoundRule): 7 | spec = "Enable Python" # Spoken command to enable the Python grammar. 8 | 9 | def _process_recognition(self, node, extras): # Callback when command is spoken. 10 | pythonBootstrap.disable() 11 | pythonGrammar.enable() 12 | print "Python grammar enabled" 13 | 14 | class PythonDisabler(CompoundRule): 15 | spec = "switch language" # spoken command to disable the Python grammar. 16 | 17 | def _process_recognition(self, node, extras): # Callback when command is spoken. 18 | pythonGrammar.disable() 19 | pythonBootstrap.enable() 20 | print "Python grammar disabled" 21 | 22 | # This is a test rule to see if the Python grammar is enabled 23 | class PythonTestRule(CompoundRule): 24 | spec = "test Python" # Spoken form of command. 25 | 26 | def _process_recognition(self, node, extras): # Callback when command is spoken. 27 | print "Python grammar tested" 28 | 29 | # Handles Python commenting syntax 30 | class PythonCommentsSyntax(MappingRule): 31 | 32 | mapping = { 33 | "comment": Text("# "), 34 | 35 | 36 | } 37 | 38 | 39 | # handles Python control structures 40 | class PythonControlStructures(MappingRule): 41 | mapping = { 42 | "if": Text("if condition:") + Key("enter"), 43 | "while loop": Text("while condition:") + Key("enter"), 44 | "for loop": Text("for something in something:") + Key("enter"), 45 | 46 | "function": Text("def functionName():") + Key("enter"), 47 | "class": Text("class className(inheritance):") + Key("enter"), 48 | 49 | 50 | } 51 | 52 | 53 | # The main Python grammar rules are activated here 54 | pythonBootstrap = Grammar("python bootstrap") 55 | pythonBootstrap.add_rule(PythonEnabler()) 56 | pythonBootstrap.load() 57 | 58 | pythonGrammar = Grammar("python grammar") 59 | pythonGrammar.add_rule(PythonTestRule()) 60 | pythonGrammar.add_rule(PythonCommentsSyntax()) 61 | pythonGrammar.add_rule(PythonControlStructures()) 62 | pythonGrammar.add_rule(PythonDisabler()) 63 | pythonGrammar.load() 64 | pythonGrammar.disable() 65 | 66 | 67 | # Unload function which will be called by natlink at unload time. 68 | def unload(): 69 | global pythonGrammar 70 | if pythonGrammar: pythonGrammar.unload() 71 | pythonGrammar = None 72 | -------------------------------------------------------------------------------- /_bash.py: -------------------------------------------------------------------------------- 1 | from dragonfly import (Grammar, AppContext, MappingRule, Dictation, IntegerRef, 2 | Key, Text) 3 | 4 | 5 | git_context = AppContext(title="git Bash") 6 | git_context2 = AppContext(title="MINGW32:") 7 | # set the window title to bash in putty for this context to work 8 | putty_context = AppContext(title="bash") 9 | grammar = Grammar("bash", context=(putty_context | git_context | git_context2)) 10 | 11 | 12 | general_rule = MappingRule( 13 | name = "general", 14 | mapping = { 15 | "cancel": Key("c-c"), 16 | "kay": Key("enter"), 17 | "left": Key("left"), 18 | "right": Key("right"), 19 | 20 | "say ": Text("%(text)s"), 21 | }, 22 | extras = [ 23 | Dictation("text"), 24 | ], 25 | ) 26 | 27 | 28 | 29 | file_extensions_rule = MappingRule( 30 | name = "file extensions", 31 | mapping = { 32 | "dot text": Text(".txt"), 33 | "dot pie": Text(".py"), 34 | }, 35 | extras = [ 36 | ], 37 | ) 38 | 39 | 40 | bash_rule = MappingRule( 41 | name = "bash", 42 | mapping = { 43 | "P. W. D.": Text("pwd\n"), 44 | 45 | "CD dot dot": Text("cd ..\n"), 46 | "CD double dot": Text("cd ..\n"), 47 | "CD triple dot": Text("cd ../..\n"), 48 | "CD ": Text("cd ") + Key("tab:3"), 49 | "CD ": Text("cd %(text)s"), 50 | 51 | "copy": Text("cp "), 52 | "copy ": Text("cp %(text)s"), 53 | 54 | "make directory ": Text("mkdir "), 55 | "make directory ": Text("mkdir %(text)s\n"), 56 | 57 | "move": Text("mv "), 58 | "move ": Text("mv %(text)s"), 59 | "remove": Text("rm "), 60 | "remove ": Text("rm %(text)s"), 61 | 62 | "secure copy": Text("scp"), 63 | "secure copy ": Text("scp %(text)"), 64 | 65 | "change mode": Text("chmod "), 66 | 67 | "grep ": Text("grep %(text)s"), 68 | 69 | "cat": Text("cat "), 70 | "cat ": Text("cat %(text)s"), 71 | "exit": Text("exit\n"), 72 | 73 | "list": Text("ls\n"), 74 | "list ": Text("ls %(text)s"), 75 | "list minus L.": Text("ls -l\n"), 76 | "list minus A.": Text("ls -a\n"), 77 | "list minus one": Text("ls -1 "), 78 | 79 | "pipe": Text(" | "), 80 | 81 | "D. P. K. G. ": Text("dpkg "), 82 | "D. P. K. G. minus L.": Text("dpkg -l "), 83 | "D. P. K. G. minus I.": Text("dpkg -i "), 84 | 85 | "manual page": Text("man "), 86 | 87 | "word count": Text("wc "), 88 | "word count minus L.": Text("wc -l "), 89 | 90 | "repeat previous argument": Key("a-dot"), 91 | "up": Key("up"), 92 | 93 | # cursor movement 94 | "back": Key("a-b"), 95 | "[] back": Key("a-b:%(n)d"), 96 | "[] whiskey": Key("a-f:%(n)d"), 97 | "dollar": Key("c-e"), 98 | "hat": Key("c-a"), 99 | 100 | "scratch": Key("c-w"), 101 | "[] scratch": Key("c-w:%(n)d"), 102 | "paste": Key("c-y"), 103 | 104 | "make": Text("make\n"), 105 | "make clean": Text("make clean\n"), 106 | 107 | "evince": Text("evince "), 108 | "evince ": Text("evince %(text)s"), 109 | 110 | "Python": Text("python "), 111 | 112 | "aptitude search": Text("aptitude search "), 113 | "pseudo-aptitude install": Text("sudo aptitude install "), 114 | "pseudo-aptitude update": Text("sudo aptitude update "), 115 | "pseudo-aptitude remove": Text("sudo aptitude remove "), 116 | 117 | "A. P. T. file search": Text("apt-file search "), 118 | 119 | "vim": Text("vim "), 120 | "vim ": Text("vim %(text)s"), 121 | 122 | 123 | "W. get ": Text("wget "), 124 | }, 125 | extras = [ 126 | Dictation("text"), 127 | IntegerRef("n", 1, 20) 128 | ], 129 | defaults = { 130 | "n": 1 131 | } 132 | ) 133 | 134 | 135 | git_rule = MappingRule( 136 | name = "git", 137 | mapping = { 138 | # commands for git version control 139 | "git add": Text("git add "), 140 | "git add ": Text("git add %(text)s"), 141 | "git remove": Text("git rm "), 142 | "git remove ": Text("git rm %(text)s"), 143 | "git move": Text("git move "), 144 | "git move ": Text("git mv %(text)s"), 145 | "git status": Text("git status\n"), 146 | "git patch": Text("git add -p\n"), 147 | 148 | "git branch": Text("git branch "), 149 | 150 | "git merge": Text("git merge "), 151 | "git merge not fast forward": Text("git merge --no-ff "), 152 | 153 | "git log": Text("git log\n"), 154 | "git log [color] words": Text("git log -p --color-words\n"), 155 | "git log minus (P.|patch)": Text("git log -p\n"), 156 | "git log minus stat": Text("git log --stat\n"), 157 | 158 | "git diff": Text("git diff\n"), 159 | "git diff [color] words": Text("git diff --color-words\n"), 160 | "git diff cache": Text("git diff --cached\n"), 161 | "git diff [color] words cached": Text("git diff --color-words --cached\n"), 162 | 163 | 164 | "git submodule init": Text("git submodule init "), 165 | "git submodule update": Text("git submodule update "), 166 | 167 | "git kay": Text("gitk\n"), 168 | "git kay all": Text("gitk --all\n"), 169 | 170 | "git commit message": Text("git commit -m ''") + Key("left"), 171 | "git commit": Text("git commit "), 172 | "git commit --amend": Text("git commit --amend\n"), 173 | 174 | "git check out": Text("git checkout "), 175 | "git check out ": Text("git checkout %(text)s"), 176 | "git check out minus F.": Text("git checkout -f\n"), 177 | 178 | "git stash": Text("git stash\n"), 179 | 180 | "git pull": Text("git pull\n"), 181 | 182 | "git push": Text("git push\n"), 183 | "git push drop box": Text("git push dropbox\n"), 184 | "git push origin": Text("git push origin\n"), 185 | "git push tomato": Text("git push tomate\n"), 186 | "git push all": Text("git push --all\n"), 187 | "git push github": Text("git push github\n"), 188 | "git help": Text("git help"), 189 | "git help push": Text("git help push\n"), 190 | 191 | "git remote add": Text("git remote add"), 192 | "yes": Key("y,enter"), 193 | "no": Key("n,enter"), 194 | "quit": Key("q,enter"), 195 | }, 196 | extras = [ 197 | Dictation("text"), 198 | ], 199 | ) 200 | 201 | prefix_key = "c-a" 202 | 203 | screen_rule = MappingRule( 204 | name = "screen", 205 | mapping = { 206 | "switch to (screen | window) ": Key(prefix_key) + Key("%(n)d"), 207 | "switch to (window next | next window | screen next | next screen)": 208 | Key(prefix_key) + Key("n"), 209 | "switch to (window previous | previous window | screen previous | previous screen)": 210 | Key(prefix_key) + Key("p"), 211 | "create (screen | window)": Key(prefix_key) + Key("c"), 212 | }, 213 | extras = [ 214 | IntegerRef("n", 0, 20) 215 | ] 216 | ) 217 | 218 | 219 | grammar.add_rule(general_rule) 220 | grammar.add_rule(file_extensions_rule) 221 | grammar.add_rule(bash_rule) 222 | grammar.add_rule(screen_rule) 223 | grammar.add_rule(git_rule) 224 | grammar.load() 225 | 226 | # Unload function which will be called by natlink at unload time. 227 | def unload(): 228 | global grammar 229 | if grammar: grammar.unload() 230 | grammar = None 231 | 232 | -------------------------------------------------------------------------------- /notepad.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is a command-module for Dragonfly. 3 | # (c) Copyright 2008 by Christo Butcher 4 | # Licensed under the LGPL, see 5 | # 6 | 7 | """ 8 | Command-module for cursor movement and **editing** 9 | ============================================================================ 10 | 11 | This module allows the user to control the cursor and 12 | efficiently perform multiple text editing actions within a 13 | single phrase. 14 | 15 | 16 | Example commands 17 | ---------------------------------------------------------------------------- 18 | 19 | *Note the "/" characters in the examples below are simply 20 | to help the reader see the different parts of each voice 21 | command. They are not present in the actual command and 22 | should not be spoken.* 23 | 24 | Example: **"up 4 / down 1 page / home / space 2"** 25 | This command will move the cursor up 4 lines, down 1 page, 26 | move to the beginning of the line, and then insert 2 spaces. 27 | 28 | Example: **"left 7 words / backspace 3 / insert hello Cap world"** 29 | This command will move the cursor left 7 words, then delete 30 | the 3 characters before the cursor, and finally insert 31 | the text "hello World". 32 | 33 | Example: **"home / space 4 / down / 43 times"** 34 | This command will insert 4 spaces at the beginning of 35 | of this and the next 42 lines. The final "43 times" 36 | repeats everything in front of it that many times. 37 | 38 | 39 | Discussion of this module 40 | ---------------------------------------------------------------------------- 41 | 42 | This command-module creates a powerful voice command for 43 | editing and cursor movement. This command's structure can 44 | be represented by the following simplified language model: 45 | 46 | - *CommandRule* -- top-level rule which the user can say 47 | - *repetition* -- sequence of actions (name = "sequence") 48 | - *KeystrokeRule* -- rule that maps a single 49 | spoken-form to an action 50 | - *optional* -- optional specification of repeat count 51 | - *integer* -- repeat count (name = "n") 52 | - *literal* -- "times" 53 | 54 | The top-level command rule has a callback method which is 55 | called when this voice command is recognized. The logic 56 | within this callback is very simple: 57 | 58 | 1. Retrieve the sequence of actions from the element with 59 | the name "sequence". 60 | 2. Retrieve the repeat count from the element with the name 61 | "n". 62 | 3. Execute the actions the specified number of times. 63 | 64 | """ 65 | 66 | try: 67 | import pkg_resources 68 | pkg_resources.require("dragonfly >= 0.6.5beta1.dev-r99") 69 | except ImportError: 70 | pass 71 | 72 | from dragonfly import * 73 | 74 | 75 | #--------------------------------------------------------------------------- 76 | # Here we globally defined the release action which releases all 77 | # modifier-keys used within this grammar. It is defined here 78 | # because this functionality is used in many different places. 79 | # Note that it is harmless to release ("...:up") a key multiple 80 | # times or when that key is not held down at all. 81 | 82 | release = Key("shift:up, ctrl:up") 83 | 84 | 85 | #--------------------------------------------------------------------------- 86 | # Set up this module's configuration. 87 | 88 | config = Config("multi edit") 89 | config.cmd = Section("Language section") 90 | config.cmd.map = Item( 91 | # Here we define the *default* command map. If you would like to 92 | # modify it to your personal taste, please *do not* make changes 93 | # here. Instead change the *config file* called "_multiedit.txt". 94 | { 95 | # Spoken-form -> -> -> Action object 96 | "[] up": Key("up:%(n)d"), 97 | "[] down": Key("down:%(n)d"), 98 | "[] left": Key("left:%(n)d"), 99 | "[] right": Key("right:%(n)d"), 100 | "[] go up": Key("pgup:%(n)d"), 101 | "[] go down": Key("pgdown:%(n)d"), 102 | "up (page | pages)": Key("pgup:%(n)d"), 103 | "down (page | pages)": Key("pgdown:%(n)d"), 104 | "left (word | words)": Key("c-left:%(n)d"), 105 | "right (word | words)": Key("c-right:%(n)d"), 106 | "hat": Key("home"), 107 | "dollar": Key("end"), 108 | "doc home": Key("c-home"), 109 | "doc end": Key("c-end"), 110 | 111 | "space []": release + Key("space:%(n)d"), 112 | "enter []": release + Key("enter:%(n)d"), 113 | "tab []": Key("tab:%(n)d"), 114 | "D. []": release + Key("del:%(n)d"), 115 | "D. [ | this] (line|lines)": release + Key("home, s-down:%(n)d, del"), 116 | "backspace []": release + Key("backspace:%(n)d"), 117 | "pop up": release + Key("apps"), 118 | 119 | "paste": release + Key("c-v"), 120 | "duplicate ": release + Key("c-c, c-v:%(n)d"), 121 | "copy": release + Key("c-c"), 122 | "cut": release + Key("c-x"), 123 | "select all": release + Key("c-a"), 124 | "[hold] shift": Key("shift:down"), 125 | "release shift": Key("shift:up"), 126 | "[hold] control": Key("ctrl:down"), 127 | "release control": Key("ctrl:up"), 128 | "release [all]": release, 129 | 130 | "save file": Key("c-s"), 131 | 132 | "mimic ": release + Mimic(extra="text"), 133 | }, 134 | namespace={ 135 | "Key": Key, 136 | "Text": Text, 137 | } 138 | ) 139 | namespace = config.load() 140 | 141 | #--------------------------------------------------------------------------- 142 | # Here we prepare the list of formatting functions from the config file. 143 | 144 | # Retrieve text-formatting functions from this module's config file. 145 | # Each of these functions must have a name that starts with "format_". 146 | format_functions = {} 147 | if namespace: 148 | for name, function in namespace.items(): 149 | if name.startswith("format_") and callable(function): 150 | spoken_form = function.__doc__.strip() 151 | 152 | # We wrap generation of the Function action in a function so 153 | # that its *function* variable will be local. Otherwise it 154 | # would change during the next iteration of the namespace loop. 155 | def wrap_function(function): 156 | def _function(dictation): 157 | formatted_text = function(dictation) 158 | Text(formatted_text).execute() 159 | return Function(_function) 160 | 161 | action = wrap_function(function) 162 | format_functions[spoken_form] = action 163 | 164 | 165 | # Here we define the text formatting rule. 166 | # The contents of this rule were built up from the "format_*" 167 | # functions in this module's config file. 168 | if format_functions: 169 | class FormatRule(MappingRule): 170 | 171 | mapping = format_functions 172 | extras = [Dictation("dictation")] 173 | 174 | else: 175 | FormatRule = None 176 | 177 | 178 | #--------------------------------------------------------------------------- 179 | # Here we define the keystroke rule. 180 | 181 | # This rule maps spoken-forms to actions. Some of these 182 | # include special elements like the number with name "n" 183 | # or the dictation with name "text". This rule is not 184 | # exported, but is referenced by other elements later on. 185 | # It is derived from MappingRule, so that its "value" when 186 | # processing a recognition will be the right side of the 187 | # mapping: an action. 188 | # Note that this rule does not execute these actions, it 189 | # simply returns them when it's value() method is called. 190 | # For example "up 4" will give the value Key("up:4"). 191 | # More information about Key() actions can be found here: 192 | # http://dragonfly.googlecode.com/svn/trunk/dragonfly/documentation/actionkey.html 193 | class KeystrokeRule(MappingRule): 194 | 195 | exported = False 196 | 197 | mapping = config.cmd.map 198 | extras = [ 199 | IntegerRef("n", 1, 100), 200 | Dictation("text"), 201 | Dictation("text2"), 202 | ] 203 | defaults = { 204 | "n": 1, 205 | } 206 | # Note: when processing a recognition, the *value* of 207 | # this rule will be an action object from the right side 208 | # of the mapping given above. This is default behavior 209 | # of the MappingRule class' value() method. It also 210 | # substitutes any "%(...)." within the action spec 211 | # with the appropriate spoken values. 212 | 213 | 214 | #--------------------------------------------------------------------------- 215 | # Here we create an element which is the sequence of keystrokes. 216 | 217 | # First we create an element that references the keystroke rule. 218 | # Note: when processing a recognition, the *value* of this element 219 | # will be the value of the referenced rule: an action. 220 | alternatives = [] 221 | alternatives.append(RuleRef(rule=KeystrokeRule())) 222 | if FormatRule: 223 | alternatives.append(RuleRef(rule=FormatRule())) 224 | single_action = Alternative(alternatives) 225 | 226 | # Second we create a repetition of keystroke elements. 227 | # This element will match anywhere between 1 and 16 repetitions 228 | # of the keystroke elements. Note that we give this element 229 | # the name "sequence" so that it can be used as an extra in 230 | # the rule definition below. 231 | # Note: when processing a recognition, the *value* of this element 232 | # will be a sequence of the contained elements: a sequence of 233 | # actions. 234 | sequence = Repetition(single_action, min=1, max=16, name="sequence") 235 | 236 | 237 | #--------------------------------------------------------------------------- 238 | # Here we define the top-level rule which the user can say. 239 | 240 | # This is the rule that actually handles recognitions. 241 | # When a recognition occurs, it's _process_recognition() 242 | # method will be called. It receives information about the 243 | # recognition in the "extras" argument: the sequence of 244 | # actions and the number of times to repeat them. 245 | class RepeatRule(CompoundRule): 246 | 247 | # Here we define this rule's spoken-form and special elements. 248 | spec = " [[[and] repeat [that]] times]" 249 | extras = [ 250 | sequence, # Sequence of actions defined above. 251 | IntegerRef("n", 1, 100), # Times to repeat the sequence. 252 | ] 253 | defaults = { 254 | "n": 1, # Default repeat count. 255 | } 256 | 257 | # This method gets called when this rule is recognized. 258 | # Arguments: 259 | # - node -- root node of the recognition parse tree. 260 | # - extras -- dict of the "extras" special elements: 261 | # . extras["sequence"] gives the sequence of actions. 262 | # . extras["n"] gives the repeat count. 263 | def _process_recognition(self, node, extras): 264 | sequence = extras["sequence"] # A sequence of actions. 265 | count = extras["n"] # An integer repeat count. 266 | for i in range(count): 267 | for action in sequence: 268 | action.execute() 269 | release.execute() 270 | 271 | 272 | #--------------------------------------------------------------------------- 273 | # Create and load this module's grammar. 274 | 275 | notepad_context = AppContext(executable="notepad") 276 | grammar = Grammar("multi edit", context=notepad_context) 277 | grammar.add_rule(RepeatRule()) # Add the top-level rule. 278 | grammar.load() # Load the grammar. 279 | 280 | # Unload function which will be called at unload time. 281 | def unload(): 282 | global grammar 283 | if grammar: grammar.unload() 284 | grammar = None 285 | -------------------------------------------------------------------------------- /gvim.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is a command-module for Dragonfly. 3 | # (c) Copyright 2008 by Christo Butcher 4 | # Licensed under the LGPL, see 5 | # 6 | # Modified by David Gessner 7 | # Contains some code obtained from 8 | # https://github.com/danielgm/JarvisGrammars/blob/master/vim.py 9 | 10 | """ 11 | Command-module for the vim editor 12 | ============================================================================ 13 | 14 | This module allows the user to control the vim text editor. 15 | 16 | 17 | Discussion of this module 18 | ---------------------------------------------------------------------------- 19 | 20 | This command-module creates a powerful voice command for 21 | editing and cursor movement. This command's structure can 22 | be represented by the following simplified language model: 23 | 24 | - *CommandRule* -- top-level rule which the user can say 25 | - *repetition* -- sequence of actions (name = "sequence") 26 | - *NormalModeKeystrokeRule* -- rule that maps a single 27 | spoken-form to an action 28 | - *optional* -- optional specification of repeat count 29 | - *integer* -- repeat count (name = "n") 30 | - *literal* -- "times" 31 | 32 | The top-level command rule has a callback method which is 33 | called when this voice command is recognized. The logic 34 | within this callback is very simple: 35 | 36 | 1. Retrieve the sequence of actions from the element with 37 | the name "sequence". 38 | 2. Retrieve the repeat count from the element with the name 39 | "n". 40 | 3. Execute the actions the specified number of times. 41 | 42 | """ 43 | 44 | try: 45 | import pkg_resources 46 | pkg_resources.require("dragonfly >= 0.6.5beta1.dev-r99") 47 | except ImportError: 48 | pass 49 | 50 | from dragonfly import * 51 | 52 | 53 | #--------------------------------------------------------------------------- 54 | # Here we globally defined the release action which releases all 55 | # modifier-keys used within this grammar. It is defined here 56 | # because this functionality is used in many different places. 57 | # Note that it is harmless to release ("...:up") a key multiple 58 | # times or when that key is not held down at all. 59 | 60 | release = Key("shift:up, ctrl:up") 61 | 62 | class LetterRule(MappingRule): 63 | exported = True 64 | mapping = { 65 | 'alpha': Key('a', static=True), 66 | 'bravo': Key('b', static=True), 67 | 'charlie': Key('c', static=True), 68 | 'delta': Key('d', static=True), 69 | 'echo': Key('e', static=True), 70 | 'foxtrot': Key('f', static=True), 71 | 'golf': Key('g', static=True), 72 | 'hotel': Key('h', static=True), 73 | 'india': Key('i', static=True), 74 | 'juliet': Key('j', static=True), 75 | 'kilo': Key('k', static=True), 76 | 'lima': Key('l', static=True), 77 | 'mike': Key('m', static=True), 78 | 'november': Key('n', static=True), 79 | 'oscar': Key('o', static=True), 80 | 'papa': Key('p', static=True), 81 | 'queen': Key('q', static=True), 82 | 'romeo': Key('r', static=True), 83 | 'sierra': Key('s', static=True), 84 | 'tango': Key('t', static=True), 85 | 'uniform': Key('u', static=True), 86 | 'victor': Key('v', static=True), 87 | 'whiskey': Key('w', static=True), 88 | 'x-ray': Key('x', static=True), 89 | 'yankee': Key('y', static=True), 90 | 'zulu': Key('z', static=True), 91 | 92 | 'upper alpha': Key('A', static=True), 93 | 'upper bravo': Key('B', static=True), 94 | 'upper charlie': Key('C', static=True), 95 | 'upper delta': Key('D', static=True), 96 | 'upper echo': Key('E', static=True), 97 | 'upper foxtrot': Key('F', static=True), 98 | 'upper golf': Key('G', static=True), 99 | 'upper hotel': Key('H', static=True), 100 | 'upper india': Key('I', static=True), 101 | 'upper juliet': Key('J', static=True), 102 | 'upper kilo': Key('K', static=True), 103 | 'upper lima': Key('L', static=True), 104 | 'upper mike': Key('M', static=True), 105 | 'upper november': Key('N', static=True), 106 | 'upper oscar': Key('O', static=True), 107 | 'upper papa': Key('P', static=True), 108 | 'upper queen': Key('Q', static=True), 109 | 'upper romeo': Key('R', static=True), 110 | 'upper sierra': Key('S', static=True), 111 | 'upper tango': Key('T', static=True), 112 | 'upper uniform': Key('U', static=True), 113 | 'upper victor': Key('V', static=True), 114 | 'upper whiskey': Key('W', static=True), 115 | 'upper x-ray': Key('X', static=True), 116 | 'upper yankee': Key('Y', static=True), 117 | 'upper zulu': Key('Z', static=True), 118 | 119 | 'zero': Key('0'), 120 | 'one': Key('1'), 121 | 'two': Key('2'), 122 | 'three': Key('3'), 123 | 'four': Key('4'), 124 | 'five': Key('5'), 125 | 'six': Key('6'), 126 | 'seven': Key('7'), 127 | 'eight': Key('8'), 128 | 'nine': Key('9'), 129 | 130 | 'space': Key('space'), 131 | 'tab': Key('tab'), 132 | 133 | 'ampersand': Key('ampersand'), 134 | 'apostrophe': Key('apostrophe'), 135 | 'asterisk': Key('asterisk'), 136 | 'at': Key('at'), 137 | 'backslash': Key('backslash'), 138 | 'backtick': Key('backtick'), 139 | 'bar': Key('bar'), 140 | 'caret': Key('caret'), 141 | 'colon': Key('colon'), 142 | 'comma': Key('comma'), 143 | 'dollar': Key('dollar'), 144 | '(dot|period)': Key('dot'), 145 | 'double quote': Key('dquote'), 146 | 'equal': Key('equal'), 147 | 'bang': Key('exclamation'), 148 | 'hash': Key('hash'), 149 | 'hyphen': Key('hyphen'), 150 | 'minus': Key('minus'), 151 | 'percent': Key('percent'), 152 | 'plus': Key('plus'), 153 | 'question': Key('question'), 154 | # Getting Invalid key name: 'semicolon' 155 | #'semicolon': Key('semicolon'), 156 | 'slash': Key('slash'), 157 | '[single] quote': Key('squote'), 158 | 'tilde': Key('tilde'), 159 | 'underscore | score': Key('underscore'), 160 | 161 | 'langle': Key('langle'), 162 | 'lace': Key('lbrace'), 163 | 'lack': Key('lbracket'), 164 | 'laip': Key('lparen'), 165 | 'rangle': Key('rangle'), 166 | 'race': Key('rbrace'), 167 | 'rack': Key('rbracket'), 168 | 'raip': Key('rparen'), 169 | } 170 | 171 | letter = RuleRef(rule=LetterRule(), name='letter') 172 | letter_sequence = Repetition(letter, min=1, max=32, name='letter_sequence') 173 | 174 | def executeLetter(letter): 175 | letter.execute() 176 | 177 | def executeLetterSequence(letter_sequence): 178 | for letter in letter_sequence: 179 | letter.execute() 180 | 181 | #--------------------------------------------------------------------------- 182 | # Set up this module's configuration. 183 | 184 | # This defines a configuration object with the name "gvim". 185 | config = Config("gvim") 186 | config.cmd = Section("Language section") 187 | 188 | 189 | # This searches for a file with the same name as this file (gvim.py), but with 190 | # the extension ".py" replaced by ".txt". In other words, it loads the 191 | # configuration specified in the file gvim.txt 192 | namespace = config.load() 193 | 194 | #--------------------------------------------------------------------------- 195 | # Here we prepare the list of formatting functions from the config file. 196 | 197 | # Retrieve text-formatting functions from this module's config file. 198 | # Each of these functions must have a name that starts with "format_". 199 | format_functions = {} 200 | if namespace: 201 | for name, function in namespace.items(): 202 | if name.startswith("format_") and callable(function): 203 | spoken_form = function.__doc__.strip() 204 | 205 | # We wrap generation of the Function action in a function so 206 | # that its *function* variable will be local. Otherwise it 207 | # would change during the next iteration of the namespace loop. 208 | def wrap_function(function): 209 | def _function(dictation): 210 | formatted_text = function(dictation) 211 | Text(formatted_text).execute() 212 | return Function(_function) 213 | 214 | action = wrap_function(function) 215 | format_functions[spoken_form] = action 216 | 217 | 218 | # Here we define the text formatting rule. 219 | # The contents of this rule were built up from the "format_*" 220 | # functions in this module's config file. 221 | if format_functions: 222 | class FormatRule(MappingRule): 223 | 224 | mapping = format_functions 225 | extras = [Dictation("dictation")] 226 | 227 | else: 228 | FormatRule = None 229 | 230 | 231 | #--------------------------------------------------------------------------- 232 | # Here we define the keystroke rule. 233 | 234 | # This rule maps spoken-forms to actions. Some of these 235 | # include special elements like the number with name "n" 236 | # or the dictation with name "text". This rule is not 237 | # exported, but is referenced by other elements later on. 238 | # It is derived from MappingRule, so that its "value" when 239 | # processing a recognition will be the right side of the 240 | # mapping: an action. 241 | # Note that this rule does not execute these actions, it 242 | # simply returns them when it's value() method is called. 243 | # For example "up 4" will give the value Key("up:4"). 244 | # More information about Key() actions can be found here: 245 | # http://dragonfly.googlecode.com/svn/trunk/dragonfly/documentation/actionkey.html 246 | class NormalModeKeystrokeRule(MappingRule): 247 | 248 | exported = False 249 | 250 | mapping = { 251 | "[] up": Key("k:%(n)d"), 252 | "[] down": Key("j:%(n)d"), 253 | "[] left": Key("h:%(n)d"), 254 | "[] right": Key("l:%(n)d"), 255 | "[] go up": Key("c-b:%(n)d"), 256 | "[] go down": Key("c-f:%(n)d"), 257 | "hat": Key("caret"), 258 | "dollar": Key("dollar"), 259 | "match": Key("percent"), 260 | "doc home": Key("c-home"), 261 | "doc end": Key("c-end"), 262 | 263 | "lower case": Key("g,u"), 264 | "upper case": Key("g,U"), 265 | "swap case": Key("tilde"), 266 | 267 | "visual": Key("v"), 268 | "visual line": Key("s-v"), 269 | "visual block": Key("c-v"), 270 | 271 | "next": Key("n"), 272 | "previous": Key("N"), 273 | "[] back": Key("b:%(n)d"), 274 | "[] whiskey": Key("w:%(n)d"), 275 | "[] end": Key("e:%(n)d"), 276 | 277 | "Center": Key("z,dot"), 278 | "format": Key("g,q"), 279 | 280 | "next paragraph": Key("rbrace"), 281 | "previous paragraph": Key("lbrace"), 282 | "a paragraph": Key("a,p"), 283 | "inner paragraph": Key("i,p"), 284 | 285 | "[] X.": Key("x:%(n)d"), 286 | "[] backspace": Key("backspace:%(n)d"), 287 | 288 | 289 | "[] Pete macro": Key("at,at:%(n)d"), 290 | 291 | "[] join": Key("J:%(n)d"), 292 | 293 | "(delete | D.)": Key("d"), 294 | "[] (delete | D.) (whiskey|word)": Text("%(n)ddw"), 295 | "(delete | D.) a (whiskey | word)": Key("d,a,w"), 296 | "(delete | D.) inner (whiskey | word)": Key("d,i,w"), 297 | "(delete | D.) a paragraph": Key("d,a,p"), 298 | "(delete | D.) inner paragraph": Key("d,i,p"), 299 | "(delete | D.) a (paren|parenthesis|raip|laip)": Key("d,a,rparen"), 300 | "(delete | D.) inner (paren|parenthesis|raip|laip)": Key("d,i,rparen"), 301 | "(delete | D.) a (bracket|rack|lack)": Key("d,a,rbracket"), 302 | "(delete | D.) inner (bracket|rack|lack)": Key("d,i,rbracket"), 303 | "(delete | D.) a (bracket|race|lace)": Key("d,a,rbrace"), 304 | "(delete | D.) inner (bracket|race|lace)": Key("d,i,rbrace"), 305 | 306 | "[] (increment|increase)": Key("c-a:%(n)d"), 307 | "[] (decrement|decrease)": Key("c-x:%(n)d"), 308 | 309 | "shift (delete | D.)": Key("s-d"), 310 | 311 | "[] undo": Key("u:%(n)d"), 312 | "[] redo": Key("c-r:%(n)d"), 313 | 314 | '[] find ': Text('%(n)df') + Function(executeLetter), 315 | '[] shift find ': Text('%(n)dF') + Function(executeLetter), 316 | 'find [] ': Text('%(n)df') + Function(executeLetter), 317 | 'shift find [] ': Text('%(n)dF') + Function(executeLetter), 318 | 319 | '[] again': Text('%(n)d;'), 320 | '[] shift again': Text('%(n)d,'), 321 | 322 | '[] until ': Text('%(n)dt') + Function(executeLetter), 323 | '[] shift until ': Text('%(n)dT') + Function(executeLetter), 324 | 'until [] ': Text('%(n)dt') + Function(executeLetter), 325 | 'shift until [] ': Text('%(n)dT') + Function(executeLetter), 326 | 327 | "(yank | copy)": Key("y"), 328 | "(yank | copy) a paragraph": Key("y,a,p"), 329 | "(yank | copy) inner paragraph": Key("y,i,p"), 330 | "(yank | copy) a (paren|parenthesis|raip|laip)": Key("y,a,rparen"), 331 | "(yank | copy) inner (paren|parenthesis|raip|laip)": Key("y,i,rparen"), 332 | "shift (yank | copy)": Key("Y"), 333 | "copy line": Key("y,y"), 334 | 335 | "paste": Key("p"), 336 | "shift paste": Key("P"), 337 | 338 | "replace": Key("r"), 339 | "shift replace": Key("R"), 340 | 341 | "shift left": Key("langle,langle"), 342 | "shift right": Key("rangle,rangle"), 343 | 344 | "fuzzy find": Key("backslash,t"), 345 | 346 | # Python specific macros that work together with certain plug-ins 347 | 348 | # used in Jedi vim 349 | "go to definition": Key("backslash,d"), 350 | 351 | # Pete is shorthand for repeat 352 | "[] Pete": Key("dot:%(n)d"), 353 | 354 | "mimic ": release + Mimic(extra="text"), 355 | } 356 | extras = [ 357 | letter, 358 | letter_sequence, 359 | IntegerRef("n", 1, 100), 360 | Dictation("text"), 361 | Dictation("text2"), 362 | ] 363 | defaults = { 364 | "n": 1, 365 | } 366 | # Note: when processing a recognition, the *value* of 367 | # this rule will be an action object from the right side 368 | # of the mapping given above. This is default behavior 369 | # of the MappingRule class' value() method. It also 370 | # substitutes any "%(...)." within the action spec 371 | # with the appropriate spoken values. 372 | 373 | 374 | #--------------------------------------------------------------------------- 375 | # Here we create an element which is the sequence of keystrokes. 376 | 377 | # First we create an element that references the keystroke rule. 378 | # Note: when processing a recognition, the *value* of this element 379 | # will be the value of the referenced rule: an action. 380 | normal_mode_alternatives = [] 381 | normal_mode_alternatives.append(RuleRef(rule=NormalModeKeystrokeRule())) 382 | if FormatRule: 383 | normal_mode_alternatives.append(RuleRef(rule=FormatRule())) 384 | normal_mode_single_action = Alternative(normal_mode_alternatives) 385 | 386 | # Second we create a repetition of keystroke elements. 387 | # This element will match anywhere between 1 and 16 repetitions 388 | # of the keystroke elements. Note that we give this element 389 | # the name "sequence" so that it can be used as an extra in 390 | # the rule definition below. 391 | # Note: when processing a recognition, the *value* of this element 392 | # will be a sequence of the contained elements: a sequence of 393 | # actions. 394 | normal_mode_sequence = Repetition(normal_mode_single_action, 395 | min=1, max=16, name="normal_mode_sequence") 396 | 397 | 398 | #--------------------------------------------------------------------------- 399 | # Here we define the top-level rule which the user can say. 400 | 401 | # This is the rule that actually handles recognitions. 402 | # When a recognition occurs, it's _process_recognition() 403 | # method will be called. It receives information about the 404 | # recognition in the "extras" argument: the sequence of 405 | # actions and the number of times to repeat them. 406 | class NormalModeRepeatRule(CompoundRule): 407 | 408 | # Here we define this rule's spoken-form and special elements. 409 | spec = " [[[and] repeat [that]] times]" 410 | extras = [ 411 | # Sequence of actions defined above. 412 | normal_mode_sequence, 413 | # Times to repeat the sequence. 414 | IntegerRef("n", 1, 100), 415 | ] 416 | defaults = { 417 | # Default repeat count. 418 | "n": 1, 419 | } 420 | 421 | # This method gets called when this rule is recognized. 422 | # Arguments: 423 | # - node -- root node of the recognition parse tree. 424 | # - extras -- dict of the "extras" special elements: 425 | # . extras["sequence"] gives the sequence of actions. 426 | # . extras["n"] gives the repeat count. 427 | def _process_recognition(self, node, extras): 428 | # A sequence of actions. 429 | normal_mode_sequence = extras["normal_mode_sequence"] 430 | # An integer repeat count. 431 | count = extras["n"] 432 | for i in range(count): 433 | for action in normal_mode_sequence: 434 | action.execute() 435 | release.execute() 436 | 437 | 438 | #--------------------------------------------------------------------------- 439 | 440 | gvim_window_rule = MappingRule( 441 | name = "gvim_window", 442 | mapping = { 443 | # window navigation commands 444 | "window left": Key("c-w,h"), 445 | "window right": Key("c-w,l"), 446 | "window up": Key("c-w,k"), 447 | "window down": Key("c-w,j"), 448 | 449 | # window creation commands 450 | "window split": Key("c-w,s"), 451 | "window vertical split": Key("c-w,v"), 452 | }, 453 | extras = [ 454 | ] 455 | ) 456 | 457 | #--------------------------------------------------------------------------- 458 | 459 | gvim_tabulator_rule = MappingRule( 460 | name = "gvim_tabulators", 461 | mapping = { 462 | # tabulator navigation commands 463 | "tabulator next": Key("g,t"), 464 | "tabulator previous": Key("g,T"), 465 | }, 466 | extras = [ 467 | ] 468 | ) 469 | 470 | #--------------------------------------------------------------------------- 471 | 472 | gvim_general_rule = MappingRule( 473 | name = "gvim_general", 474 | mapping = { 475 | "cancel": Key("escape,u"), 476 | }, 477 | extras = [ 478 | ] 479 | ) 480 | 481 | #--------------------------------------------------------------------------- 482 | 483 | gvim_navigation_rule = MappingRule( 484 | name = "gvim_navigation", 485 | mapping = { 486 | "go first line": Key("g,g"), 487 | "go last line": Key("G"), 488 | "go old": Key("c-o"), 489 | 490 | "cursor top": Key("s-h"), 491 | "cursor middle": Key("s-m"), 492 | "cursor (low | bottom)": Key("s-l"), 493 | 494 | # line navigation 495 | "go ": Key("colon") + Text("%(line)s\n"), 496 | 497 | # searching 498 | "search ": Key("slash") + Text("%(text)s\n"), 499 | "search this": Key("asterisk"), 500 | "back search ": Key("question") + Text("%(text)s\n"), 501 | 502 | }, 503 | extras = [ 504 | Dictation("text"), 505 | IntegerRef("n", 1, 50), 506 | IntegerRef("line", 1, 10000) 507 | ] 508 | ) 509 | 510 | #--------------------------------------------------------------------------- 511 | 512 | 513 | class ExModeEnabler(CompoundRule): 514 | # Spoken command to enable the ExMode grammar. 515 | spec = "execute" 516 | 517 | # Callback when command is spoken. 518 | def _process_recognition(self, node, extras): 519 | exModeBootstrap.disable() 520 | normalModeGrammar.disable() 521 | ExModeGrammar.enable() 522 | Key("colon").execute() 523 | print "ExMode grammar enabled" 524 | print "Available commands:" 525 | print ' \n'.join(ExModeCommands.mapping.keys()) 526 | print "\n(EX MODE)" 527 | 528 | 529 | 530 | class ExModeDisabler(CompoundRule): 531 | # spoken command to exit ex mode 532 | spec = "" 533 | extras = [Choice("command", { 534 | "kay": "okay", 535 | "cancel": "cancel", 536 | })] 537 | 538 | def _process_recognition(self, node, extras): 539 | ExModeGrammar.disable() 540 | exModeBootstrap.enable() 541 | normalModeGrammar.enable() 542 | if extras["command"] == "cancel": 543 | print "ex mode command canceled" 544 | Key("escape").execute() 545 | else: 546 | print "ex mode command accepted" 547 | Key("enter").execute() 548 | print "\n(NORMAL)" 549 | 550 | # handles ExMode control structures 551 | class ExModeCommands(MappingRule): 552 | mapping = { 553 | "read": Text("r "), 554 | "(write|save) file": Text("w "), 555 | "quit": Text("q "), 556 | "write and quit": Text("wq "), 557 | "edit": Text("e "), 558 | "tab edit": Text("tabe "), 559 | 560 | "set number": Text("set number "), 561 | "set relative number": Text("set relativenumber "), 562 | "set ignore case": Text("set ignorecase "), 563 | "set no ignore case": Text("set noignorecase "), 564 | "set file format UNIX": Text("set fileformat=unix "), 565 | "set file format DOS": Text("set fileformat=dos "), 566 | "set file type Python": Text("set filetype=python"), 567 | "set file type tex": Text("set filetype=tex"), 568 | 569 | "P. W. D.": Text("pwd "), 570 | 571 | "help": Text("help"), 572 | "substitute": Text("s/"), 573 | "up": Key("up"), 574 | "down": Key("down"), 575 | "[] left": Key("left:%(n)d"), 576 | "[] right": Key("right:%(n)d"), 577 | } 578 | extras = [ 579 | Dictation("text"), 580 | IntegerRef("n", 1, 50), 581 | ] 582 | defaults = { 583 | "n": 1, 584 | } 585 | 586 | 587 | #--------------------------------------------------------------------------- 588 | 589 | class InsertModeEnabler(CompoundRule): 590 | spec = "" 591 | extras = [Choice("command", { 592 | "insert": "i", 593 | "shift insert": "I", 594 | 595 | "change": "c", 596 | "change whiskey": "c,w", 597 | "change (echo|end)": "c,e", 598 | "change a paragraph": "c,a,p", 599 | "change inner paragraph": "c,i,p", 600 | "change a (paren|parenthesis|raip|laip)": "c,a,rparen", 601 | "change inner (paren|parenthesis|raip|laip)": "c,i,rparen", 602 | "shift change": "C", 603 | 604 | "sub line" : "S", 605 | 606 | "(after | append)": "a", 607 | "shift (after | append)": "A", 608 | 609 | "oh": "o", 610 | "shift oh": "O", 611 | 612 | # Jedi vim rename command 613 | "rename": "backslash,r", 614 | })] 615 | 616 | def _process_recognition(self, node, extras): 617 | InsertModeBootstrap.disable() 618 | normalModeGrammar.disable() 619 | InsertModeGrammar.enable() 620 | for string in extras["command"].split(','): 621 | key = Key(string) 622 | key.execute() 623 | print "Available commands:" 624 | print ' \n'.join(InsertModeCommands.mapping.keys()) 625 | print "\n(INSERT)" 626 | 627 | 628 | 629 | class InsertModeDisabler(CompoundRule): 630 | # spoken command to exit InsertMode 631 | spec = "" 632 | extras = [Choice("command", { 633 | "kay": "okay", 634 | "cancel": "cancel", 635 | })] 636 | 637 | def _process_recognition(self, node, extras): 638 | InsertModeGrammar.disable() 639 | InsertModeBootstrap.enable() 640 | normalModeGrammar.enable() 641 | Key("escape").execute() 642 | if extras["command"] == "cancel": 643 | Key("u").execute() 644 | print "Insert command canceled" 645 | else: 646 | print "Insert command accepted" 647 | print "\n(NORMAL)" 648 | 649 | 650 | # handles InsertMode control structures 651 | class InsertModeCommands(MappingRule): 652 | mapping = { 653 | "": Text("%(text)s"), 654 | "[] (scratch|delete)": Key("c-w:%(n)d"), 655 | "[] slap": Key("enter:%(n)d"), 656 | "[] tab": Key("tab:%(n)d"), 657 | "[] backspace": Key("backspace:%(n)d"), 658 | "(scratch|delete) line": Key("c-u"), 659 | "[] left": Key("left:%(n)d"), 660 | "[] right": Key("right:%(n)d"), 661 | 662 | "assign": Key("space,equal,space"), 663 | "plus": Key("space,plus,space"), 664 | "minus": Key("space,minus,space"), 665 | "times": Key("space,asterisk,space"), 666 | "equals": Key("space,equal,equal,space"), 667 | "not equals": Key("space,exclamation,equal,space"), 668 | "triple quote": Key("dquote,dquote,dquote"), 669 | 670 | # snippets for snipmate 671 | "new fixture": Key("f,i,x,tab"), 672 | "new method": Key("d,e,f,s,tab"), 673 | "new class": Key("c,l,tab"), 674 | "new function": Key("d,e,f,tab"), 675 | "new while loop": Key("w,h,tab"), 676 | "new for loop": Key("f,o,r,tab"), 677 | } 678 | extras = [ 679 | Dictation("text"), 680 | IntegerRef("n", 1, 50), 681 | ] 682 | defaults = { 683 | "n": 1, 684 | } 685 | 686 | 687 | #--------------------------------------------------------------------------- 688 | 689 | gvim_exec_context = AppContext(executable="gvim") 690 | # set the window title to vim in the putty session for the following context to 691 | # work. 692 | vim_putty_context = AppContext(title="vim") 693 | gvim_context = (gvim_exec_context | vim_putty_context) 694 | 695 | # set up the grammar for vim's ex mode 696 | exModeBootstrap = Grammar("ExMode bootstrap", context=gvim_context) 697 | exModeBootstrap.add_rule(ExModeEnabler()) 698 | exModeBootstrap.load() 699 | ExModeGrammar = Grammar("ExMode grammar", context=gvim_context) 700 | ExModeGrammar.add_rule(ExModeCommands()) 701 | ExModeGrammar.add_rule(ExModeDisabler()) 702 | ExModeGrammar.load() 703 | ExModeGrammar.disable() 704 | 705 | 706 | 707 | # set up the grammar for vim's insert mode 708 | InsertModeBootstrap = Grammar("InsertMode bootstrap", context=gvim_context) 709 | InsertModeBootstrap.add_rule(InsertModeEnabler()) 710 | InsertModeBootstrap.load() 711 | InsertModeGrammar = Grammar("InsertMode grammar", context=gvim_context) 712 | InsertModeGrammar.add_rule(InsertModeCommands()) 713 | InsertModeGrammar.add_rule(InsertModeDisabler()) 714 | InsertModeGrammar.load() 715 | InsertModeGrammar.disable() 716 | 717 | 718 | 719 | # set up the grammar for vim's normal mode and start normal mode 720 | normalModeGrammar = Grammar("gvim", context=gvim_context) 721 | normalModeGrammar.add_rule(NormalModeRepeatRule()) 722 | normalModeGrammar.add_rule(gvim_window_rule) 723 | normalModeGrammar.add_rule(gvim_tabulator_rule) 724 | normalModeGrammar.add_rule(gvim_general_rule) 725 | normalModeGrammar.add_rule(gvim_navigation_rule) 726 | normalModeGrammar.load() 727 | 728 | 729 | 730 | # Unload function which will be called at unload time. 731 | def unload(): 732 | global normalModeGrammar 733 | if normalModeGrammar: normalModeGrammar.unload() 734 | normalModeGrammar = None 735 | 736 | global ExModeGrammar 737 | if ExModeGrammar: ExModeGrammar.unload() 738 | ExModeGrammar = None 739 | 740 | global InsertModeGrammar 741 | if InsertModeGrammar: InsertModeGrammar.unload() 742 | InsertModeGrammar = None 743 | --------------------------------------------------------------------------------