diff options
| author | Stephen Blott | 2016-12-11 08:22:18 +0000 |
|---|---|---|
| committer | Stephen Blott | 2016-12-11 08:22:18 +0000 |
| commit | 1664a02c02be27a824b19633740a23ec01573c77 (patch) | |
| tree | b7ba7adf347c0b347eec0753717f4bbe746d6537 /background_scripts | |
| parent | bd06c7ccfbfcf36e6d15fba72b7af90254b05da2 (diff) | |
| download | vimium-1664a02c02be27a824b19633740a23ec01573c77.tar.bz2 | |
Rework key-mapping parsing.
There are two changes here:
1. Treat built-in key mappings and custom key mappings in the same way;
that is, we prepend the built-in mappings to the custom mappings and
then parse them all together. This results in a number of
simplifications due to previous duplication of logic and the elimination
of special cases.
2. Parse key mappings in reverse order, so we can just ignore key
mappings after first encountering a key sequence. So, `map`, `unmap`
and `unmapAll` are all treated in more or less the same way.
This is preparatory to reworking some aspects of the help page. In
particular, regardless of the order of maps, unmaps, etc., this approach
makes it easier to find the mapping in effect for a key sequence (and be
able to recreate the order of those mappings).
Diffstat (limited to 'background_scripts')
| -rw-r--r-- | background_scripts/commands.coffee | 120 |
1 files changed, 47 insertions, 73 deletions
diff --git a/background_scripts/commands.coffee b/background_scripts/commands.coffee index 6aa8ca0d..2d3312ea 100644 --- a/background_scripts/commands.coffee +++ b/background_scripts/commands.coffee @@ -1,36 +1,54 @@ Commands = + availableCommands: {} + keyToCommandRegistry: null + mapKeyRegistry: null + init: -> - for own command, descriptor of commandDescriptions - @addCommand(command, descriptor[0], descriptor[1]) - @loadKeyMappings Settings.get "keyMappings" + for own command, [description, options] of commandDescriptions + @availableCommands[command] = extend (options ? {}), description: description + Settings.postUpdateHooks["keyMappings"] = @loadKeyMappings.bind this + @loadKeyMappings Settings.get "keyMappings" loadKeyMappings: (customKeyMappings) -> - @clearKeyMappingsAndSetDefaults() - @parseCustomKeyMappings customKeyMappings - @generateKeyStateMapping() - chrome.storage.local.set mapKeyRegistry: @mapKeyRegistry - - availableCommands: {} - keyToCommandRegistry: {} - - # Registers a command, making it available to be optionally bound to a key. - # options: - # - background: whether this command needs to be run against the background page. - addCommand: (command, description, options = {}) -> - if command of @availableCommands - BgUtils.log "#{command} is already defined! Check commands.coffee for duplicates." - return + @keyToCommandRegistry = {} + @mapKeyRegistry = {} - @availableCommands[command] = extend options, description: description + configLines = ("map #{key} #{command}" for own key, command of defaultKeyMappings) + configLines.push BgUtils.parseLines(customKeyMappings)... + seen = {} + unmapAll = false + for line in configLines.reverse() + tokens = line.split /\s+/ + switch tokens[0] + when "map" + if 3 <= tokens.length and not unmapAll + [_, key, command, optionsList...] = tokens + if not seen[key] and registryEntry = @availableCommands[command] + seen[key] = true + keySequence = @parseKeySequence key + options = @parseCommandOptions command, optionsList + @keyToCommandRegistry[key] = extend {keySequence, command, options}, @availableCommands[command] + when "unmap" + if tokens.length == 2 + seen[tokens[1]] = true + when "unmapAll" + unmapAll = true + when "mapkey" + if tokens.length == 3 + fromChar = @parseKeySequence tokens[1] + toChar = @parseKeySequence tokens[2] + @mapKeyRegistry[fromChar[0]] = toChar[0] if fromChar.length == toChar.length == 1 - mapKeyToCommand: ({ key, keySequence, command, options }) -> - unless @availableCommands[command] - BgUtils.log "#{command} doesn't exist!" - return + chrome.storage.local.set mapKeyRegistry: @mapKeyRegistry + @installKeyStateMapping() - options ?= {} - @keyToCommandRegistry[key] = extend { keySequence, command, options }, @availableCommands[command] + # Push the key mapping for passNextKey into Settings so that it's available in the front end for insert + # mode. We exclude single-key mappings (that is, printable keys) because when users press printable keys + # in insert mode they expect the character to be input, not to be droppped into some special Vimium + # mode. + Settings.set "passNextKeyKeys", + (key for own key of @keyToCommandRegistry when @keyToCommandRegistry[key].command == "passNextKey" and 1 < key.length) # Lower-case the appropriate portions of named keys. # @@ -60,43 +78,6 @@ Commands = else [key[0], @parseKeySequence(key[1..])...] - parseCustomKeyMappings: (customKeyMappings) -> - for line in BgUtils.parseLines customKeyMappings - tokens = line.split /\s+/ - switch tokens[0] - when "map" - [ _, key, command, optionList... ] = tokens - keySequence = @parseKeySequence key - if command? and @availableCommands[command] - key = keySequence.join "" - BgUtils.log "mapping [\"#{keySequence.join '", "'}\"] to #{command}" - @mapKeyToCommand { key, command, keySequence, options: @parseCommandOptions command, optionList } - else - BgUtils.log "skipping [\"#{keySequence.join '", "'}\"] for #{command} -- something is not right" - - when "unmap" - if tokens.length == 2 - keySequence = @parseKeySequence tokens[1] - key = keySequence.join "" - BgUtils.log "Unmapping #{key}" - delete @keyToCommandRegistry[key] - - when "unmapAll" - @keyToCommandRegistry = {} - - when "mapkey" - if tokens.length == 3 - fromChar = @parseKeySequence tokens[1] - toChar = @parseKeySequence tokens[2] - @mapKeyRegistry[fromChar[0]] = toChar[0] if fromChar.length == toChar.length == 1 - - # Push the key mapping for passNextKey into Settings so that it's available in the front end for insert - # mode. We exclude single-key mappings (that is, printable keys) because when users press printable keys - # in insert mode they expect the character to be input, not to be droppped into some special Vimium - # mode. - Settings.set "passNextKeyKeys", - (key for own key of @keyToCommandRegistry when @keyToCommandRegistry[key].command == "passNextKey" and 1 < key.length) - # Command options follow command mappings, and are of one of two forms: # key=value - a value # key - a flag @@ -113,16 +94,9 @@ Commands = options - clearKeyMappingsAndSetDefaults: -> - @keyToCommandRegistry = {} - @mapKeyRegistry = {} - for own key, command of defaultKeyMappings - keySequence = @parseKeySequence key - key = keySequence.join "" - @mapKeyToCommand { key, command, keySequence } - - # This generates a nested key-to-command mapping structure. There is an example in mode_key_handler.coffee. - generateKeyStateMapping: -> + # This generates and installs a nested key-to-command mapping structure. There is an example in + # mode_key_handler.coffee. + installKeyStateMapping: -> keyStateMapping = {} for own keys, registryEntry of @keyToCommandRegistry currentMapping = keyStateMapping @@ -136,7 +110,7 @@ Commands = else currentMapping[key] = extend {}, registryEntry # We don't need these properties in the content scripts. - delete registryEntry[prop] for prop in ["keySequence", "description"] + delete currentMapping[key][prop] for prop in ["keySequence", "description"] chrome.storage.local.set normalModeKeyStateMapping: keyStateMapping # An ordered listing of all available commands, grouped by type. This is the order they will |
