todorb 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/todorb.rb CHANGED
@@ -4,7 +4,8 @@
4
4
  * Description: a command line todo list manager
5
5
  * Author: rkumar
6
6
  * Date: 2010-06-10 20:10
7
- * License: GPL
7
+ * License: Ruby License
8
+ * Now requires subcommand gem as of 2010-06-22 16:16
8
9
 
9
10
  =end
10
11
  require 'rubygems'
@@ -12,15 +13,17 @@ require 'rubygems'
12
13
  require 'common/colorconstants'
13
14
  require 'common/sed'
14
15
  require 'common/cmdapp'
16
+ require 'subcommand'
15
17
  include ColorConstants
16
18
  include Sed
17
19
  include Cmdapp
20
+ include Subcommands
18
21
 
19
22
  PRI_A = YELLOW + BOLD
20
23
  PRI_B = WHITE + BOLD
21
24
  PRI_C = GREEN + BOLD
22
25
  PRI_D = CYAN + BOLD
23
- VERSION = "2.0"
26
+ VERSION = "1.0.0"
24
27
  DATE = "2010-06-10"
25
28
  APPNAME = File.basename($0)
26
29
  AUTHOR = "rkumar"
@@ -59,7 +62,6 @@ class Todo
59
62
  def initialize options, argv
60
63
 
61
64
  @options = options
62
- @aliases = {}
63
65
  @argv = argv
64
66
  @file = options[:file]
65
67
  ## data is a 2 dim array: rows and fields. It contains each row of the file
@@ -86,29 +88,28 @@ class Todo
86
88
  $valid_array = false
87
89
  # menu MENU
88
90
  #@actions = %w[ list add pri priority depri tag del delete status redo note archive help]
89
- @actions = {}
90
- @actions["list"] = "List all tasks.\n\t --hide-numbering --renumber"
91
- @actions["listsub"] = "List all tasks.\n\t --hide-numbering --renumber"
92
- @actions["add"] = "Add a task. \n\t #{$APPNAME} add <TEXT>\n\t --component C --project P --priority X add <TEXT>"
93
- @actions["pri"] = "Add priority to task. \n\t #{$APPNAME} pri <ITEM> [A-Z]"
94
- @actions["priority"] = "Same as pri"
95
- @actions["depri"] = "Remove priority of task. \n\t #{$APPNAME} depri <ITEM>"
96
- @actions["delete"] = "Delete a task. \n\t #{$APPNAME} delete <ITEM>"
97
- @actions["del"] = "Same as delete"
98
- @actions["status"] = "Change the status of a task. \n\t #{$APPNAME} status <STAT> <ITEM>\n\t<STAT> are open closed started pending hold next"
99
- @actions["redo"] = "Renumbers the todo file starting 1"
100
- @actions["note"] = "Add a note to an item. \n\t #{$APPNAME} note <ITEM> <TEXT>"
101
- @actions["tag"] = "Add a tag to an item/s. \n\t #{$APPNAME} tag <ITEMS> <TEXT>"
102
- @actions["archive"] = "archive closed tasks to archive.txt"
103
- @actions["copyunder"] = "Move first item under second (as a subtask). aka cu"
104
-
105
- @actions["help"] = "Display help"
106
- @actions["addsub"] = "Add a task under another . \n\t #{$APPNAME} add <TEXT>\n\t --component C --project P --priority X add <TEXT>"
91
+ #@actions = {}
92
+ #@actions["list"] = "List all tasks.\n\t --hide-numbering --renumber"
93
+ #@actions["listsub"] = "List all tasks.\n\t --hide-numbering --renumber"
94
+ #@actions["add"] = "Add a task. \n\t #{$APPNAME} add <TEXT>\n\t --component C --project P --priority X add <TEXT>"
95
+ #@actions["pri"] = "Add priority to task. \n\t #{$APPNAME} pri <TASK> [A-Z]"
96
+ #@actions["priority"] = "Same as pri"
97
+ #@actions["depri"] = "Remove priority of task. \n\t #{$APPNAME} depri <TASK>"
98
+ #@actions["delete"] = "Delete a task. \n\t #{$APPNAME} delete <TASK>"
99
+ #@actions["del"] = "Same as delete"
100
+ #@actions["status"] = "Change the status of a task. \n\t #{$APPNAME} status <STAT> <TASK>\n\t<STAT> are open closed started pending hold next"
101
+ #@actions["redo"] = "Renumbers the todo file starting 1"
102
+ #@actions["note"] = "Add a note to an item. \n\t #{$APPNAME} note <TASK> <TEXT>"
103
+ #@actions["tag"] = "Add a tag to an item/s. \n\t #{$APPNAME} tag <TASK> <TEXT>"
104
+ #@actions["archive"] = "archive closed tasks to archive.txt"
105
+ #@actions["copyunder"] = "Move first item under second (as a subtask). aka cu"
106
+ #
107
+ #@actions["help"] = "Display help"
108
+ #@actions["addsub"] = "Add a task under another . \n\t #{$APPNAME} add <TEXT>\n\t --component C --project P --priority X add <TEXT>"
107
109
 
