diff options
| author | Stephen Blott | 2016-12-11 15:22:02 +0000 |
|---|---|---|
| committer | GitHub | 2016-12-11 15:22:02 +0000 |
| commit | 7fe88a70031c09f530ad2c22be88c30c7f1e787e (patch) | |
| tree | 2f6b3bdefc8456d3427684f1a0079f81b86f3fbb /background_scripts | |
| parent | bd06c7ccfbfcf36e6d15fba72b7af90254b05da2 (diff) | |
| parent | bd607cf57512580cf5c9c7d81be5b79b93d1ae9f (diff) | |
| download | vimium-7fe88a70031c09f530ad2c22be88c30c7f1e787e.tar.bz2 | |
Merge pull request #2368 from smblott-github/rework-key-mapping-parsing
Rework key-mapping parsing and help-dialog HTML
Diffstat (limited to 'background_scripts')
| -rw-r--r-- | background_scripts/commands.coffee | 137 | ||||
| -rw-r--r-- | background_scripts/main.coffee | 51 |
2 files changed, 64 insertions, 124 deletions
diff --git a/background_scripts/commands.coffee b/background_scripts/commands.coffee index 6aa8ca0d..aece4bec 100644 --- a/background_scripts/commands.coffee +++ b/background_scripts/commands.coffee @@ -1,36 +1,55 @@ 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" + @prepareHelpPageData() 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 +79,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 +95,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,9 +111,25 @@ 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 + # Build the "helpPageData" data structure which the help page needs and place it in Chrome storage. + prepareHelpPageData: -> + commandToKey = {} + for own key, registryEntry of @keyToCommandRegistry + (commandToKey[registryEntry.command] ?= []).push key + commandGroups = {} + for own group, commands of @commandGroups + commandGroups[group] = [] + for command in commands + commandGroups[group].push + command: command + description: @availableCommands[command].description + keys: commandToKey[command] ? [] + advanced: command in @advancedCommands + chrome.storage.local.set helpPageData: commandGroups + # An ordered listing of all available commands, grouped by type. This is the order they will # be shown in the help page. commandGroups: diff --git a/background_scripts/main.coffee b/background_scripts/main.coffee index e57e061d..8f99cf3e 100644 --- a/background_scripts/main.coffee +++ b/background_scripts/main.coffee @@ -80,56 +80,6 @@ onURLChange = (details) -> chrome.webNavigation.onHistoryStateUpdated.addListener onURLChange # history.pushState. chrome.webNavigation.onReferenceFragmentUpdated.addListener onURLChange # Hash changed. -# Retrieves the help dialog HTML template from a file, and populates it with the latest keybindings. -getHelpDialogHtml = ({showUnboundCommands, showCommandNames, customTitle}) -> - commandsToKey = {} - for own key of Commands.keyToCommandRegistry - command = Commands.keyToCommandRegistry[key].command - commandsToKey[command] = (commandsToKey[command] || []).concat(key) - - replacementStrings = - version: Utils.getCurrentVersion() - title: customTitle || "Help" - tip: if showCommandNames then "Tip: click command names to yank them to the clipboard." else " " - - for own group of Commands.commandGroups - replacementStrings[group] = - helpDialogHtmlForCommandGroup(group, commandsToKey, Commands.availableCommands, - showUnboundCommands, showCommandNames) - - replacementStrings - -# -# Generates HTML for a given set of commands. commandGroups are defined in commands.js -# -helpDialogHtmlForCommandGroup = (group, commandsToKey, availableCommands, - showUnboundCommands, showCommandNames) -> - html = [] - for command in Commands.commandGroups[group] - keys = commandsToKey[command] || [] - bindings = ("<span class='vimiumHelpDialogKey'>#{Utils.escapeHtml key}</span>" for key in keys).join ", " - if (showUnboundCommands || commandsToKey[command]) - isAdvanced = Commands.advancedCommands.indexOf(command) >= 0 - description = availableCommands[command].description - if keys.join(", ").length < 12 - helpDialogHtmlForCommand html, isAdvanced, bindings, description, showCommandNames, command - else - # If the length of the bindings is too long, then we display the bindings on a separate row from the - # description. This prevents the column alignment from becoming out of whack. - helpDialogHtmlForCommand html, isAdvanced, bindings, "", false, "" - helpDialogHtmlForCommand html, isAdvanced, "", description, showCommandNames, command - html.join("\n") - -helpDialogHtmlForCommand = (html, isAdvanced, bindings, description, showCommandNames, command) -> - html.push "<tr class='vimiumReset #{"advanced" if isAdvanced}'>" - if description - html.push "<td class='vimiumReset'>#{bindings}</td>" - html.push "<td class='vimiumReset'></td><td class='vimiumReset vimiumHelpDescription'>", description - html.push("(<span class='vimiumReset commandName'>#{command}</span>)") if showCommandNames - else - html.push "<td class='vimiumReset' colspan='3' style='text-align: left;'>", bindings - html.push("</td></tr>") - # Cache "content_scripts/vimium.css" in chrome.storage.local for UI components. do -> req = new XMLHttpRequest() @@ -429,7 +379,6 @@ portHandlers = sendRequestHandlers = runBackgroundCommand: (request) -> BackgroundCommands[request.registryEntry.command] request - getHelpDialogHtml: getHelpDialogHtml # getCurrentTabUrl is used by the content scripts to get their full URL, because window.location cannot help # with Chrome-specific URLs like "view-source:http:..". getCurrentTabUrl: ({tab}) -> tab.url |
