github.com/hoop33/elvish@v0.0.0-20160801152013-6d25485beab4/edit/key.go (about)

     1  package edit
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  )
     7  
     8  // Key represents a single keyboard input, typically assembled from a escape
     9  // sequence.
    10  type Key struct {
    11  	Rune rune
    12  	Mod  Mod
    13  }
    14  
    15  // Predefined special Key values.
    16  var (
    17  	// Default is used in the key binding table to indicate default binding.
    18  	Default = Key{DefaultBindingRune, 0}
    19  )
    20  
    21  // Mod represents a modifier key.
    22  type Mod byte
    23  
    24  // Values for Mod.
    25  const (
    26  	// Shift is the shift modifier. It is only applied to special keys (e.g.
    27  	// Shift-F1). For instance 'A' and '@' which are typically entered with the
    28  	// shift key pressed, are not considered to be shift-modified.
    29  	Shift Mod = 1 << iota
    30  	// Alt is the alt modifier, traditionally known as the meta modifier.
    31  	Alt
    32  	Ctrl
    33  )
    34  
    35  func (k Key) String() (s string) {
    36  	if k.Mod&Ctrl != 0 {
    37  		s += "Ctrl-"
    38  	}
    39  	if k.Mod&Alt != 0 {
    40  		s += "Alt-"
    41  	}
    42  	if k.Mod&Shift != 0 {
    43  		s += "Shift-"
    44  	}
    45  	if k.Rune > 0 {
    46  		if name, ok := keyNames[k.Rune]; ok {
    47  			s += name
    48  		} else {
    49  			s += string(k.Rune)
    50  		}
    51  	} else {
    52  		i := int(-k.Rune)
    53  		if i >= len(functionKeyNames) {
    54  			s += fmt.Sprintf("(bad function key %d)", i)
    55  		} else {
    56  			s += functionKeyNames[-k.Rune]
    57  		}
    58  	}
    59  	return
    60  }
    61  
    62  // modifierByName maps a name to an modifier. It is used for parsing keys where
    63  // the modifier string is first turned to lower case, so that all of C, c,
    64  // CTRL, Ctrl and ctrl can represent the Ctrl modifier.
    65  var modifierByName = map[string]Mod{
    66  	"s": Shift, "shift": Shift,
    67  	"a": Alt, "alt": Alt,
    68  	"m": Alt, "meta": Alt,
    69  	"c": Ctrl, "ctrl": Ctrl,
    70  }
    71  
    72  // parseKey parses a key. The syntax is:
    73  //
    74  // Key = { Mod ('+' | '-') } BareKey
    75  //
    76  // BareKey = FunctionKeyName | SingleRune
    77  func parseKey(s string) (Key, error) {
    78  	var k Key
    79  	// parse modifiers
    80  	for {
    81  		i := strings.IndexAny(s, "+-")
    82  		if i == -1 {
    83  			break
    84  		}
    85  		modname := strings.ToLower(s[:i])
    86  		mod, ok := modifierByName[modname]
    87  		if !ok {
    88  			return Key{}, fmt.Errorf("bad modifier: %q", modname)
    89  		}
    90  		k.Mod |= mod
    91  		s = s[i+1:]
    92  	}
    93  
    94  	if len(s) == 1 {
    95  		k.Rune = rune(s[0])
    96  		return k, nil
    97  	}
    98  
    99  	for r, name := range keyNames {
   100  		if s == name {
   101  			k.Rune = r
   102  			return k, nil
   103  		}
   104  	}
   105  
   106  	for i, name := range functionKeyNames[1:] {
   107  		if s == name {
   108  			k.Rune = rune(-i - 1)
   109  			return k, nil
   110  		}
   111  	}
   112  
   113  	return Key{}, fmt.Errorf("bad key: %q", s)
   114  }
   115  
   116  // Special negative runes to represent function keys, used in the Rune field of
   117  // the Key struct.
   118  const (
   119  	F1 rune = -iota - 1
   120  	F2
   121  	F3
   122  	F4
   123  	F5
   124  	F6
   125  	F7
   126  	F8
   127  	F9
   128  	F10
   129  	F11
   130  	F12
   131  
   132  	Up
   133  	Down
   134  	Right
   135  	Left
   136  
   137  	Home
   138  	Insert
   139  	Delete
   140  	End
   141  	PageUp
   142  	PageDown
   143  
   144  	DefaultBindingRune // A special value used in DefaultBinding
   145  
   146  	// Some function key names are just aliases for their ASCII representation
   147  
   148  	Tab       = '\t'
   149  	Enter     = '\n'
   150  	Backspace = 0x7f
   151  )
   152  
   153  var functionKeyNames = [...]string{
   154  	"(Invalid)",
   155  	"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12",
   156  	"Up", "Down", "Right", "Left",
   157  	"Home", "Insert", "Delete", "End", "PageUp", "PageDown", "default",
   158  }
   159  
   160  var keyNames = map[rune]string{
   161  	Tab: "Tab", Enter: "Enter", Backspace: "Backspace",
   162  }