108
110
  # adding some sort of aliases so shortcuts can be defined
109
- @aliases["open"] = ["status","open"]
110
- @aliases["close"] = ["status","closed"]
111
- @aliases["cu"] = ["copyunder"]
111
+ #@aliases["open"] = ["status","open"]
112
+ #@aliases["close"] = ["status","closed"]
112
113
 
113
114
  @copying = false # used by copyunder when it calls addsub
114
115
  # TODO: config
@@ -147,8 +148,9 @@ class Todo
147
148
  ##
148
149
  # add a subtask
149
150
  # @param [Array] 1. item under which to place, 2. text
150
- # @return
151
- # @example:
151
+ # @return [0,1] success or fail
152
+ #
153
+ # @example
152
154
  # addsub 1 "A task"
153
155
  # => will get added as 1.1 or 1.2 etc
154
156
  # addsub 1.3 "a task"
@@ -232,16 +234,20 @@ class Todo
232
234
  @ctr = 0
233
235
  @total = 0
234
236
  #CSV.foreach(@file,:col_sep => "\t") do |row| # 1.9 2009-10-05 11:12
235
- File.open(@file).each do |line|
236
- row = line.chomp.split "\t"
237
- @total += 1
238
- if @options[:show_all]
239
- @data << row
240
- @ctr += 1
241
- else
242
- unless row[1] =~ /^\[x\]/
237
+ filelist = [@file]
238
+ filelist << @archive_path if @options[:show_arch]
239
+ filelist.each do |file|
240
+ File.open(file).each do |line|
241
+ row = line.chomp.split "\t"
242
+ @total += 1
243
+ if @options[:show_all]
243
244
  @data << row
244
245
  @ctr += 1
246
+ else
247
+ unless row[1] =~ /^\[x\]/
248
+ @data << row
249
+ @ctr += 1
250
+ end
245
251
  end
246
252
  end
247
253
  end
@@ -325,7 +331,8 @@ class Todo
325
331
  #string = "#{BLUE}#{string}#{CLEAR}"
326
332
  end
327
333
  else
328
- string = "#{NORMAL}#{string}#{CLEAR}"
334
+ #string = "#{NORMAL}#{string}#{CLEAR}"
335
+ # no need to put clear, let it be au natural
329
336
  end
330
337
  end # colorme
331
338
  ## since we've added notes, we convert C-a to newline with spaces
@@ -335,8 +342,15 @@ class Todo
335
342
  puts string
336
343
  end
337
344
  end
345
+ # internal method for sorting on reverse of line (status, priority)
338
346
  def sort
339
- @data.sort! { |a,b| b[1] <=> a[1] }
347
+ fold_subtasks
348
+ if @options[:reverse]
349
+ @data.sort! { |a,b| a[1] <=> b[1] }
350
+ else
351
+ @data.sort! { |a,b| b[1] <=> a[1] }
352
+ end
353
+ unfold_subtasks
340
354
  end
341
355
  def grep
342
356
  r = Regexp.new @options[:grep]
@@ -347,8 +361,8 @@ class Todo
347
361
  # Adds or changes priority for a task
348
362
  #
349
363
  # @param [Array] priority, single char A-Z, item or items
350
- # @return
351
- # @example:
364
+ # @return [0,1] success or fail
365
+ # @example
352
366
  # pri A 5 6 7
353
367
  # pri 5 6 7 A
354
368
  # -- NO LONGER this complicated system pri A 5 6 7 B 1 2 3
@@ -400,7 +414,7 @@ class Todo
400
414
  # Remove the priority of a task
