doing 1.0.79 → 1.0.83
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +10 -4
- data/bin/doing +40 -11
- data/lib/doing/version.rb +1 -1
- data/lib/doing/wwid.rb +148 -117
- data/lib/doing.rb +3 -2
- metadata +2 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: fb85f27f305f246d4ab182268c9e5188da67f22fde46d3ee4ae716996c78b2c3
         | 
| 4 | 
            +
              data.tar.gz: 7b302748d9837511adc77679fd619c6daf85b2f7e15f541d530c8cc211e0aac3
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: dbf5e04626a97e5287c2417cf5afffd6516860a1fa5f3ed64e93fe15bdc62b85f045d0a54adc08c774b4d711add29f02799cf3d4a2c22853e1273a691d0a9f00
         | 
| 7 | 
            +
              data.tar.gz: 87bf6eac2e770b161c8ae4fd2fee4adea5ed261b828f2142997858393a627e0d36788981fe52a4c66486f442da2de349ce1ac157732d824b0ef633e4dcbdc703
         | 
    
        data/README.md
    CHANGED
    
    | @@ -27,7 +27,7 @@ If there's something I want to look at later but doesn't need to be added to a t | |
| 27 27 |  | 
| 28 28 | 
             
            ## Installation
         | 
| 29 29 |  | 
| 30 | 
            -
            The current version of `doing` is <!--VER-->1.0. | 
| 30 | 
            +
            The current version of `doing` is <!--VER-->1.0.82<!--END VER-->.
         | 
| 31 31 |  | 
| 32 32 | 
             
                $ [sudo] gem install doing
         | 
| 33 33 |  | 
| @@ -245,7 +245,7 @@ You can create your own "views" in the `~/.doingrc` file and view them with `doi | |
| 245 245 |  | 
| 246 246 | 
             
                views:
         | 
| 247 247 | 
             
                  old:
         | 
| 248 | 
            -
                    section:  | 
| 248 | 
            +
                    section: Archive
         | 
| 249 249 | 
             
                    count: 5
         | 
| 250 250 | 
             
                    wrap_width: 0
         | 
| 251 251 | 
             
                    date_format: '%F %_I:%M%P'
         | 
| @@ -253,6 +253,10 @@ You can create your own "views" in the `~/.doingrc` file and view them with `doi | |
| 253 253 | 
             
                    order: asc
         | 
| 254 254 | 
             
                    tags: done finished cancelled
         | 
| 255 255 | 
             
                    tags_bool: ANY
         | 
| 256 | 
            +
                    only_timed: false
         | 
| 257 | 
            +
                    tag_sort: time
         | 
| 258 | 
            +
                    tag_order: asc
         | 
| 259 | 
            +
                    totals: true
         | 
| 256 260 |  | 
| 257 261 | 
             
            You can add additional custom views. Just nest them under the `views` key (indented two spaces from the edge). Multiple views would look like this:
         | 
| 258 262 |  | 
| @@ -276,7 +280,9 @@ You can add new sections with `doing add_section section_name`. You can also cre | |
| 276 280 |  | 
| 277 281 | 
             
            The `tags` and `tags_bool` keys allow you to specify tags that the view is filtered by. You can list multiple tags separated by spaces, and then use `tags_bool` to specify `ALL`, `ANY`, or `NONE` to determine how it handles the multiple tags.
         | 
| 278 282 |  | 
| 279 | 
            -
            The `order` key defines the sort order of the output. This is applied _after_ the tasks are retrieved and cut off at the maximum number specified in `count`.
         | 
| 283 | 
            +
            The `order` key defines the sort order of the output (asc or desc). This is applied _after_ the tasks are retrieved and cut off at the maximum number specified in `count`.
         | 
| 284 | 
            +
             | 
| 285 | 
            +
            You can include tag timers and totals in the output with `totals: true`. Control tag output using `tag_sort` (name or title) and `tag_order` (asc or desc). You can also output only timed entries using `only_timed: true`. All of these options can be overridden using flags on the `doing view` command.
         | 
| 280 286 |  | 
| 281 287 | 
             
            Regarding colors, you can use them to create very nice displays if you're outputting to a color terminal. Example:
         | 
| 282 288 |  | 
| @@ -291,7 +297,7 @@ Outputs: | |
| 291 297 |  | 
| 292 298 | 
             
            
         | 
| 293 299 |  | 
| 294 | 
            -
            You can also specify a default output format for a view. Most of the optional output formats override the template specification (`html`, `csv`, `json`). If the `view` command is used with the `-o` flag, it will override what's specified in the  | 
| 300 | 
            +
            You can also specify a default output format for a view. Most of the optional output formats override the template specification (`html`, `csv`, `json`). If the `view` command is used with the `-o` flag, it will override what's specified for the view in the config.
         | 
| 295 301 |  | 
| 296 302 | 
             
            ### Colors
         | 
| 297 303 |  | 
    
        data/bin/doing
    CHANGED
    
    | @@ -1,4 +1,4 @@ | |
| 1 | 
            -
            #!/usr/bin/env ruby
         | 
| 1 | 
            +
            #!/usr/bin/env ruby -W1
         | 
| 2 2 | 
             
            # frozen_string_literal: true
         | 
| 3 3 |  | 
| 4 4 | 
             
            $LOAD_PATH.unshift File.join(__dir__, '..', 'lib')
         | 
| @@ -301,6 +301,9 @@ command :select do |c| | |
| 301 301 | 
             
              c.desc 'Add flag to selected item(s)'
         | 
| 302 302 | 
             
              c.switch %i[flag], negatable: false, default_value: false
         | 
| 303 303 |  | 
| 304 | 
            +
              c.desc 'Perform action without confirmation'
         | 
