Class: Rvim::Keymap

Inherits:
Object
  • Object
show all
Defined in:
lib/rvim/keymap.rb

Defined Under Namespace

Classes: Mapping

Constant Summary collapse

MODES =
%i[normal visual insert op_pending cmdline].freeze
MAP_MODES =
%i[normal visual op_pending].freeze
BANG_MODES =
%i[insert cmdline].freeze
REVERSE_TAGS =
{
  "\r" => '<CR>',
  "\e" => '<Esc>',
  "\t" => '<Tab>',
  "\x7f" => '<BS>',
  "\n" => '<NL>',
  "\x00" => '<Nul>',
  "\e[A" => '<Up>',
  "\e[B" => '<Down>',
  "\e[C" => '<Right>',
  "\e[D" => '<Left>',
  "\e[H" => '<Home>',
  "\e[F" => '<End>',
  "\e[5~" => '<PageUp>',
  "\e[6~" => '<PageDown>',
  "\e[2~" => '<Insert>',
  "\e[3~" => '<Delete>',
}.freeze
REVERSE_KEYS_LONG_FIRST =
REVERSE_TAGS.keys.sort_by { |k| -k.bytesize }.freeze
MODES_FOR_VERB =
{
  map: MAP_MODES,
  noremap: MAP_MODES,
  nmap: %i[normal],
  nnoremap: %i[normal],
  vmap: %i[visual],
  vnoremap: %i[visual],
  imap: %i[insert],
  inoremap: %i[insert],
  omap: %i[op_pending],
  onoremap: %i[op_pending],
  cmap: %i[cmdline],
  cnoremap: %i[cmdline],
  unmap: MAP_MODES,
  nunmap: %i[normal],
  vunmap: %i[visual],
  iunmap: %i[insert],
  ounmap: %i[op_pending],
  cunmap: %i[cmdline],
  mapclear: MAP_MODES,
  nmapclear: %i[normal],
  vmapclear: %i[visual],
  imapclear: %i[insert],
  omapclear: %i[op_pending],
  cmapclear: %i[cmdline],
}.freeze
BANG_VERBS =
%i[map noremap unmap mapclear].freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeKeymap

Returns a new instance of Keymap.



12
13
14
# File 'lib/rvim/keymap.rb', line 12

def initialize
  @table = MODES.each_with_object({}) { |m, h| h[m] = {} }
end

Class Method Details

.expand(str, leader: '\\') ⇒ Object



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/rvim/keymap.rb', line 49

def self.expand(str, leader: '\\')
  out = +''
  i = 0
  while i < str.length
    if str[i] == '<' && (close = str.index('>', i))
      tag = str[(i + 1)...close]
      out << expand_tag(tag, leader: leader)
      i = close + 1
    else
      out << str[i]
      i += 1
    end
  end
  out
end

.expand_tag(tag, leader: '\\') ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/rvim/keymap.rb', line 65

def self.expand_tag(tag, leader: '\\')
  case tag.downcase
  when 'cr', 'enter', 'return' then "\r"
  when 'esc' then "\e"
  when 'tab' then "\t"
  when 'space' then ' '
  when 'bs' then "\x7f"
  when 'lt' then '<'
  when 'gt' then '>'
  when 'nl', 'lf' then "\n"
  when 'nul' then "\x00"
  when 'up' then "\e[A"
  when 'down' then "\e[B"
  when 'right' then "\e[C"
  when 'left' then "\e[D"
  when 'home' then "\e[H"
  when 'end' then "\e[F"
  when 'pageup' then "\e[5~"
  when 'pagedown' then "\e[6~"
  when 'insert' then "\e[2~"
  when 'delete', 'del' then "\e[3~"
  when 'leader' then leader
  when 'f1' then "\eOP"
  when 'f2' then "\eOQ"
  when 'f3' then "\eOR"
  when 'f4' then "\eOS"
  when 'f5' then "\e[15~"
  when 'f6' then "\e[17~"
  when 'f7' then "\e[18~"
  when 'f8' then "\e[19~"
  when 'f9' then "\e[20~"
  when 'f10' then "\e[21~"
  when 'f11' then "\e[23~"
  when 'f12' then "\e[24~"
  when /\Ac-(.)\z/i
    ch = Regexp.last_match(1)
    (ch.upcase.ord & 0x1f).chr
  when /\As-(.)\z/i
    Regexp.last_match(1).upcase
  else
    "<#{tag}>"
  end
