Module: Rvim::TextMotion

Defined in:
lib/rvim/text_motion.rb

Constant Summary collapse

SENTENCE_END =
/[.!?]/.freeze

Class Method Summary collapse

Class Method Details

.advance_to_first_nonblank(buffer, line_index, byte_pointer) ⇒ Object



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/rvim/text_motion.rb', line 75

def self.advance_to_first_nonblank(buffer, line_index, byte_pointer)
  li = line_index
  bp = byte_pointer
  while li < buffer.size
    line = buffer[li] || ''
    while bp < line.bytesize && line.byteslice(bp, 1) =~ /\s/
      bp += 1
    end
    return [li, bp] if bp < line.bytesize

    li += 1
    bp = 0
  end
  [buffer.size - 1, 0]
end

.blank?(line) ⇒ Boolean

Returns:

  • (Boolean)


118
119
120
# File 'lib/rvim/text_motion.rb', line 118

def self.blank?(line)
  line.nil? || line.to_s.strip.empty?
end

.next_paragraph(buffer, line_index) ⇒ Object

Next blank line at or below line_index+1, or the last line if none.



92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/rvim/text_motion.rb', line 92

def self.next_paragraph(buffer, line_index)
  return 0 if buffer.empty?

  li = line_index + 1
  # Skip remaining non-blank lines after current.
  while li < buffer.size
    return li if blank?(buffer[li])

    li += 1
  end
  buffer.size - 1
end

.next_sentence(buffer, line_index, byte_pointer) ⇒ Object

Returns [line, byte] of the next sentence start. EOF clamps to end of last line. Returns nil only for an empty buffer.



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/rvim/text_motion.rb', line 9

def self.next_sentence(buffer, line_index, byte_pointer)
  return nil if buffer.empty?

  li = line_index
  bp = byte_pointer
  while li < buffer.size
    line = buffer[li] || ''
    # Find next sentence-end punctuation strictly after bp.
    i = bp
    while i < line.bytesize
      c = line.byteslice(i, 1)
      if c =~ SENTENCE_END
        j = i + 1
        j += 1 while j < line.bytesize && line.byteslice(j, 1) =~ /\s/
        if j < line.bytesize
          return [li, j]
        else
          # Skip to next non-blank line/byte.
          ni = li + 1
          while ni < buffer.size
            nl = buffer[ni] || ''
            k = 0
            k += 1 while k < nl.bytesize && nl.byteslice(k, 1) =~ /\s/
            return [ni, k] if k < nl.bytesize

            ni += 1
          end
          return [buffer.size - 1, [(buffer[-1] || '').bytesize - 1, 0].max]
        end
      end
      i += 1
    end
    li += 1
    bp = 0
  end
  [buffer.size - 1, [(buffer[-1] || '').bytesize - 1, 0].max]
end

.prev_paragraph(buffer, line_index) ⇒ Object

Previous blank line above, or line 0 if none.



106
107
108
109
110
111
112
113
114
115
116
# File 'lib/rvim/text_motion.rb', line 106

def self.prev_paragraph(buffer, line_index)
  return 0 if buffer.empty?

  li = line_index - 1
  while li >= 0
    return li if blank?(buffer[li])

    li -= 1
  end
  0
end

.prev_sentence(buffer, line_index, byte_pointer) ⇒ Object



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/rvim/text_motion.rb', line 47

def self.prev_sentence(buffer, line_index, byte_pointer)
  return nil if buffer.empty?

  # Walk backward; find the previous sentence-end punctuation strictly
  # before the cursor. The sentence-start we want is the first non-blank
  # AFTER that punctuation. If no punctuation found, jump to (0, first
  # non-blank).
  li = line_index
  bp = byte_pointer - 1
  while li >= 0
    line = buffer[li] || ''
    bp = line.bytesize - 1 if bp >= line.bytesize
    while bp >= 0
      c = line.byteslice(bp, 1)
      if c =~ SENTENCE_END
        # Sentence start = first non-blank after this punctuation.
        return advance_to_first_nonblank(buffer, li, bp + 1)
      end
      bp -= 1
    end
    li -= 1
    bp = li >= 0 ? (buffer[li] || '').bytesize - 1 : -1
  end

  # No prior sentence — jump to first non-blank in buffer.
  advance_to_first_nonblank(buffer, 0, 0)
end