401
415
  #
402
416
  # @param [Array] items to deprioritize
403
- # @return
417
+ # @return [0,1] success or fail
404
418
  def depri(args)
405
419
  change_items args, /\([A-Z]\) /,""
406
420
  end
@@ -409,7 +423,7 @@ class Todo
409
423
  # FIXME: check with subtasks
410
424
  #
411
425
  # @param [Array] items and tag, or tag and items
412
- # @return
426
+ # @return [0,1] success or fail
413
427
  def tag(args)
414
428
  tag, items = _separate args
415
429
  #change_items items do |item, row|
@@ -422,8 +436,7 @@ class Todo
422
436
  # deletes one or more items
423
437
  #
424
438
  # @param [Array, #include?] items to delete
425
- # @return
426
- # FIXME: if invalid item passed I have no way of giving error
439
+ # @return [0,1] success or fail
427
440
  public
428
441
  def delete(args)
429
442
  ctr = errors = 0
@@ -454,10 +467,24 @@ class Todo
454
467
  end
455
468
  end
456
469
  totalitems.each { |item|
470
+ # FIXME: TODO: if --force used then don'y prompt
457
471
  puts "#{item[0]} #{item[1]}"
458
- print "Do you wish to delete (Y/N): "
459
- STDOUT.flush
460
- ans = STDIN.gets.chomp
472
+ ans = nil
473
+ if @options[:force]
474
+ ans = "Y"
475
+ else
476
+ $stderr.print "Do you wish to delete (Y/N/A/q): "
477
+ STDOUT.flush
478
+ ans = STDIN.gets.chomp
479
+ # A means user specified ALL, don't keep asking
480
+ if ans =~ /[Aa]/
481
+ ans = "Y"
482
+ @options[:force] = true
483
+ elsif ans =~ /[qQ]/
484
+ $stderr.puts "Operation canceled. No tasks deleted."
485
+ exit 1
486
+ end
487
+ end
461
488
  if ans =~ /[Yy]/
462
489
  @data.delete item
463
490
  # put deleted row into deleted file, so one can undo
@@ -479,7 +506,7 @@ class Todo
479
506
  # Change status of given items
480
507
  #
481
508
  # @param [Array, #include?] items to change status of
482
- # @return [true, false] success or fail
509
+ # @return [0,1] success or fail
483
510
  public
484
511
  def status(args)
485
512
  stat, items = _separate args #, /^[a-zA-Z]/
@@ -530,7 +557,7 @@ class Todo
530
557
  end
531
558
  ##
532
559
  # Renumber while displaying
533
- # @return [true, false] success or fail
560
+ # @return [0,1] success or fail
534
561
  private
535
562
  def renumber
536
563
  ## this did not account for subtasks
@@ -556,7 +583,7 @@ class Todo
556
583
  # For given items, add a note
557
584
  #
558
585
  # @param [Array, #include?] items to add note to, note
559
- # @return [true, false] success or fail
586
+ # @return [0, 1] success or fail
560
587
  public
561
588
  def note(args)
562
589
  _backup
@@ -567,12 +594,13 @@ class Todo
567
594
  ret = row[1].sub!(/ (\([0-9]{4})/," #{indent}* #{text} "+'\1')
568
595
  ret
569
596
  end
597
+ 0
570
598
  end
571
599
  ##
572
- # Archive all items
600
+ # Archive all closed items
573
601
  #
574
602
  # @param none (ignored)
575
- # @return [true, false] success or fail
603
+ # @return [0, 1] success or fail
576
604
  public
577
605
  def archive(args=nil)
578
606
  filename = @archive_path
@@ -588,11 +616,12 @@ class Todo
588
616
  end
589
617
  file.close
590
618
  puts "Archived #{ctr} tasks."
619
+ 0
591
620
  end
592
621
  # Copy given item under second item
593
622
  #
594
623
  # @param [Array] 2 items, move first under second
595
- # @return [Boolean] success or fail
624
+ # @return [0,1] success or fail
596
625
  public
597
626
  def copyunder(args)
598
627
  if args.nil? or args.count != 2
@@ -616,8 +645,8 @@ class Todo
616
645
  # remove item number and status ?
617
646
  # give to addsub to add.
618
647
  # delete from
619
- delete_item from
620
- # take care of data in addsub (if existing, and also /
648
+ # The earlier todoapp.sh was not deleting, so we don't. We just copy
649
+ delete_item(from) if @options[:delete_old]
621
650
  end
622
651
  ##
623
652
  # Get row for given item or nil.
@@ -740,7 +769,7 @@ class Todo
740
769
  def regexp_item item
741
770
  Regexp.new("^ +#{item}#{@todo_delim}")
742
771
  end
743
- # @unused - wrote so i could use it refactoring - i should be using this TODO:
772
+ # unused - wrote so i could use it refactoring - i should be using this TODO:
744
773
  def extract_item line
745
774
  item = line.match(/^ *([0-9\.]+)/)
746
775
  return nil if item.nil?
@@ -749,6 +778,7 @@ class Todo
749
778
  ##
750
779
  # Redoes the numbering in the file.
751
780
  # Useful if the numbers have gone high and you want to start over.
781
+ # @return [0,1] success or fail
752
782
  def redo args
753
783
  #require 'fileutils'
754
784
  #FileUtils.cp @app_file_path, "#{@app_file_path}.org"
@@ -771,8 +801,9 @@ class Todo
771
801
  line.sub!(/[0-9]+\./, "#{ctr}.")
772
802
  end
773
803
  end
774
- _set_serial_number ctr
804
+ _set_serial_number ctr+1
775
805
  puts "Redone numbering"
806
+ 0
776
807
  end
777
808
  ##
778
809
  private
@@ -818,6 +849,46 @@ class Todo
818
849
  end
819
850
  ## [1, 2, 3, 3.1, 3.1.1, 3.2, 3.3 ... ], " 3.1.1\t[ ] some task"
820
851
 
852
+ def fold_subtasks
853
+ #load_array
854
+ prev = ""
855
+ newarray = []
856
+ # get the main item, avoid subitem
857
+ #item = line.match(/^ *([0-9\.]+)/)
858
+ rx = Regexp.new "^ *([0-9]+)"
859
+ @data.each { |row|
860
+ it = row[0].match(rx)
861
+ item = it[1]
862
+ if item == prev # append to prev line
863
+ #puts "item matches prev #{item} #{prev} "
864
+ x=newarray.last
865
+ x[1] << "#{row[0]}\t#{row[1]}"
866
+ else
867
+ #puts "no match item matches prev #{row[0]}: #{prev} "
868
+ newarray << row
869
+ end
870
+ prev = item
871
+ }
872
+ #newarray.each { |row| puts "#{row[0]} #{row[1]}" }
873
+ @data = newarray
874
+ end
875
+ def unfold_subtasks
876
+ newarray = []
877
+ # get the main item, avoid subitem
878
+ #item = line.match(/^ *([0-9\.]+)/)
879
+ @data.each { |row|
880
+ if row[1] =~ //
881
+ #puts "row #{row[0]} contains ^B"
882
+ line = row.join "\t"
883
+ lines = line.split //
884
+ #puts " #{lines.count} lines "
885
+ lines.each { |e| newarray << e.split("\t") }
886
+ else
887
+ newarray << row
888
+ end
889
+ }
890
+ @data = newarray
891
+ end
821
892
  def self.main args
822
893
  ret = nil
823
894
  begin
@@ -836,103 +907,197 @@ class Todo
836
907
  options[:colorize] = (plain == "0") ? false:true
837
908
  end
838
909
 
839
- OptionParser.new do |opts|
840
- opts.banner = "Usage: #{$APPNAME} [options] action"
841
-
842
- opts.separator ""
843
- opts.separator "Options for list and add:"
844
-
845
- opts.on("-P", "--project PROJECTNAME", "name of project for add or list") { |v|
846
- options[:project] = v
847
- options[:filter] = true
848
- }
849
- opts.on("-p", "--priority A-Z", "priority code for add or list") { |v|
850
- options[:priority] = v
851
- options[:filter] = true
852
- }
853
- opts.on("-C", "--component COMPONENT", "component name for add or list") { |v|
854
- options[:component] = v
855
- options[:filter] = true
856
- }
857
- opts.separator ""
858
- opts.separator "Specific options:"
859
- opts.on("--force", "force delete or add without prompting") do |v|
860
- options[:force] = v
861
- end
862
- opts.on("--recursive", "operate on subtasks also for delete, status") do |v|
863
- options[:recursive] = v
864
- end
865
- opts.separator ""
866
- opts.separator "List options:"
867
-
868
- opts.on("--[no-]color", "--[no-]colors", "colorize listing") do |v|
869
- options[:colorize] = v
870
- options[:color_scheme] = 1
871
- end
872
- opts.on("-s", "--sort", "sort list on priority") do |v|
873
- options[:sort] = v
874
- end
875
- opts.on("-g", "--grep REGEXP", "filter list on pattern") do |v|
876
- options[:grep] = v
877
- end
878
- opts.on("--renumber", "renumber while listing") do |v|
879
- options[:renumber] = v
880
- end
881
- opts.on("--hide-numbering", "hide-numbering while listing ") do |v|
882
- options[:hide_numbering] = v
883
- end
884
- opts.on("--[no-]show-all", "show all tasks (incl closed)") do |v|
885
- options[:show_all] = v
886
- end
887
-
888
- opts.separator ""
889
- opts.separator "Common options:"
890
-
891
- opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
892
- options[:verbose] = v
893
- end
894
- opts.on("-f", "--file FILENAME", "CSV filename") do |v|
895
- options[:file] = v
896
- end
897
- opts.on("-d DIR", "--dir DIR", "Use TODO file in this directory") do |v|
898
- require 'FileUtils'
899
- dir = File.expand_path v
900
- if File.directory? dir
901
- options[:dir] = dir
902
- # changing dir is important so that serial_number file is the current one.
903
- FileUtils.cd dir
904
- else
905
- die "#{RED}#{v}: no such directory #{CLEAR}"
906
- end
907
- end
908
- # No argument, shows at tail. This will print an options summary.
909
- # Try it and see!
910
- opts.on("-h", "--help", "Show this message") do
911
- puts opts
912
- exit 0
913
- end
914
-
915
- opts.on("--show-actions", "show actions ") do |v|
916
- todo = Todo.new(options, ARGV)
917
- todo.help nil
918
- exit 0
919
- end
910
+ Subcommands::global_options do |opts|
911
+ opts.banner = "Usage: #{$APPNAME} [options] [subcommand [options]]"
912
+ opts.description = "Todo list manager"
913
+ #opts.separator ""
914
+ #opts.separator "Global options are:"
915
+ opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
916
+ options[:verbose] = v
917
+ end
918
+ opts.on("-f", "--file FILENAME", "CSV filename") do |v|
919
+ options[:file] = v
920
+ end
921
+ opts.on("-d DIR", "--dir DIR", "Use TODO file in this directory") do |v|
922
+ require 'FileUtils'
923
+ dir = File.expand_path v
924
+ if File.directory? dir
925
+ options[:dir] = dir
926
+ # changing dir is important so that serial_number file is the current one.
927
+ FileUtils.cd dir
928
+ else
929
+ die "#{RED}#{v}: no such directory #{CLEAR}"
930
+ end
931
+ end
932
+ opts.on("--show-actions", "show actions ") do |v|
933
+ todo = Todo.new(options, ARGV)
934
+ todo.help nil
935
+ exit 0
936
+ end
920
937
 
921
- opts.on("--version", "Show version") do
922
- puts "#{APPNAME} version #{VERSION}, #{DATE}"
923
- puts "by #{AUTHOR}. This software is under the GPL License."
924
- exit 0
925
- end
938
+ opts.on("--version", "Show version") do
939
+ version = Cmdapp::version_info || VERSION
940
+ puts "#{APPNAME} version #{version}, #{DATE}"
941
+ puts "by #{AUTHOR}. This software is under the GPL License."
942
+ exit 0
943
+ end
944
+ # No argument, shows at tail. This will print an options summary.
945
+ # Try it and see!
946
+ opts.on("-h", "--help", "Show this message") do
947
+ puts opts
948
+ exit 0
949
+ end
926
950
  opts.separator ""
927
951
  opts.separator "Common Usage:"
928
952
  opts.separator <<TEXT
953
+ #{APPNAME} add "Text ...."
929
954
  #{APPNAME} list
930
- #{APPNAME} add "TEXT ...."
931
955
  #{APPNAME} pri 1 A
932
956
  #{APPNAME} close 1
933
957
  TEXT
934
-
935
- end.parse!(args)
958
+ end
959
+
960
+ Subcommands::command :list do |opts|
961
+ opts.banner = "Usage: list [options]"
962
+ opts.description = "List tasks.\t --show-all and others"
963
+ opts.on("-P", "--project PROJECTNAME", "name of project for add or list") { |v|
964
+ options[:project] = v
965
+ options[:filter] = true
966
+ }
967
+ opts.on("-p", "--priority A-Z", "priority code for add or list") { |v|
968
+ options[:priority] = v
969
+ options[:filter] = true
970
+ }
971
+ opts.on("-C", "--component COMPONENT", "component name for add or list") { |v|
972
+ options[:component] = v
973
+ options[:filter] = true
974
+ }
975
+ opts.on("--[no-]color", "--[no-]colors", "colorize listing") do |v|
976
+ options[:colorize] = v
977
+ options[:color_scheme] = 1
978
+ end
979
+ opts.on("-s", "--sort", "sort list on status,priority") do |v|
980
+ options[:sort] = v
981
+ end
982
+ opts.on("--reverse", "sort list on status,priority reversed") do |v|
983
+ options[:reverse] = v
984
+ end
985
+ opts.on("-g", "--grep REGEXP", "filter list on pattern") do |v|
986
+ options[:grep] = v
987
+ end
988
+ opts.on("--renumber", "renumber while listing") do |v|
989
+ options[:renumber] = v
990
+ end
991
+ opts.on("--hide-numbering", "hide-numbering while listing ") do |v|
992
+ options[:hide_numbering] = v
993
+ end
994
+ opts.on("--[no-]show-all", "show all tasks (incl closed)") do |v|
995
+ options[:show_all] = v
996
+ end
997
+ opts.on("--show-arch", "show all tasks adding archived ones too") do |v|
998
+ options[:show_arch] = v
999
+ options[:show_all] = v # when adding archived, we set show-all so closed are visible
1000
+ end
1001
+ end
1002
+
1003
+ Subcommands::command :add, :a do |opts|
1004
+ opts.banner = "Usage: add [options] TEXT"
1005
+ opts.description = "Add a task."
1006
+ opts.on("-f", "--[no-]force", "force verbosely") do |v|
1007
+ options[:force] = v
1008
+ end
1009
+ opts.on("-P", "--project PROJECTNAME", "name of project for add or list") { |v|
1010
+ options[:project] = v
1011
+ options[:filter] = true
1012
+ }
1013
+ opts.on("-p", "--priority A-Z", "priority code for add or list") { |v|
1014
+ options[:priority] = v
1015
+ options[:filter] = true
1016
+ }
1017
+ opts.on("-C", "--component COMPONENT", "component name for add or list") { |v|
1018
+ options[:component] = v
1019
+ options[:filter] = true
1020
+ }
1021
+ end
1022
+ # XXX order of these 2 matters !! reverse and see what happens
1023
+ Subcommands::command :pri, :p do |opts|
1024
+ opts.banner = "Usage: pri [options] [A-Z] <TASK/s>"
1025
+ opts.description = "Add priority to task. "
1026
+ opts.on("-f", "--[no-]force", "force verbosely") do |v|
1027
+ options[:force] = v
1028
+ end
1029
+ end
1030
+ Subcommands::command :depri do |opts|
1031
+ opts.banner = "Usage: depri [options] <TASK/s>"
1032
+ opts.description = "Remove priority of task. \n\t todorb depri <TASK>"
1033
+ opts.on("-f", "--[no-]force", "force verbosely") do |v|
1034
+ options[:force] = v
1035
+ end
1036
+ end
1037
+ Subcommands::command :delete, :del do |opts|
1038
+ opts.banner = "Usage: delete [options] <TASK/s>"
1039
+ opts.description = "Delete a task. \n\t todorb delete <TASK>"
1040
+ opts.on("-f", "--[no-]force", "force - don't prompt") do |v|
1041
+ options[:force] = v
1042
+ end
1043
+ opts.on("--recursive", "operate on subtasks also") { |v|
1044
+ options[:recursive] = v
1045
+ }
1046
+ end
1047
+ Subcommands::command :status do |opts|
1048
+ opts.banner = "Usage: status [options] <STATUS> <TASKS>"
1049
+ opts.description = "Change the status of a task. \t<STATUS> are open closed started pending hold next"
1050
+ opts.on("--recursive", "operate on subtasks also") { |v|
1051
+ options[:recursive] = v
1052
+ }
1053
+ end
1054
+ Subcommands::command :redo do |opts|
1055
+ opts.banner = "Usage: redo"
1056
+ opts.description = "Renumbers the todo file starting 1"
1057
+ end
1058
+ Subcommands::command :note do |opts|
1059
+ opts.banner = "Usage: note <TASK> <TEXT>"
1060
+ opts.description = "Add a note to a task."
1061
+ end
1062
+ Subcommands::command :tag do |opts|
1063
+ opts.banner = "Usage: tag <TAG> <TASKS>"
1064
+ opts.description = "Add a tag to an item/s. "
1065
+ end
1066
+ Subcommands::command :archive do |opts|
1067
+ opts.banner = "Usage: archive"
1068
+ opts.description = "archive closed tasks to archive.txt"
1069
+ end
1070
+ Subcommands::command :copyunder, :cu do |opts|
1071
+ opts.banner = "Usage: copyunder"
1072
+ opts.description = "Move first task under second (as a subtask). aka cu"
1073
+ opts.on("-d", "--delete", "Delete old after copying") do |v|
1074
+ options[:delete_old] = v
1075
+ end
1076
+ end
1077
+ Subcommands::command :addsub do |opts|
1078
+ opts.banner = "Usage: addsub [options]"
1079
+ opts.description = "Add a task under another."
1080
+ opts.on("-P", "--project PROJECTNAME", "name of project for add or list") { |v|
1081
+ options[:project] = v
1082
+ #options[:filter] = true
1083
+ }
1084
+ opts.on("-p", "--priority A-Z", "priority code for add or list") { |v|
1085
+ options[:priority] = v
1086
+ #options[:filter] = true
1087
+ }
1088
+ opts.on("-C", "--component COMPONENT", "component name for add or list") { |v|
1089
+ options[:component] = v
1090
+ #options[:filter] = true
1091
+ }
1092
+ end
1093
+ #Subcommands::command :testy do |opts|
1094
+ #opts.banner = "Usage: test"
1095
+ #opts.description = "test out some functionality"
1096
+ #end
1097
+ Subcommands::alias_command :open , "status","open"
1098
+ Subcommands::alias_command :close , "status","closed"
1099
+ cmd = Subcommands::opt_parse()
1100
+ args.unshift cmd if cmd
936
1101
 
937
1102
  options[:file] ||= "TODO2.txt"
938
1103
  if options[:verbose]
data/tests/data.1 ADDED
@@ -0,0 +1,14 @@
1
+ 1 [x] if no TODO file give proper message to add task (2010-06-14)
2
+ 2 [x] what if no serial_number file? (2010-06-14)
3
+ 3 [x] Add a close for status close (2010-06-14)
4
+ 3.1 [ ] hello there new a u 3 (2010-06-15)
5
+ 3.1.1 [ ] hello there new a u 3 (2010-06-15)
6
+ 3.1.2 [ ] hello there new a u 3 (2010-06-15)
7
+ 3.1.3 [ ] hello there new a u 3 (2010-06-15)
8
+ 3.2 [ ] hello there new a u 3.2 (2010-06-15)
9
+ 3.2.1 [ ] hello there new a u 3.2.1 (2010-06-15)
10
+ 3.2.1.1 [ ] hello there new a u 3.2.1.1 (2010-06-15)
11
+ 4 [ ] start rubyforge project for todorb (2010-06-14)
12
+ 5 [ ] list: if dir given then show full path of TODO2.txt at end (2010-06-14)
13
+ 6 [ ] allow for ENV VARS such as verbose, plain, force (2010-06-15)
14
+ 7 [ ] list: search terms with - + and = (2010-06-15)
data/tests/data.2 ADDED
@@ -0,0 +1,7 @@
1
+ 1 [ ] if no TODO file give proper message to add task (2010-06-14)
2
+ 2 [ ] what if no serial_number file? (2010-06-14)
3
+ 3 [ ] Add a close for status close (2010-06-14)
4
+ 4 [ ] start rubyforge project for todorb (2010-06-14)
5
+ 5 [ ] list: if dir given then show full path of TODO2.txt at end (2010-06-14)
6
+ 6 [ ] allow for ENV VARS such as verbose, plain, force (2010-06-15)
7
+ 7 [ ] list: search terms with - + and = (2010-06-15)