end

.mapclear?(verb) ⇒ Boolean

Returns:

  • (Boolean)


194
195
196
# File 'lib/rvim/keymap.rb', line 194

def self.mapclear?(verb)
  %i[mapclear nmapclear vmapclear imapclear omapclear cmapclear].include?(verb)
end

.modes_for(verb, bang: false) ⇒ Object



180
181
182
183
184
# File 'lib/rvim/keymap.rb', line 180

def self.modes_for(verb, bang: false)
  return BANG_MODES if bang && BANG_VERBS.include?(verb)

  MODES_FOR_VERB[verb]
end

.noremap?(verb) ⇒ Boolean

Returns:

  • (Boolean)


186
187
188
# File 'lib/rvim/keymap.rb', line 186

def self.noremap?(verb)
  %i[noremap nnoremap vnoremap inoremap onoremap cnoremap].include?(verb)
end

.render(str) ⇒ Object



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/rvim/keymap.rb', line 130

def self.render(str)
  out = +''
  i = 0
  while i < str.bytesize
    matched = REVERSE_KEYS_LONG_FIRST.find { |k| str.byteslice(i, k.bytesize) == k }
    if matched
      out << REVERSE_TAGS[matched]
      i += matched.bytesize
    else
      ch = str.byteslice(i, 1)
      if ch && ch.bytes.first < 0x20
        out << format('<C-%s>', (ch.bytes.first | 0x40).chr)
      else
        out << ch.to_s
      end
      i += 1
    end
  end
  out
end

.unmap?(verb) ⇒ Boolean

Returns:

  • (Boolean)


190
191
192
# File 'lib/rvim/keymap.rb', line 190

def self.unmap?(verb)
  %i[unmap nunmap vunmap iunmap ounmap cunmap].include?(verb)
end

Instance Method Details

#add(modes, lhs, rhs, recursive: true, silent: false, callback: nil) ⇒ Object



16
17
18
19
20
21
22
# File 'lib/rvim/keymap.rb', line 16

def add(modes, lhs, rhs, recursive: true, silent: false, callback: nil)
  Array(modes).each do |mode|
    next unless @table[mode]

    @table[mode][lhs] = Mapping.new(lhs: lhs, rhs: rhs, recursive: recursive, silent: silent, callback: callback)
  end
end

#clear(modes) ⇒ Object



28
29
30
# File 'lib/rvim/keymap.rb', line 28

def clear(modes)
  Array(modes).each { |mode| @table[mode]&.clear }
end

#each(mode) ⇒ Object



45
46
47
# File 'lib/rvim/keymap.rb', line 45

def each(mode)
  (@table[mode] || {}).each { |lhs, mapping| yield lhs, mapping }
end

#empty?(mode) ⇒ Boolean

Returns:

  • (Boolean)


41
42
43
# File 'lib/rvim/keymap.rb', line 41

def empty?(mode)
  (@table[mode] || {}).empty?
end

#lookup(mode, pending) ⇒ Object



32
33
34
35
36
37
38
39
# File 'lib/rvim/keymap.rb', line 32

def lookup(mode, pending)
  table = @table[mode] || {}
  exact = table[pending]
  return [:exact, exact] if exact
  return [:prefix, nil] if table.keys.any? { |lhs| lhs.start_with?(pending) && lhs != pending }

  [:none, nil]
end

#remove(modes, lhs) ⇒ Object



24
25
26
# File 'lib/rvim/keymap.rb', line 24

def remove(modes, lhs)
  Array(modes).each { |mode| @table[mode].delete(lhs) }
end