Module: RedQuilt::Indentation

Defined in:
lib/red_quilt/indentation.rb

Overview

Stateless CommonMark indentation / column arithmetic, shared by the block parser and its collaborator parsers (List, Blockquote, Footnote). Tabs expand to the next multiple of 4 columns.

Class Method Summary collapse

Class Method Details

.leading_columns(text) ⇒ Object

Leading-whitespace width of ‘text` in columns (tabs expanded to the next tab stop of 4).



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/red_quilt/indentation.rb', line 12

def leading_columns(text)
  col = 0
  i = 0
  bytes = text.bytesize
  while i < bytes
    b = text.getbyte(i)
    if b == 0x20
      col += 1
    elsif b == 0x09
      col = ((col / 4) + 1) * 4
    else
      break
    end
    i += 1
  end
  col
end

.leading_ws_bytes(text) ⇒ Object

Bytes of literal leading 0x20 / 0x09 in ‘text`.



96
97
98
99
100
101
102
103
104
105
106
# File 'lib/red_quilt/indentation.rb', line 96

def leading_ws_bytes(text)
  i = 0
  bytes = text.bytesize
  while i < bytes
    b = text.getbyte(i)
    break unless b == 0x20 || b == 0x09

    i += 1
  end
  i
end

.strip_columns(text, n) ⇒ Object

Strips up to ‘n` columns of leading whitespace from `text` and returns the rest. Leading whitespace is normalised to spaces in the returned string so subsequent strips compose correctly regardless of where they land relative to the original tab stops.



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/red_quilt/indentation.rb', line 34

def strip_columns(text, n)
  return text if n <= 0

  col = 0
  i = 0
  bytes = text.bytesize
  while i < bytes
    b = text.getbyte(i)
    if b == 0x20
      col += 1
    elsif b == 0x09
      col = ((col / 4) + 1) * 4
    else
      break
    end
    i += 1
  end
  # text[0...i] is all leading whitespace representing `col` cols.
  if n >= col
    i.zero? ? text : text.byteslice(i..)
  else
    # Keep the unstripped portion as a run of spaces.
    (" " * (col - n)) + text.byteslice(i..)
  end
end

.strip_leading_spaces(text, max) ⇒ Object

Strips up to ‘max` leading 0x20 (space) bytes from `text`, returning the rest. Unlike #strip_columns this is a plain byte strip (tabs are not expanded); used where the spec counts literal spaces, e.g. a fenced code block stripping its own opening indent. No-alloc return when `text` already starts at a non-space byte.



65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/red_quilt/indentation.rb', line 65

def strip_leading_spaces(text, max)
  return text if max <= 0

  bytes = text.bytesize
  i = 0
  while i < max && i < bytes && text.getbyte(i) == 0x20
    i += 1
  end
  return text if i.zero?

  text.byteslice(i..)
end

.strip_leading_whitespace(text) ⇒ Object

Strips all leading 0x20 / 0x09 bytes from ‘text` (spaces and tabs, no column cap). Same no-alloc return as #strip_leading_spaces when `text` already starts at a non-whitespace byte.



81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/red_quilt/indentation.rb', line 81

def strip_leading_whitespace(text)
  bytes = text.bytesize
  i = 0
  while i < bytes
    b = text.getbyte(i)
    break unless b == 0x20 || b == 0x09

    i += 1
  end
  return text if i.zero?

  text.byteslice(i..)
end