diff options
| -rw-r--r-- | content_scripts/mode_visual_edit.coffee | 92 |
1 files changed, 69 insertions, 23 deletions
diff --git a/content_scripts/mode_visual_edit.coffee b/content_scripts/mode_visual_edit.coffee index 3a8f5839..ec244895 100644 --- a/content_scripts/mode_visual_edit.coffee +++ b/content_scripts/mode_visual_edit.coffee @@ -1,18 +1,21 @@ -# This prevents unmapped printable characters from being passed through to underlying page. +# This prevents printable characters from being passed through to underlying page. It should, however, allow +# through chrome keyboard shortcuts. It's a backstop for all of the modes following. class SuppressPrintable extends Mode constructor: (options) -> handler = (event) => if KeyboardUtils.isPrintable event if event.type == "keydown" - DomUtils. suppressPropagation + DomUtils.suppressPropagation @stopBubblingAndTrue else @suppressEvent else @stopBubblingAndTrue + # This is pushed onto the handler stack before calling super(). Therefore, it ends up underneath (or + # after) all of the other handlers associated with the mode. @suppressPrintableHandlerId = handlerStack.push _name: "movement/suppress-printable" keydown: handler @@ -22,38 +25,80 @@ class SuppressPrintable extends Mode super options @onExit => handlerStack.remove @suppressPrintableHandlerId -# This watches keyboard events, and maintains @countPrefix as count-prefic and other keys are pressed. +# This watches keyboard events and maintains @countPrefix as count and other keys are pressed. class MaintainCount extends SuppressPrintable constructor: (options) -> @countPrefix = "" super options - isNumberKey = (keyChar) -> - keyChar and keyChar.length == 1 and "0" <= keyChar <= "9" - @push _name: "movement/maintain-count" keypress: (event) => @alwaysContinueBubbling => unless event.metaKey or event.ctrlKey or event.altKey keyChar = String.fromCharCode event.charCode - @countPrefix = if isNumberKey keyChar then @countPrefix + keyChar else "" + @countPrefix = + if keyChar and keyChar.length == 1 and "0" <= keyChar <= "9" + @countPrefix + keyChar + else + "" - countPrefixTimes: (func) -> - countPrefix = if 0 < @countPrefix.length then parseInt @countPrefix else 1 - @countPrefix = "" - func() for [0...countPrefix] + runCountPrefixTimes: (func) -> + count = if 0 < @countPrefix.length then parseInt @countPrefix else 1 + func() for [0...count] # This implements movement commands with count prefixes (using MaintainCount) for visual and edit modes. class Movement extends MaintainCount - movements: - h: "backward character" - l: "forward character" - k: "backward line" - j: "forward line" - b: "backward word" - e: "forward word" + # Get the direction of the selection, either "forward" or "backward". + # FIXME(smblott). There has to be a better way! + getDirection: (selection) -> + length = selection.toString().length + # Try to move the selection forward, then check whether it got bigger or smaller (then restore it). + selection.modify "extend", "forward", "character" + if length != selection.toString().length + direction = if selection.toString().length < length then "backward" else "forward" + selection.modify "extend", "backward", "character" + direction + else + # If we can't move forward, we could be at the end of the document, so try moving backward instead. + selection.modify "extend", "backward", "character" + if length != selection.toString().length + direction = if selection.toString().length < length then "forward" else "backward" + selection.modify "extend", "forward", "character" + direction + else + # Surely one of those has to work. What now? + "unknown" + + movements: + "l": "forward character" + "h": "backward character" + "j": "forward line" + "k": "backward line" + "e": "forward word" + "b": "backward word" + ")": "forward sentence" + "(": "backward sentence" + "}": "forward paragraph" + "{": "backward paragraph" + "$": "forward lineboundary" + "0": "backward lineboundary" + "G": "forward documentboundary" + "g": "backward documentboundary" + + "o": -> + selection = window.getSelection() + length = selection.toString().length + switch @getDirection selection + when "forward" + selection.collapseToEnd() + selection.modify "extend", "backward", "character" for [0...length] + when "backward" + selection.collapseToStart() + selection.modify "extend", "forward", "character" for [0...length] + + # TODO(smblott). What do we do if there is no initial selection? Or multiple ranges? constructor: (options) -> @alterMethod = options.alterMethod || "extend" super options @@ -65,11 +110,12 @@ class Movement extends MaintainCount unless event.metaKey or event.ctrlKey or event.altKey keyChar = String.fromCharCode event.charCode if @movements[keyChar] - @countPrefixTimes => - if "string" == typeof @movements[keyChar] - window.getSelection().modify @alterMethod, @movements[keyChar].split(/\s+/)... - else if "function" == typeof @movements[keyChar] - @movements[keyChar]() + @runCountPrefixTimes => + switch typeof @movements[keyChar] + when "string" + window.getSelection().modify @alterMethod, @movements[keyChar].split(" ")... + when "function" + @movements[keyChar].call @ class VisualMode extends Movement constructor: (options = {}) -> |
