Class: TodoDay

Inherits:
Object
  • Object
show all
Defined in:
lib/rodo/rodolib.rb

Overview

Encapsulate a single date of todo information

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(lines) ⇒ TodoDay

Returns a new instance of TodoDay.



252
253
254
255
256
257
258
259
# 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

Instance Attribute Details

#dateObject

Returns the value of attribute date.



249
250
251
# File 'lib/rodo/rodolib.rb', line 249

def date
  @date
end

#linesObject

Returns the value of attribute lines.



250
251
252
# File 'lib/rodo/rodolib.rb', line 250

def lines
  @lines
end

Class Method Details

.merge_structures(target, source) ⇒ Object

Merge alls entries from source into target



365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
# 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

.structure_reindex(structure, index = 0) ⇒ Object

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



413
414
415
416
417
418
419
# 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) ⇒ Object



403
404
405
406
407
408
409
410
# 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

Instance Method Details

#closeObject



332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
# 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_nameObject



261
262
263
264
# 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) ⇒ Object

Returns the number of leading spaces of the given line



286
287
288
289
290
# 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) ⇒ Object



270
271
272
273
274
275
276
277
278
279
280
281
282
283
# 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) ⇒ Object



421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
# 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) ⇒ Object

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



294
295
296
297
298
299
300
301
302
303
304
305
306
# 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

#structureObject

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

“text”, children: […], …

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



311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
# 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_sObject



266
267
268
# File 'lib/rodo/rodolib.rb', line 266

def to_s
  lines.join("\n").rstrip
end