| 305 | 
            +
              c.switch %i[force], negatable: false, default_value: false
         | 
| 306 | 
            +
             | 
| 304 307 | 
             
              c.desc 'Save selected entries to file using --output format'
         | 
| 305 308 | 
             
              c.arg_name 'FILE'
         | 
| 306 309 | 
             
              c.flag %i[save_to]
         | 
| @@ -1306,7 +1309,8 @@ desc 'Select a section to display from a menu' | |
| 1306 1309 | 
             
            command :choose do |c|
         | 
| 1307 1310 | 
             
              c.action do |_global_options, _options, _args|
         | 
| 1308 1311 | 
             
                section = wwid.choose_section
         | 
| 1309 | 
            -
             | 
| 1312 | 
            +
             | 
| 1313 | 
            +
                puts wwid.list_section({ section: section.cap_first, count: 0 }) if section
         | 
| 1310 1314 | 
             
              end
         | 
| 1311 1315 | 
             
            end
         | 
| 1312 1316 |  | 
| @@ -1340,13 +1344,14 @@ command :colors do |c| | |
| 1340 1344 | 
             
            end
         | 
| 1341 1345 |  | 
| 1342 1346 | 
             
            desc 'Display a user-created view'
         | 
| 1347 | 
            +
            long_desc 'Command line options override associated view settings'
         | 
| 1343 1348 | 
             
            arg_name 'VIEW_NAME'
         | 
| 1344 1349 | 
             
            command :view do |c|
         | 
| 1345 | 
            -
              c.desc 'Section | 
| 1350 | 
            +
              c.desc 'Section'
         | 
| 1346 1351 | 
             
              c.arg_name 'NAME'
         | 
| 1347 1352 | 
             
              c.flag %i[s section]
         | 
| 1348 1353 |  | 
| 1349 | 
            -
              c.desc 'Count to display | 
| 1354 | 
            +
              c.desc 'Count to display'
         | 
| 1350 1355 | 
             
              c.arg_name 'COUNT'
         | 
| 1351 1356 | 
             
              c.flag %i[c count], must_match: /^\d+$/, type: Integer
         | 
| 1352 1357 |  | 
| @@ -1364,12 +1369,14 @@ command :view do |c| | |
| 1364 1369 | 
             
              c.switch [:color], default_value: true, negatable: true
         | 
| 1365 1370 |  | 
| 1366 1371 | 
             
              c.desc 'Sort tags by (name|time)'
         | 
| 1367 | 
            -
              default = 'time'
         | 
| 1368 | 
            -
              default = wwid.config['tag_sort'] if wwid.config.key?('tag_sort')
         | 
| 1369 1372 | 
             
              c.arg_name 'KEY'
         | 
| 1370 | 
            -
              c.flag [:tag_sort], must_match: /^(?:name|time)$/i | 
| 1373 | 
            +
              c.flag [:tag_sort], must_match: /^(?:name|time)$/i
         | 
| 1371 1374 |  | 
| 1372 | 
            -
              c.desc ' | 
| 1375 | 
            +
              c.desc 'Tag sort direction (asc|desc)'
         | 
| 1376 | 
            +
              c.arg_name 'DIRECTION'
         | 
| 1377 | 
            +
              c.flag [:tag_order], must_match: /^(?:a(?:sc)?|d(?:esc)?)$/i
         | 
| 1378 | 
            +
             | 
| 1379 | 
            +
              c.desc 'Only show items with recorded time intervals (override view settings)'
         | 
| 1373 1380 | 
             
              c.switch [:only_timed], default_value: false, negatable: false
         | 
| 1374 1381 |  | 
| 1375 1382 | 
             
              c.action do |_global_options, options, args|
         | 
| @@ -1418,10 +1425,31 @@ command :view do |c| | |
| 1418 1425 | 
             
                            end
         | 
| 1419 1426 | 
             
                  order = view.key?('order') ? view['order'] : 'asc'
         | 
| 1420 1427 |  | 
| 1421 | 
            -
                   | 
| 1428 | 
            +
                  totals = if options[:totals]
         | 
| 1429 | 
            +
                             true
         | 
| 1430 | 
            +
                           else
         | 
| 1431 | 
            +
                             view.key?('totals') ? view['totals'] : false
         | 
| 1432 | 
            +
                           end
         | 
| 1433 | 
            +
             | 
| 1434 | 
            +
                  options[:t] = true if totals
         | 
| 1422 1435 | 
             
                  options[:output]&.downcase!
         | 
| 1423 | 
            -
                  options[:sort_tags] = options[:tag_sort] =~ /^n/i
         | 
| 1424 1436 |  | 
| 1437 | 
            +
                  options[:sort_tags] = if options[:tag_sort]
         | 
| 1438 | 
            +
                                          options[:tag_sort] =~ /^n/i ? true : false
         | 
| 1439 | 
            +
                                        elsif view.key?('tag_sort')
         | 
| 1440 | 
            +
                                          view['tag_sort'] =~ /^n/i ? true : false
         | 
| 1441 | 
            +
                                        else
         | 
| 1442 | 
            +
                                          false
         | 
| 1443 | 
            +
                                        end
         | 
| 1444 | 
            +
             | 
| 1445 | 
            +
                  tag_order = if options[:tag_order]
         | 
| 1446 | 
            +
                                options[:tag_order] =~ /^d/i ? 'desc' : 'asc'
         | 
| 1447 | 
            +
                              elsif view.key?('tag_order')
         | 
| 1448 | 
            +
                                view['tag_order'] =~ /^d/i ? 'desc' : 'asc'
         | 
| 1449 | 
            +
                              else
         | 
