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 | 
