Module: Margin::Parser

Defined in:
lib/margin/parser.rb

Overview

Notes:

  • The parser requires a trailing newline at the end of the last item.

  • Per the spec: leading and trailing dashes, colons, asterisks, chevrons, underscores and whitespaces, as well as blank lines, are ignored.

Defined Under Namespace

Modules: LineMethods Classes: Line

Constant Summary collapse

IGNORED_CHARACTERS =
/[\ \-\*:><_]/
LINE_DECORATION =
/#{IGNORED_CHARACTERS}*/
EMPTY_LINE =
/^#{IGNORED_CHARACTERS}*\n/
TASK_START =
/^\[.\]\ /
ANNOTATION_ONLY =
/^\[.*\]$/

Class Method Summary collapse

Class Method Details

.parse(text) ⇒ Object



137
138
139
140
141
142
143
144
145
146
# File 'lib/margin/parser.rb', line 137

def parse(text)
  s = StringScanner.new(text)
  lines = []
  until s.eos?
    raw = s.scan_until(/\n/)&.chomp
    break if raw.nil? # probably should handle this with a custom error
    lines << Line.new(raw) unless raw.match? (/^#{IGNORED_CHARACTERS}*$/)
  end
  parse_items Item.root, lines
end

.parse_items(parent, lines) ⇒ Object



148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/margin/parser.rb', line 148

def parse_items(parent, lines)
  return parent if !lines.any?
  while this_line = lines.shift do
    this_item = nil

    # handle this line
    case this_line.type
    when :item, :task
      this_item = Item.from_line(this_line)
      parent.children << this_item
    when :annotation
      parent.annotations += this_line.annotations
    else
      raise TypeError, "Unknown line type: `#{this_line.type}`"
    end
    
    break if this_item.nil?
    break if lines.empty?
    
    # now look ahead to decide what to do next
    next_line = lines.first
    parse_items(this_item, lines) if next_line.offset > this_line.offset
    break if next_line.offset < this_line.offset
  end
  parent
end