| 1450 | 
            +
                                'asc'
         | 
| 1451 | 
            +
                              end
         | 
| 1452 | 
            +
                  warn "TAG ORDER: #{options[:tag_order]}"
         | 
| 1425 1453 | 
             
                  opts = {
         | 
| 1426 1454 | 
             
                    count: count,
         | 
| 1427 1455 | 
             
                    format: format,
         | 
| @@ -1432,10 +1460,11 @@ command :view do |c| | |
| 1432 1460 | 
             
                    section: section,
         | 
| 1433 1461 | 
             
                    sort_tags: options[:sort_tags],
         | 
| 1434 1462 | 
             
                    tag_filter: tag_filter,
         | 
| 1463 | 
            +
                    tag_order: tag_order,
         | 
| 1435 1464 | 
             
                    tags_color: tags_color,
         | 
| 1436 1465 | 
             
                    template: template,
         | 
| 1437 1466 | 
             
                    times: options[:t],
         | 
| 1438 | 
            -
                    totals:  | 
| 1467 | 
            +
                    totals: totals
         | 
| 1439 1468 | 
             
                  }
         | 
| 1440 1469 |  | 
| 1441 1470 | 
             
                  puts wwid.list_section(opts)
         | 
    
        data/lib/doing/version.rb
    CHANGED
    
    
    
        data/lib/doing/wwid.rb
    CHANGED
    
    | @@ -84,6 +84,7 @@ class WWID | |
| 84 84 | 
             
              ##
         | 
| 85 85 | 
             
              def configure(opt = {})
         | 
| 86 86 | 
             
                @timers = {}
         | 
| 87 | 
            +
                @recorded_items = []
         | 
| 87 88 | 
             
                opt[:ignore_local] ||= false
         | 
| 88 89 |  | 
| 89 90 | 
             
                @config_file ||= File.join(@user_home, @default_config_file)
         | 
| @@ -583,17 +584,17 @@ class WWID | |
| 583 584 | 
             
              end
         | 
| 584 585 |  | 
| 585 586 | 
             
              def same_time?(item_a, item_b)
         | 
| 586 | 
            -
                item_a['date'] == item_b['date'] ? get_interval(item_a, false) == get_interval(item_b, false) : false
         | 
| 587 | 
            +
                item_a['date'] == item_b['date'] ? get_interval(item_a, formatted: false, record: false) == get_interval(item_b,  formatted: false, record: false) : false
         | 
| 587 588 | 
             
              end
         | 
| 588 589 |  | 
| 589 590 | 
             
              def overlapping_time?(item_a, item_b)
         | 
| 590 591 | 
             
                return true if same_time?(item_a, item_b)
         | 
| 591 592 |  | 
| 592 593 | 
             
                start_a = item_a['date']
         | 
| 593 | 
            -
                interval = get_interval(item_a, false)
         | 
| 594 | 
            +
                interval = get_interval(item_a, formatted: false, record: false)
         | 
| 594 595 | 
             
                end_a = interval ? start_a + interval.to_i : start_a
         | 
| 595 596 | 
             
                start_b = item_b['date']
         | 
| 596 | 
            -
                interval = get_interval(item_b, false)
         | 
| 597 | 
            +
                interval = get_interval(item_b,  formatted: false, record: false)
         | 
| 597 598 | 
             
                end_b = interval ? start_b + interval.to_i : start_b
         | 
| 598 599 | 
             
                (start_a >= start_b && start_a <= end_b) || (end_a >= start_b && end_a <= end_b) || (start_a < start_b && end_a > end_b)
         | 
| 599 600 | 
             
              end
         | 
| @@ -757,7 +758,7 @@ class WWID | |
| 757 758 | 
             
                  all_items.concat(@content[section]['items'].dup) if @content.key?(section)
         | 
| 758 759 | 
             
                end
         | 
| 759 760 |  | 
| 760 | 
            -
                if opt[:tag] | 
| 761 | 
            +
                if opt[:tag]&.length
         | 
| 761 762 | 
             
                  all_items.select! { |item| item.has_tags?(opt[:tag], opt[:tag_bool]) }
         | 
| 762 763 | 
             
                elsif opt[:search]&.length
         | 
| 763 764 | 
             
                  all_items.select! { |item| item.matches_search?(opt[:search]) }
         | 
| @@ -771,16 +772,17 @@ class WWID | |
| 771 772 | 
             
              ##
         | 
| 772 773 | 
             
              ## @return     (String) The selected option
         | 
| 773 774 | 
             
              ##
         | 
| 774 | 
            -
              def choose_from(options, prompt)
         | 
| 775 | 
            -
                 | 
| 776 | 
            -
                 | 
| 777 | 
            -
             | 
| 778 | 
            -
                 | 
| 779 | 
            -
                 | 
| 780 | 
            -
                 | 
| 781 | 
            -
                 | 
| 782 | 
            -
             | 
| 783 | 
            -
             | 
| 775 | 
            +
              def choose_from(options, prompt: 'Make a selection: ', multiple: false, fzf_args: [])
         | 
| 776 | 
            +
                fzf = File.join(File.dirname(__FILE__), '../helpers/fuzzyfilefinder')
         | 
| 777 | 
            +
                fzf_args << '-1'
         | 
| 778 | 
            +
                fzf_args << %(--prompt "#{prompt}")
         | 
| 779 | 
            +
                fzf_args << '--multi' if multiple
         | 
| 780 | 
            +
                header = "esc: cancel,#{multiple ? ' tab: multi-select, ctrl-a: select all,' : ''} return: confirm"
         | 
| 781 | 
            +
                fzf_args << %(--header "#{header}")
         | 
