Module: Rvim::MatchMotion

Defined in:
lib/rvim/match_motion.rb

Constant Summary collapse

OPEN_TO_CLOSE =
{ '(' => ')', '[' => ']', '{' => '}' }.freeze
CLOSE_TO_OPEN =
OPEN_TO_CLOSE.invert.freeze
BRACKETS =
(OPEN_TO_CLOSE.keys + OPEN_TO_CLOSE.values).freeze

Class Method Summary collapse

Class Method Details

.locate_starting_bracket(line, byte_pointer) ⇒ Object



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/rvim/match_motion.rb', line 27

def self.locate_starting_bracket(line, byte_pointer)
  return nil if line.empty?

  pos = byte_pointer.clamp(0, line.bytesize - 1)
  ch = line.byteslice(pos, 1)
  return pos if BRACKETS.include?(ch)

  i = pos
  while i < line.bytesize
    c = line.byteslice(i, 1)
    return i if BRACKETS.include?(c)

    i += 1
  end
  nil
end

.match_at(buffer_of_lines, line_index, byte_pointer) ⇒ Object

Returns [target_line, target_byte] or nil. The starting bracket is the bracket at (line_index, byte_pointer); if not on a bracket, scans forward on the current line to find the first one (vim semantics).



12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/rvim/match_motion.rb', line 12

def self.match_at(buffer_of_lines, line_index, byte_pointer)
  line = buffer_of_lines[line_index]
  return nil unless line

  start_byte = locate_starting_bracket(line, byte_pointer)
  return nil unless start_byte

  ch = line.byteslice(start_byte, 1)
  if OPEN_TO_CLOSE.key?(ch)
    scan_forward(buffer_of_lines, line_index, start_byte, ch, OPEN_TO_CLOSE[ch])
  elsif CLOSE_TO_OPEN.key?(ch)
    scan_backward(buffer_of_lines, line_index, start_byte, CLOSE_TO_OPEN[ch], ch)
  end
end

.scan_backward(buffer_of_lines, line_index, start_byte, open_ch, close_ch) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/rvim/match_motion.rb', line 69

def self.scan_backward(buffer_of_lines, line_index, start_byte, open_ch, close_ch)
  depth = 1
  li = line_index
  bp = start_byte - 1
  while li >= 0
    line = buffer_of_lines[li]
    while bp >= 0
      c = line.byteslice(bp, 1)
      if c == close_ch
        depth += 1
      elsif c == open_ch
        depth -= 1
        return [li, bp] if depth.zero?
      end
      bp -= 1
    end
    li -= 1
    bp = li >= 0 ? buffer_of_lines[li].bytesize - 1 : -1
  end
  nil
end

.scan_forward(buffer_of_lines, line_index, start_byte, open_ch, close_ch) ⇒ Object

‘open_ch` is the bracket we started on; `close_ch` is its match. Walking forward, depth starts at 1 (we counted the start). When it returns to 0 we found the match.



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/rvim/match_motion.rb', line 47

def self.scan_forward(buffer_of_lines, line_index, start_byte, open_ch, close_ch)
  depth = 1
  li = line_index
  bp = start_byte + 1
  while li < buffer_of_lines.size
    line = buffer_of_lines[li]
    while bp < line.bytesize
      c = line.byteslice(bp, 1)
      if c == open_ch
        depth += 1
      elsif c == close_ch
        depth -= 1
        return [li, bp] if depth.zero?
      end
      bp += 1
    end
    li += 1
    bp = 0
  end
  nil
end