class TodoDay

Encapsulate a single date of todo information

Attributes

date[RW]
lines[RW]

Public Class Methods

merge_structures(target, source) click to toggle source

Merge alls entries from source into target

# File lib/rodo/rodolib.rb, line 365
def self.merge_structures(target, source)
  # Attempt 1.3:
  to_prepend = []
  source.each { |new_block|
    existing_block_index = target.find_index { |existing_block|
      new_block != nil && existing_block != nil && new_block[:text] != "" && new_block[:text] == existing_block[:text]
    }

    if existing_block_index
      existing_block = target[existing_block_index]

      # Insert everything in the to_prepend queue at the given position...

      # ... but merge whitespace now
      whitespace_check_index = existing_block_index - 1
      while whitespace_check_index >=0 && to_prepend.size > 0 && to_prepend[0][:text] == "" && target[whitespace_check_index][:text] = ""
        to_prepend.shift
        whitespace_check_index -= 1
      end

      target.insert(existing_block_index, *to_prepend)

      # Start queue from scratch
      to_prepend = []
      merge_structures(existing_block[:children], new_block[:children])
    else
      to_prepend << new_block.dup
    end
  }
  # Everything that couldn't be matched, goes to the end
  # TODO Whitespace merging
  target.concat(to_prepend)

  TodoDay::structure_reindex(target)

  return target
end
new(lines) click to toggle source
# File lib/rodo/rodolib.rb, line 252
def initialize(lines)
  self.lines = lines

  if lines.size > 0 && lines[0] =~ /^\s*\#\s*(\d\d\d\d-\d\d-\d\d)/
    self.date = Date.parse($1)
    raise "Date couldn't be parsed on line #{lines[0]}" if self.date == nil
  end
end
structure_reindex(structure, index = 0) click to toggle source

Will traverse the given structure and update all indices to be in increasing order

# File lib/rodo/rodolib.rb, line 413
def self.structure_reindex(structure, index = 0)
  structure.each { |block|
    block[:index] = index
    index = structure_reindex(block[:children], index + 1)
  }
  return index
end
structure_to_a(structure) click to toggle source
# File lib/rodo/rodolib.rb, line 403
def self.structure_to_a(structure)
  result = []
  structure.each { |block|
    result << block[:text]
    result.concat(structure_to_a(block[:children]))
  }
  return result
end

Public Instance Methods

close() click to toggle source
# File lib/rodo/rodolib.rb, line 332
def close

  unfinished_lines = []
  lines.each { |line|
    if line =~ /^\s*(-\s+)?\[(.)\]/

      if $2 == " "
        unfinished_lines << line.dup
        line.sub!(/\[\s\]/, "[>]")
      end

    # Copy structure:
    elsif !(line =~ /^\s*[-*]\s+/ || line =~ /^\s*#\s/)
      unfinished_lines << line.dup
    end
  }

  if unfinished_lines[0] =~ /^\s*\#\s*(\d\d\d\d-\d\d-\d\d)/
    unfinished_lines.shift
  end

  # When closing on the same day: append hour and minutes
  newDate = "# #{Time.now.strftime("%Y-%m-%d %a")}"
  if lines.size > 0 && lines[0].start_with?(newDate)
    newDate = "# #{Time.now.strftime("%Y-%m-%d %a %H:%M")}"
  end

  return TodoDay.new([newDate, *unfinished_lines])

end
date_name() click to toggle source
# File lib/rodo/rodolib.rb, line 261
def date_name
  return date.strftime("%Y-%m-%d") if date
  return "undefined"
end
indent_depth(line_index) click to toggle source

Returns the number of leading spaces of the given line

# File lib/rodo/rodolib.rb, line 286
def indent_depth(line_index)
  return nil if !lines[line_index] || lines[line_index].strip.length == 0

  lines[line_index][/\A\s*/].length
end
line_prototype(line_index) click to toggle source
# File lib/rodo/rodolib.rb, line 270
def line_prototype(line_index)
  line = lines[line_index]
  if /^(?<lead>\s+[*-])(?<option>\s\[.\]\s?)?(?<rest>.*?)$/ =~ line
    if option =~ /^\s\[.\]/
      option = " [ ]"
    end
  else
    lead = " -"
    option = " [ ]"
  end

  option = "" if !option
  return lead + option.rstrip + " "
end
merge_lines(lines_to_append) click to toggle source
# File lib/rodo/rodolib.rb, line 421
def merge_lines(lines_to_append)

  return if lines_to_append.empty?

  end_lines = []
  end_lines << lines.pop while lines.last.strip.size == 0

  my_structure = structure
  ap_structure = TodoDay.new(lines_to_append).structure

  TodoDay::merge_structures(my_structure, ap_structure)

  @lines = TodoDay::structure_to_a(my_structure)

  lines.concat(end_lines)
end
parent_index(line_index) click to toggle source

Returns the line index of the parent line if any or nil The parent line is the line with a reduced indentation or the section header in case there no reduced indented line

# File lib/rodo/rodolib.rb, line 294
def parent_index(line_index)
  j = line_index - 1
  my_indent = indent_depth(line_index)
  return nil if !my_indent
  while j > 0 # Day header does not count as parent
    other_indent = indent_depth(j)
    if other_indent && other_indent < my_indent
      return j
    end
    j -= 1
  end
  return nil
end
structure() click to toggle source

Turns the linear list of lines of this TodoDay into a nested structure of the form

{text: “text”, children: […]}, …

where … is the same hash structure {text: “text”, children: […]}

# File lib/rodo/rodolib.rb, line 311
def structure

  indents = [nil] * lines.size
  (lines.size - 1).downto(0).each { |i|
    indents[i] = indent_depth(i) || (i+1 < indents.size ? indents[i+1] : 0)
  }

  stack = [{depth: -1, children: []}]
  lines.each_with_index { |s, i|
    indent = indents[i]
    new_child = {depth: indent, text: s, index: i, children: []}
    while indent <= stack.last[:depth]
      stack.pop
    end
    stack.last[:children] << new_child
    stack << new_child
  }

  return stack.first[:children]
end
to_s() click to toggle source
# File lib/rodo/rodolib.rb, line 266
def to_s
  lines.join("\n").rstrip
end