| 782 | 
            +
                res = `echo #{Shellwords.escape(options.join("\n"))}|#{fzf} #{fzf_args.join(' ')}`
         | 
| 783 | 
            +
                return false if res.strip.size.zero?
         | 
| 784 | 
            +
             | 
| 785 | 
            +
                res
         | 
| 784 786 | 
             
              end
         | 
| 785 787 |  | 
| 786 788 | 
             
              ##
         | 
| @@ -811,7 +813,7 @@ class WWID | |
| 811 813 | 
             
                    ') ',
         | 
| 812 814 | 
             
                    item['date'],
         | 
| 813 815 | 
             
                    ' | ',
         | 
| 814 | 
            -
                    item['title'] | 
| 816 | 
            +
                    item['title']
         | 
| 815 817 | 
             
                  ]
         | 
| 816 818 | 
             
                  if opt[:section] =~ /^all/i
         | 
| 817 819 | 
             
                    out.concat([
         | 
| @@ -822,8 +824,15 @@ class WWID | |
| 822 824 | 
             
                  end
         | 
| 823 825 | 
             
                  out.join('')
         | 
| 824 826 | 
             
                end
         | 
| 825 | 
            -
             | 
| 826 | 
            -
             | 
| 827 | 
            +
                fzf_args = [
         | 
| 828 | 
            +
                  %(--header="Arrows: navigate, tab: mark for selection, ctrl-a: select all, enter: commit"),
         | 
| 829 | 
            +
                  %(--prompt="Select entries to act on > "),
         | 
| 830 | 
            +
                  '-1',
         | 
| 831 | 
            +
                  '-m',
         | 
| 832 | 
            +
                  '--bind ctrl-a:select-all',
         | 
| 833 | 
            +
                  %(-q "#{opt[:query]}")
         | 
| 834 | 
            +
                ]
         | 
| 835 | 
            +
                res = `echo #{Shellwords.escape(options.join("\n"))}|#{fzf} #{fzf_args.join(' ')}`
         | 
| 827 836 | 
             
                selected = []
         | 
| 828 837 | 
             
                res.split(/\n/).each do |item|
         | 
| 829 838 | 
             
                  idx = item.match(/^(\d+)\)/)[1].to_i
         | 
| @@ -845,62 +854,71 @@ class WWID | |
| 845 854 | 
             
                end
         | 
| 846 855 |  | 
| 847 856 | 
             
                unless has_action
         | 
| 848 | 
            -
                   | 
| 849 | 
            -
             | 
| 850 | 
            -
             | 
| 851 | 
            -
             | 
| 852 | 
            -
             | 
| 853 | 
            -
             | 
| 854 | 
            -
             | 
| 855 | 
            -
             | 
| 856 | 
            -
             | 
| 857 | 
            -
             | 
| 858 | 
            -
             | 
| 859 | 
            -
             | 
| 860 | 
            -
             | 
| 861 | 
            -
             | 
| 862 | 
            -
             | 
| 863 | 
            -
                   | 
| 864 | 
            -
             | 
| 865 | 
            -
             | 
| 866 | 
            -
             | 
| 867 | 
            -
                     | 
| 868 | 
            -
                     | 
| 869 | 
            -
             | 
| 870 | 
            -
             | 
| 871 | 
            -
             | 
| 872 | 
            -
             | 
| 873 | 
            -
             | 
| 874 | 
            -
             | 
| 875 | 
            -
                       | 
| 876 | 
            -
                       | 
| 877 | 
            -
                       | 
| 878 | 
            -
                      opt[: | 
| 857 | 
            +
                  choice = choose_from([
         | 
| 858 | 
            +
                                         'add tag',
         | 
| 859 | 
            +
                                         'remove tag',
         | 
| 860 | 
            +
                                         'cancel',
         | 
| 861 | 
            +
                                         'delete',
         | 
| 862 | 
            +
                                         'finish',
         | 
| 863 | 
            +
                                         'flag',
         | 
| 864 | 
            +
                                         'archive',
         | 
| 865 | 
            +
                                         'move',
         | 
| 866 | 
            +
                                         'edit',
         | 
| 867 | 
            +
                                         'output formatted'
         | 
| 868 | 
            +
                                       ],
         | 
| 869 | 
            +
                                       prompt: 'What do you want to do with the selected items? > ',
         | 
| 870 | 
            +
                                       multiple: true,
         | 
| 871 | 
            +
                                       fzf_args: ['--height=60%', '--tac', '--no-sort'])
         | 
| 872 | 
            +
                  return unless choice
         | 
| 873 | 
            +
             | 
| 874 | 
            +
                  to_do = choice.strip.split(/\n/)
         | 
| 875 | 
            +
                  to_do.each do |action|
         | 
| 876 | 
            +
                    case action
         | 
| 877 | 
            +
                    when /(add|remove) tag/
         | 
| 878 | 
            +
                      type = action =~ /^add/ ? 'add' : 'remove'
         | 
| 879 | 
            +
                      if opt[:tag]
         | 
| 880 | 
            +
                        warn "'add tag' and 'remove tag' can not be used together"
         | 
| 881 | 
            +
                        Process.exit 1
         | 
| 882 | 
            +
                      end
         | 
| 883 | 
            +
                      print "#{colors['yellow']}Tag to #{type}: #{colors['reset']}"
         | 
| 884 | 
            +
                      tag = STDIN.gets
         | 
| 885 | 
            +
                      return if tag =~ /^ *$/
         | 
| 886 | 
            +
                      opt[:tag] = tag.strip.sub(/^@/, '')
         | 
| 887 | 
            +
                      opt[:remove] = true if type == 'remove'
         | 
| 888 | 
            +
                    when /output formatted/
         | 
| 889 | 
            +
                      output_format = choose_from(%w[doing taskpaper json timeline html csv].sort, prompt: 'Which output format? > ', fzf_args: ['--height=60%', '--tac', '--no-sort'])
         | 
| 890 | 
            +
                      return if tag =~ /^ *$/
         | 
| 891 | 
            +
                      opt[:output] = output_format.strip
         | 
| 892 | 
            +
                      res = opt[:force] ? false : yn('Save to file?', default_response: 'n')
         | 
| 893 | 
            +
                      if res
         | 
| 894 | 
            +
                        print "#{colors['yellow']}File path/name: #{colors['reset']}"
         | 
| 895 | 
            +
                        filename = STDIN.gets.strip
         | 
| 896 | 
            +
                        return if filename.empty?
         | 
| 897 | 
            +
                        opt[:save_to] = filename
         | 
| 898 | 
            +
                      end
         | 
| 899 | 
            +
                    when /archive/
         | 
| 900 | 
            +
                      opt[:archive] = true
         | 
| 901 | 
            +
                    when /delete/
         | 
| 902 | 
            +
                      opt[:delete] = true
         | 
| 903 | 
            +
                    when /edit/
         | 
| 904 | 
            +
                      opt[:editor] = true
         | 
| 905 | 
            +
                    when /finish/
         | 
| 906 | 
            +
                      opt[:finish] = true
         | 
| 907 | 
            +
                    when /cancel/
         | 
| 908 | 
            +
                      opt[:cancel] = true
         | 
| 909 | 
            +
                    when /move/
         | 
| 910 | 
            +
                      section = choose_section.strip
         | 
| 911 | 
            +
                      opt[:move] = section.strip unless section =~ /^ *$/
         | 
| 912 | 
            +
                    when /flag/
         | 
| 913 | 
            +
                      opt[:flag] = true
         | 
| 879 914 | 
             
                    end
         | 
| 880 | 
            -
                  when /archive/
         | 
| 881 | 
            -
                    opt[:archive] = true
         | 
| 882 | 
            -
                  when /delete/
         | 
| 883 | 
            -
                    opt[:delete] = true
         | 
| 884 | 
            -
                  when /edit/
         | 
| 885 | 
            -
                    opt[:editor] = true
         | 
| 886 | 
            -
                  when /finish/
         | 
| 887 | 
            -
                    opt[:finish] = true
         | 
| 888 | 
            -
                  when /cancel/
         | 
| 889 | 
            -
                    opt[:cancel] = true
         | 
| 890 | 
            -
                  when /move/
         | 
| 891 | 
            -
                    section = choose_section.strip
         | 
| 892 | 
            -
                    return if section =~ /^ *$/
         | 
| 893 | 
            -
                    opt[:move] = section.strip
         | 
| 894 | 
            -
                  when /flag/
         | 
| 895 | 
            -
                    opt[:flag] = true
         | 
| 896 915 | 
             
                  end
         | 
| 897 916 | 
             
                end
         | 
| 898 917 |  | 
| 899 | 
            -
             | 
| 900 918 | 
             
                if opt[:delete]
         | 
| 901 | 
            -
                  res = yn("Delete #{selected.size} items?", default_response: 'y')
         | 
| 919 | 
            +
                  res = opt[:force] ? true : yn("Delete #{selected.size} items?", default_response: 'y')
         | 
| 902 920 | 
             
                  if res
         | 
| 903 | 
            -
                    selected.each {|item| delete_item(item) }
         | 
| 921 | 
            +
                    selected.each { |item| delete_item(item) }
         | 
| 904 922 | 
             
                    write(@doing_file)
         | 
| 905 923 | 
             
                  end
         | 
| 906 924 | 
             
                  return
         | 
| @@ -994,13 +1012,16 @@ class WWID | |
| 994 1012 | 
             
                    item
         | 
| 995 1013 | 
             
                  end
         | 
| 996 1014 |  | 
| 997 | 
            -
                  @content = {'Export' => {'original' => 'Export:', 'items' => selected}}
         | 
| 998 | 
            -
                  options = {section: 'Export'}
         | 
| 1015 | 
            +
                  @content = { 'Export' => { 'original' => 'Export:', 'items' => selected } }
         | 
| 1016 | 
            +
                  options = { section: 'Export' }
         | 
| 999 1017 |  | 
| 1000 | 
            -
                   | 
| 1001 | 
            -
             | 
| 1002 | 
            -
                  else
         | 
| 1018 | 
            +
                  case opt[:output]
         | 
| 1019 | 
            +
                  when /doing/
         | 
| 1003 1020 | 
             
                    options[:template] = '- %date | %title%note'
         | 
| 1021 | 
            +
                  when /taskpaper/
         | 
| 1022 | 
            +
                    options[:template] = '- %title @date(%date)%note'
         | 
| 1023 | 
            +
                  else
         | 
| 1024 | 
            +
                    options[:output] = opt[:output]
         | 
| 1004 1025 | 
             
                  end
         | 
| 1005 1026 |  | 
| 1006 1027 | 
             
                  output = list_section(options)
         | 
| @@ -1082,7 +1103,6 @@ class WWID | |
| 1082 1103 | 
             
                    count = (opt[:count]).zero? ? items.length : opt[:count]
         | 
| 1083 1104 | 
             
                    items.map! do |item|
         | 
| 1084 1105 | 
             
                      break if idx == count
         | 
| 1085 | 
            -
             | 
| 1086 1106 | 
             
                      finished = opt[:unfinished] && item.has_tags?('done', :and)
         | 
| 1087 1107 | 
             
                      tag_match = opt[:tag].nil? || opt[:tag].empty? ? true : item.has_tags?(opt[:tag], opt[:tag_bool])
         | 
| 1088 1108 | 
             
                      search_match = opt[:search].nil? || opt[:search].empty? ? true : item.matches_search?(opt[:search])
         | 
| @@ -1507,14 +1527,8 @@ class WWID | |
| 1507 1527 | 
             
              ## @return     (String) The selected section name
         | 
| 1508 1528 | 
             
              ##
         | 
| 1509 1529 | 
             
              def choose_section
         | 
| 1510 | 
            -
                sections. | 
| 1511 | 
            -
             | 
| 1512 | 
            -
                end
         | 
| 1513 | 
            -
                print "#{colors['green']}> #{colors['default']}"
         | 
| 1514 | 
            -
                num = STDIN.gets
         | 
| 1515 | 
            -
                return false if num =~ /^[a-z ]*$/i
         | 
| 1516 | 
            -
             | 
| 1517 | 
            -
                sections[num.to_i - 1]
         | 
| 1530 | 
            +
                choice = choose_from(sections.sort, prompt: 'Choose a section > ', fzf_args: ['--height=60%'])
         | 
| 1531 | 
            +
                choice ? choice.strip : choice
         | 
| 1518 1532 | 
             
              end
         | 
| 1519 1533 |  | 
| 1520 1534 | 
             
              ##
         | 
| @@ -1532,14 +1546,8 @@ class WWID | |
| 1532 1546 | 
             
              ## @return     (String) The selected view name
         | 
| 1533 1547 | 
             
              ##
         | 
| 1534 1548 | 
             
              def choose_view
         | 
| 1535 | 
            -
                views. | 
| 1536 | 
            -
             | 
| 1537 | 
            -
                end
         | 
| 1538 | 
            -
                print '> '
         | 
| 1539 | 
            -
                num = STDIN.gets
         | 
| 1540 | 
            -
                return false if num =~ /^[a-z ]*$/i
         | 
| 1541 | 
            -
             | 
| 1542 | 
            -
                views[num.to_i - 1]
         | 
| 1549 | 
            +
                choice = choose_from(views.sort, prompt: 'Choose a view > ', fzf_args: ['--height=60%'])
         | 
| 1550 | 
            +
                choice ? choice.strip : choice
         | 
| 1543 1551 | 
             
              end
         | 
| 1544 1552 |  | 
| 1545 1553 | 
             
              ##
         | 
| @@ -1562,20 +1570,21 @@ class WWID | |
| 1562 1570 | 
             
              def list_section(opt = {})
         | 
| 1563 1571 | 
             
                opt[:count] ||= 0
         | 
| 1564 1572 | 
             
                count = opt[:count] - 1
         | 
| 1565 | 
            -
                opt[:section] ||= nil
         | 
| 1566 | 
            -
                opt[:format] ||= @default_date_format
         | 
| 1567 | 
            -
                opt[:template] ||= @default_template
         | 
| 1568 1573 | 
             
                opt[:age] ||= 'newest'
         | 
| 1574 | 
            +
                opt[:date_filter] ||= []
         | 
| 1575 | 
            +
                opt[:format] ||= @default_date_format
         | 
| 1576 | 
            +
                opt[:only_timed] ||= false
         | 
| 1569 1577 | 
             
                opt[:order] ||= 'desc'
         | 
| 1570 | 
            -
                opt[: | 
| 1578 | 
            +
                opt[:search] ||= false
         | 
| 1579 | 
            +
                opt[:section] ||= nil
         | 
| 1580 | 
            +
                opt[:sort_tags] ||= false
         | 
| 1571 1581 | 
             
                opt[:tag_filter] ||= false
         | 
| 1582 | 
            +
                opt[:tag_order] ||= 'asc'
         | 
| 1572 1583 | 
             
                opt[:tags_color] ||= false
         | 
| 1584 | 
            +
                opt[:template] ||= @default_template
         | 
| 1573 1585 | 
             
                opt[:times] ||= false
         | 
| 1586 | 
            +
                opt[:today] ||= false
         | 
| 1574 1587 | 
             
                opt[:totals] ||= false
         | 
| 1575 | 
            -
                opt[:sort_tags] ||= false
         | 
| 1576 | 
            -
                opt[:search] ||= false
         | 
| 1577 | 
            -
                opt[:only_timed] ||= false
         | 
| 1578 | 
            -
                opt[:date_filter] ||= []
         | 
| 1579 1588 |  | 
| 1580 1589 | 
             
                # opt[:highlight] ||= true
         | 
| 1581 1590 | 
             
                section = ''
         | 
| @@ -1628,7 +1637,7 @@ class WWID | |
| 1628 1637 |  | 
| 1629 1638 | 
             
                if opt[:only_timed]
         | 
| 1630 1639 | 
             
                  items.delete_if do |item|
         | 
| 1631 | 
            -
                    get_interval(item) == false
         | 
| 1640 | 
            +
                    get_interval(item, record: false) == false
         | 
| 1632 1641 | 
             
                  end
         | 
| 1633 1642 | 
             
                end
         | 
| 1634 1643 |  | 
| @@ -1663,7 +1672,7 @@ class WWID | |
| 1663 1672 | 
             
                      arr = i['note'].map { |line| line.strip }.delete_if { |e| e =~ /^\s*$/ }
         | 
| 1664 1673 | 
             
                      note = arr.join("\n") unless arr.nil?
         | 
| 1665 1674 | 
             
                    end
         | 
| 1666 | 
            -
                    interval = get_interval(i, false) if i['title'] =~ /@done\((\d{4}-\d\d-\d\d \d\d:\d\d.*?)\)/ && opt[:times]
         | 
| 1675 | 
            +
                    interval = get_interval(i, formatted: false) if i['title'] =~ /@done\((\d{4}-\d\d-\d\d \d\d:\d\d.*?)\)/ && opt[:times]
         | 
| 1667 1676 | 
             
                    interval ||= 0
         | 
| 1668 1677 | 
             
                    output.push(CSV.generate_line([i['date'], i['title'], note, interval, i['section']]))
         | 
| 1669 1678 | 
             
                  end
         | 
| @@ -1682,7 +1691,7 @@ class WWID | |
| 1682 1691 | 
             
                    end
         | 
| 1683 1692 | 
             
                    if i['title'] =~ /@done\((\d{4}-\d\d-\d\d \d\d:\d\d.*?)\)/ && opt[:times]
         | 
| 1684 1693 | 
             
                      end_date = Time.parse(Regexp.last_match(1))
         | 
| 1685 | 
            -
                      interval = get_interval(i, false)
         | 
| 1694 | 
            +
                      interval = get_interval(i, formatted: false)
         | 
| 1686 1695 | 
             
                    end
         | 
| 1687 1696 | 
             
                    end_date ||= ''
         | 
| 1688 1697 | 
             
                    interval ||= 0
         | 
| @@ -1731,7 +1740,7 @@ class WWID | |
| 1731 1740 | 
             
                    out = {
         | 
| 1732 1741 | 
             
                      'section' => section,
         | 
| 1733 1742 | 
             
                      'items' => items_out,
         | 
| 1734 | 
            -
                      'timers' => tag_times('json', opt[:sort_tags])
         | 
| 1743 | 
            +
                      'timers' => tag_times(format: 'json', sort_by_name: opt[:sort_tags], sort_order: opt[:tag_order])
         | 
| 1735 1744 | 
             
                    }.to_json
         | 
| 1736 1745 | 
             
                  elsif opt[:output] == 'timeline'
         | 
| 1737 1746 | 
             
                    template = <<~EOTEMPLATE
         | 
| @@ -1812,7 +1821,7 @@ class WWID | |
| 1812 1821 | 
             
                            css_template
         | 
| 1813 1822 | 
             
                          end
         | 
| 1814 1823 |  | 
| 1815 | 
            -
                  totals = opt[:totals] ? tag_times('html', opt[:sort_tags]) : ''
         | 
| 1824 | 
            +
                  totals = opt[:totals] ? tag_times(format: 'html', sort_by_name: opt[:sort_tags], sort_order: opt[:tag_order]) : ''
         | 
| 1816 1825 | 
             
                  engine = Haml::Engine.new(template)
         | 
| 1817 1826 | 
             
                  out = engine.render(Object.new,
         | 
| 1818 1827 | 
             
                                     { :@items => items_out, :@page_title => page_title, :@style => style, :@totals => totals })
         | 
| @@ -1853,7 +1862,7 @@ class WWID | |
| 1853 1862 |  | 
| 1854 1863 | 
             
                    output.sub!(/%date/, item['date'].strftime(opt[:format]))
         | 
| 1855 1864 |  | 
| 1856 | 
            -
                    interval = get_interval(item) if item['title'] =~ /@done\((\d{4}-\d\d-\d\d \d\d:\d\d.*?)\)/ && opt[:times]
         | 
| 1865 | 
            +
                    interval = get_interval(item, record: true) if item['title'] =~ /@done\((\d{4}-\d\d-\d\d \d\d:\d\d.*?)\)/ && opt[:times]
         | 
| 1857 1866 | 
             
                    interval ||= ''
         | 
| 1858 1867 | 
             
                    output.sub!(/%interval/, interval)
         | 
| 1859 1868 |  | 
| @@ -1903,7 +1912,8 @@ class WWID | |
| 1903 1912 |  | 
| 1904 1913 | 
             
                    out += "#{output}\n"
         | 
| 1905 1914 | 
             
                  end
         | 
| 1906 | 
            -
             | 
| 1915 | 
            +
             | 
| 1916 | 
            +
                  out += tag_times(format: 'text', sort_by_name: opt[:sort_tags], sort_order: opt[:tag_order]) if opt[:totals]
         | 
| 1907 1917 | 
             
                end
         | 
| 1908 1918 | 
             
                out
         | 
| 1909 1919 | 
             
              end
         | 
| @@ -2166,11 +2176,15 @@ class WWID | |
| 2166 2176 | 
             
              end
         | 
| 2167 2177 |  | 
| 2168 2178 | 
             
              ##
         | 
| 2169 | 
            -
              ## @brief      Get total elapsed time for all tags in | 
| 2179 | 
            +
              ## @brief      Get total elapsed time for all tags in
         | 
| 2180 | 
            +
              ##             selection
         | 
| 2170 2181 | 
             
              ##
         | 
| 2171 | 
            -
              ## @param      format | 
| 2182 | 
            +
              ## @param      format        (String) return format (html,
         | 
| 2183 | 
            +
              ##                           json, or text)
         | 
| 2184 | 
            +
              ## @param      sort_by_name  (Boolean) Sort by name if true, otherwise by time
         | 
| 2185 | 
            +
              ## @param      sort_order    (String) The sort order (asc or desc)
         | 
| 2172 2186 | 
             
              ##
         | 
| 2173 | 
            -
              def tag_times(format  | 
| 2187 | 
            +
              def tag_times(format: 'text', sort_by_name: false, sort_order: 'asc')
         | 
| 2174 2188 | 
             
                return '' if @timers.empty?
         | 
| 2175 2189 |  | 
| 2176 2190 | 
             
                max = @timers.keys.sort_by { |k| k.length }.reverse[0].length + 1
         | 
| @@ -2179,11 +2193,13 @@ class WWID | |
| 2179 2193 |  | 
| 2180 2194 | 
             
                tags_data = @timers.delete_if { |_k, v| v == 0 }
         | 
| 2181 2195 | 
             
                sorted_tags_data = if sort_by_name
         | 
| 2182 | 
            -
                                     tags_data.sort_by { |k, _v| k } | 
| 2196 | 
            +
                                     tags_data.sort_by { |k, _v| k }
         | 
| 2183 2197 | 
             
                                   else
         | 
| 2184 2198 | 
             
                                     tags_data.sort_by { |_k, v| v }
         | 
| 2185 2199 | 
             
                                   end
         | 
| 2186 2200 |  | 
| 2201 | 
            +
                sorted_tags_data.reverse! if sort_order =~ /^asc/i
         | 
| 2202 | 
            +
             | 
| 2187 2203 | 
             
                if format == 'html'
         | 
| 2188 2204 | 
             
                  output = <<EOS
         | 
| 2189 2205 | 
             
                    <table>
         | 
| @@ -2317,19 +2333,20 @@ EOS | |
| 2317 2333 | 
             
              ## @param      item       (Hash) The entry
         | 
| 2318 2334 | 
             
              ## @param      formatted  (Bool) Return human readable time (default seconds)
         | 
| 2319 2335 | 
             
              ##
         | 
| 2320 | 
            -
              def get_interval(item, formatted  | 
| 2336 | 
            +
              def get_interval(item, formatted: true, record: true)
         | 
| 2321 2337 | 
             
                done = nil
         | 
| 2322 2338 | 
             
                start = nil
         | 
| 2323 2339 |  | 
| 2324 2340 | 
             
                if @interval_cache.keys.include? item['title']
         | 
| 2325 2341 | 
             
                  seconds = @interval_cache[item['title']]
         | 
| 2342 | 
            +
                  record_tag_times(item, seconds) if record
         | 
| 2326 2343 | 
             
                  return seconds > 0 ? '%02d:%02d:%02d' % fmt_time(seconds) : false
         | 
| 2327 2344 | 
             
                end
         | 
| 2328 2345 |  | 
| 2329 2346 | 
             
                if item['title'] =~ /@done\((\d{4}-\d\d-\d\d \d\d:\d\d.*?)\)/
         | 
| 2330 2347 | 
             
                  done = Time.parse(Regexp.last_match(1))
         | 
| 2331 2348 | 
             
                else
         | 
| 2332 | 
            -
                  return  | 
| 2349 | 
            +
                  return false
         | 
| 2333 2350 | 
             
                end
         | 
| 2334 2351 |  | 
| 2335 2352 | 
             
                start = if item['title'] =~ /@start\((\d{4}-\d\d-\d\d \d\d:\d\d.*?)\)/
         | 
| @@ -2340,20 +2357,34 @@ EOS | |
| 2340 2357 |  | 
| 2341 2358 | 
             
                seconds = (done - start).to_i
         | 
| 2342 2359 |  | 
| 2360 | 
            +
                if record
         | 
| 2361 | 
            +
                  record_tag_times(item, seconds)
         | 
| 2362 | 
            +
                end
         | 
| 2363 | 
            +
             | 
| 2364 | 
            +
                @interval_cache[item['title']] = seconds
         | 
| 2365 | 
            +
             | 
| 2366 | 
            +
                return seconds > 0 ? seconds : false unless formatted
         | 
| 2367 | 
            +
             | 
| 2368 | 
            +
                seconds > 0 ? '%02d:%02d:%02d' % fmt_time(seconds) : false
         | 
| 2369 | 
            +
              end
         | 
| 2370 | 
            +
             | 
| 2371 | 
            +
              ##
         | 
| 2372 | 
            +
              ## @brief      Record times for item tags
         | 
| 2373 | 
            +
              ##
         | 
| 2374 | 
            +
              ## @param      item  The item
         | 
| 2375 | 
            +
              ##
         | 
| 2376 | 
            +
              def record_tag_times(item, seconds)
         | 
| 2377 | 
            +
                return if @recorded_items.include?(item)
         | 
| 2378 | 
            +
             | 
| 2343 2379 | 
             
                item['title'].scan(/(?mi)@(\S+?)(\(.*\))?(?=\s|$)/).each do |m|
         | 
| 2344 2380 | 
             
                  k = m[0] == 'done' ? 'All' : m[0].downcase
         | 
| 2345 | 
            -
                  if @timers. | 
| 2381 | 
            +
                  if @timers.key?(k)
         | 
| 2346 2382 | 
             
                    @timers[k] += seconds
         | 
| 2347 2383 | 
             
                  else
         | 
| 2348 2384 | 
             
                    @timers[k] = seconds
         | 
| 2349 2385 | 
             
                  end
         | 
| 2386 | 
            +
                  @recorded_items.push(item)
         | 
| 2350 2387 | 
             
                end
         | 
| 2351 | 
            -
             | 
| 2352 | 
            -
                @interval_cache[item['title']] = seconds
         | 
| 2353 | 
            -
             | 
| 2354 | 
            -
                return seconds unless formatted
         | 
| 2355 | 
            -
             | 
| 2356 | 
            -
                seconds > 0 ? '%02d:%02d:%02d' % fmt_time(seconds) : false
         | 
| 2357 2388 | 
             
              end
         | 
| 2358 2389 |  | 
| 2359 2390 | 
             
              ##
         | 
    
        data/lib/doing.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: doing
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 1.0. | 
| 4 | 
            +
              version: 1.0.83
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Brett Terpstra
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2021- | 
| 11 | 
            +
            date: 2021-10-13 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: rake
         |