doing 2.0.8.pre → 2.0.9.pre
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/CHANGELOG.md +7 -20
- data/Gemfile.lock +1 -1
- data/README.md +1 -1
- data/bin/doing +145 -12
- data/doing.rdoc +143 -10
- data/lib/doing/item.rb +7 -2
- data/lib/doing/string.rb +22 -0
- data/lib/doing/version.rb +1 -1
- data/lib/doing/wwid.rb +14 -9
- metadata +1 -1
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: f63df319758e6575ab75de3305ed9e44ac272d54b026e6873397970780115cca
         | 
| 4 | 
            +
              data.tar.gz: e770a9679824aae9582ca1cedb23e783d0bb1070b1c740d7ce662d912124006d
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 10bcf3f91db5636bb4133323b09a22f0978d3955e0e564931edef9cf8b9416aa4f7fa0480588dd85b95eab7cdb1f8952a843dce755bed6fc5dfd108ee60ea8ce
         | 
| 7 | 
            +
              data.tar.gz: 23a73fa1f03cb28afaca764296a52140a6f7eb772add3db3220b255c51831cb5c2eb97a9f103000788fd06998bf8389dcac62618880a84fadfa5b209e1c718da
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,22 +1,14 @@ | |
| 1 | 
            -
            ### 2.0. | 
| 2 | 
            -
             | 
| 3 | 
            -
            #### NEW
         | 
| 4 | 
            -
             | 
| 5 | 
            -
            - Add `--exact` flag to all commands with `--search` flag to force exact matching without requiring single quote prefix
         | 
| 6 | 
            -
            - Add `--not` flag to all commands with filters (--tag, --search, --before, etc.) to negate the filter and return entries NOT matched
         | 
| 7 | 
            -
             | 
| 8 | 
            -
            ### 2.0.7.pre
         | 
| 9 | 
            -
             | 
| 10 | 
            -
            #### FIXED
         | 
| 11 | 
            -
             | 
| 12 | 
            -
            - Zsh completion not outputting results
         | 
| 13 | 
            -
             | 
| 14 | 
            -
            ### 2.0.6.pre
         | 
| 1 | 
            +
            ### 2.0.9.pre
         | 
| 15 2 |  | 
| 16 3 | 
             
            #### NEW
         | 
| 17 4 |  | 
| 5 | 
            +
            - Add 'timer_format' config with 'human' option for tag totals
         | 
| 18 6 | 
             
            - If `doing view` and `doing show` are confused, offer option to run the other command
         | 
| 19 7 | 
             
            - `doing completion` to generate shell completion scripts for zsh, bash, and fish
         | 
| 8 | 
            +
            - --search and --not for cancel command
         | 
| 9 | 
            +
            - --case flag for commands with --search. Can be (c)ase-sensitive, (i)nsensitive, or (s)mart (default smart, case insensitive unless search string contains uppercase letters)
         | 
| 10 | 
            +
            - Add `--exact` flag to all commands with `--search` flag to force exact matching without requiring single quote prefix
         | 
| 11 | 
            +
            - Add `--not` flag to all commands with filters (--tag, --search, --before, etc.) to negate the filter and return entries NOT matched
         | 
| 20 12 |  | 
| 21 13 | 
             
            #### IMPROVED
         | 
| 22 14 |  | 
| @@ -27,16 +19,11 @@ | |
| 27 19 |  | 
| 28 20 | 
             
            #### FIXED
         | 
| 29 21 |  | 
| 22 | 
            +
            - Zsh completion not outputting results
         | 
| 30 23 | 
             
            - Remove `--[no]` from non-negatable options
         | 
| 31 24 | 
             
            - `doing plugins -t export -c` not outputting columns
         | 
| 32 25 | 
             
            - View config not respecting tag_order setting
         | 
| 33 26 |  | 
| 34 | 
            -
            ### 2.0.5.pre
         | 
| 35 | 
            -
             | 
| 36 | 
            -
            #### NEW
         | 
| 37 | 
            -
             | 
| 38 | 
            -
            - Add 'timer_format' config with 'human' option for tag totals
         | 
| 39 | 
            -
             | 
| 40 27 | 
             
            ### 2.0.3.pre
         | 
| 41 28 |  | 
| 42 29 | 
             
            #### NEW
         | 
    
        data/Gemfile.lock
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -6,7 +6,7 @@ _If you're one of the rare people like me who find this useful, feel free to [bu | |
| 6 6 |  | 
| 7 7 | 
             
            <!--README-->
         | 
| 8 8 |  | 
| 9 | 
            -
            The current version of `doing` is <!--VER-->2.0. | 
| 9 | 
            +
            The current version of `doing` is <!--VER-->2.0.8<!--END VER-->.
         | 
| 10 10 |  | 
| 11 11 | 
             
            Find all of the documentation in the [doing wiki](https://github.com/ttscoff/doing/wiki).
         | 
| 12 12 |  | 
    
        data/bin/doing
    CHANGED
    
    | @@ -62,7 +62,10 @@ if settings.dig('plugins', 'command_path') | |
| 62 62 | 
             
            end
         | 
| 63 63 |  | 
| 64 64 | 
             
            program_desc 'A CLI for a What Was I Doing system'
         | 
| 65 | 
            -
            program_long_desc %(Doing uses a TaskPaper-like formatting to keep a plain text | 
| 65 | 
            +
            program_long_desc %(Doing uses a TaskPaper-like formatting to keep a plain text
         | 
| 66 | 
            +
            record of what you've been doing, complete with tag-based time tracking. The
         | 
| 67 | 
            +
            command line tool allows you to add entries, annotate with tags and notes, and
         | 
| 68 | 
            +
            view your entries with myriad options, with a focus on a "natural" language syntax.)
         | 
| 66 69 |  | 
| 67 70 | 
             
            default_command :recent
         | 
| 68 71 | 
             
            # sort_help :manually
         | 
| @@ -201,6 +204,10 @@ command %i[reset begin] do |c| | |
| 201 204 | 
             
              c.desc 'Reset items that *don\'t* match search/tag filters'
         | 
| 202 205 | 
             
              c.switch [:not], default_value: false, negatable: false
         | 
| 203 206 |  | 
| 207 | 
            +
              c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]'
         | 
| 208 | 
            +
              c.arg_name 'TYPE'
         | 
| 209 | 
            +
              c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
         | 
| 210 | 
            +
             | 
| 204 211 | 
             
              c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters'
         | 
| 205 212 | 
             
              c.arg_name 'BOOLEAN'
         | 
| 206 213 | 
             
              c.flag [:bool], must_match: REGEX_BOOL, default_value: 'AND'
         | 
| @@ -213,7 +220,9 @@ command %i[reset begin] do |c| | |
| 213 220 | 
             
                  options[:section] = wwid.guess_section(options[:section]) || options[:section].cap_first
         | 
| 214 221 | 
             
                end
         | 
| 215 222 |  | 
| 216 | 
            -
                options[: | 
| 223 | 
            +
                options[:bool] = options[:bool].normalize_bool
         | 
| 224 | 
            +
             | 
| 225 | 
            +
                options[:case] = options[:case].normalize_case
         | 
| 217 226 |  | 
| 218 227 | 
             
                if options[:search]
         | 
| 219 228 | 
             
                  search = options[:search]
         | 
| @@ -261,6 +270,11 @@ long_desc %( | |
| 261 270 | 
             
            )
         | 
| 262 271 | 
             
            arg_name 'NOTE_TEXT'
         | 
| 263 272 | 
             
            command :note do |c|
         | 
| 273 | 
            +
              c.example 'doing note', desc: 'Open the last entry in $EDITOR to append a note'
         | 
| 274 | 
            +
              c.example 'doing note "Just a quick annotation"', desc: 'Add a quick note to the last entry'
         | 
| 275 | 
            +
              c.example 'doing note --tag done "Keeping it real or something"', desc: 'Add a note to the last item tagged @done'
         | 
| 276 | 
            +
              c.example 'doing note --search "late night" -e', desc: 'Open $EDITOR to add a note to the last item containing "late night" (fuzzy matched)'
         | 
| 277 | 
            +
             | 
| 264 278 | 
             
              c.desc 'Section'
         | 
| 265 279 | 
             
              c.arg_name 'NAME'
         | 
| 266 280 | 
             
              c.flag %i[s section], default_value: 'All'
         | 
| @@ -285,6 +299,10 @@ command :note do |c| | |
| 285 299 | 
             
              c.desc 'Add note to item that *doesn\'t* match search/tag filters'
         | 
| 286 300 | 
             
              c.switch [:not], default_value: false, negatable: false
         | 
| 287 301 |  | 
| 302 | 
            +
              c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]'
         | 
| 303 | 
            +
              c.arg_name 'TYPE'
         | 
| 304 | 
            +
              c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
         | 
| 305 | 
            +
             | 
| 288 306 | 
             
              c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters'
         | 
| 289 307 | 
             
              c.arg_name 'BOOLEAN'
         | 
| 290 308 | 
             
              c.flag [:bool], must_match: REGEX_BOOL, default_value: 'AND'
         | 
| @@ -299,6 +317,8 @@ command :note do |c| | |
| 299 317 |  | 
| 300 318 | 
             
                options[:tag_bool] = options[:bool].normalize_bool
         | 
| 301 319 |  | 
| 320 | 
            +
                options[:case] = options[:case].normalize_case
         | 
| 321 | 
            +
             | 
| 302 322 | 
             
                if options[:search]
         | 
| 303 323 | 
             
                  search = options[:search]
         | 
| 304 324 | 
             
                  search.sub!(/^'?/, "'") if options[:exact]
         | 
| @@ -356,6 +376,11 @@ end | |
| 356 376 | 
             
            desc 'Finish any running @meanwhile tasks and optionally create a new one'
         | 
| 357 377 | 
             
            arg_name 'ENTRY'
         | 
| 358 378 | 
             
            command :meanwhile do |c|
         | 
| 379 | 
            +
              c.example 'doing meanwhile "Long task that will have others after it before it\'s done"', desc: 'Add a new long-running entry, completing any current @meanwhile entry'
         | 
| 380 | 
            +
              c.example 'doing meanwhile', desc: 'Finish any open @meanwhile entry'
         | 
| 381 | 
            +
              c.example 'doing meanwhile --archive', desc: 'Finish any open @meanwhile entry and archive it'
         | 
| 382 | 
            +
              c.example 'doing meanwhile --back 2h "Something I\'ve been working on for a while', desc: 'Add a @meanwhile entry with a start date 2 hours ago'
         | 
| 383 | 
            +
             | 
| 359 384 | 
             
              c.desc 'Section'
         | 
| 360 385 | 
             
              c.arg_name 'NAME'
         | 
| 361 386 | 
             
              c.flag %i[s section]
         | 
| @@ -422,12 +447,12 @@ end | |
| 422 447 | 
             
            desc 'Output HTML, CSS, and Markdown (ERB) templates for customization'
         | 
| 423 448 | 
             
            long_desc %(
         | 
| 424 449 | 
             
              Templates are printed to STDOUT for piping to a file.
         | 
| 425 | 
            -
              Save them and use them in the configuration file under  | 
| 426 | 
            -
             | 
| 427 | 
            -
              Example `doing template haml > ~/styles/my_doing.haml`
         | 
| 450 | 
            +
              Save them and use them in the configuration file under export_templates.
         | 
| 428 451 | 
             
            )
         | 
| 429 452 | 
             
            arg_name 'TYPE', must_match: Doing::Plugins.template_regex
         | 
| 430 453 | 
             
            command :template do |c|
         | 
| 454 | 
            +
              c.example 'doing template haml > ~/styles/my_doing.haml', desc: 'Output the haml template and save it to a file'
         | 
| 455 | 
            +
             | 
| 431 456 | 
             
              c.desc 'List all available templates'
         | 
| 432 457 | 
             
              c.switch %i[l list], negatable: false
         | 
| 433 458 |  | 
| @@ -505,6 +530,10 @@ command :select do |c| | |
| 505 530 | 
             
              c.desc 'Select items that *don\'t* match search/tag filters'
         | 
| 506 531 | 
             
              c.switch [:not], default_value: false, negatable: false
         | 
| 507 532 |  | 
| 533 | 
            +
              c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]'
         | 
| 534 | 
            +
              c.arg_name 'TYPE'
         | 
| 535 | 
            +
              c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
         | 
| 536 | 
            +
             | 
| 508 537 | 
             
              c.desc 'Use --no-menu to skip the interactive menu. Use with --query to filter items and act on results automatically. Test with `--output doing` to preview matches.'
         | 
| 509 538 | 
             
              c.switch %i[menu], negatable: true, default_value: true
         | 
| 510 539 |  | 
| @@ -542,6 +571,8 @@ command :select do |c| | |
| 542 571 |  | 
| 543 572 | 
             
                raise InvalidArgument, '--no-menu requires --query' if !options[:menu] && !options[:query]
         | 
| 544 573 |  | 
| 574 | 
            +
                options[:case] = options[:case].normalize_case
         | 
| 575 | 
            +
             | 
| 545 576 | 
             
                wwid.interactive(options)
         | 
| 546 577 | 
             
              end
         | 
| 547 578 | 
             
            end
         | 
| @@ -549,6 +580,9 @@ end | |
| 549 580 | 
             
            desc 'Add an item to the Later section'
         | 
| 550 581 | 
             
            arg_name 'ENTRY'
         | 
| 551 582 | 
             
            command :later do |c|
         | 
| 583 | 
            +
              c.example 'doing later "Something I\'ll think about tomorrow"', desc: 'Add an entry to the Later section'
         | 
| 584 | 
            +
              c.example 'doing later -e', desc: 'Open $EDITOR to create an entry and optional note'
         | 
| 585 | 
            +
             | 
| 552 586 | 
             
              c.desc "Edit entry with #{Doing::Util.default_editor}"
         | 
| 553 587 | 
             
              c.switch %i[e editor], negatable: false, default_value: false
         | 
| 554 588 |  | 
| @@ -598,6 +632,11 @@ end | |
| 598 632 | 
             
            desc 'Add a completed item with @done(date). No argument finishes last entry.'
         | 
| 599 633 | 
             
            arg_name 'ENTRY'
         | 
| 600 634 | 
             
            command %i[done did] do |c|
         | 
| 635 | 
            +
              c.example 'doing done', desc: 'Tag the last entry @done'
         | 
| 636 | 
            +
              c.example 'doing done I already finished this', desc: 'Add a new entry and immediately mark it @done'
         | 
| 637 | 
            +
              c.example 'doing done --back 30m This took me half an hour', desc: 'Add an entry with a start date 30 minutes ago and a @done date of right now'
         | 
| 638 | 
            +
              c.example 'doing done --at 3pm --took 1h Started and finished this afternoon', desc: 'Add an entry with a @done date of 3pm and a start date of 2pm (3pm - 1h)'
         | 
| 639 | 
            +
             | 
| 601 640 | 
             
              c.desc 'Remove @done tag'
         | 
| 602 641 | 
             
              c.switch %i[r remove], negatable: false, default_value: false
         | 
| 603 642 |  | 
| @@ -787,6 +826,9 @@ desc 'End last X entries with no time tracked' | |
| 787 826 | 
             
            long_desc 'Adds @done tag without datestamp so no elapsed time is recorded. Alias for `doing finish --no-date`.'
         | 
| 788 827 | 
             
            arg_name 'COUNT'
         | 
| 789 828 | 
             
            command :cancel do |c|
         | 
| 829 | 
            +
              c.example 'doing cancel', desc: 'Cancel the last entry'
         | 
| 830 | 
            +
              c.example 'doing cancel --tag project1 -u 5', desc: 'Cancel the last 5 unfinished entries containing @project1'
         | 
| 831 | 
            +
             | 
| 790 832 | 
             
              c.desc 'Archive entries'
         | 
| 791 833 | 
             
              c.switch %i[a archive], negatable: false, default_value: false
         | 
| 792 834 |  | 
| @@ -802,6 +844,20 @@ command :cancel do |c| | |
| 802 844 | 
             
              c.arg_name 'BOOLEAN'
         | 
| 803 845 | 
             
              c.flag [:bool], must_match: REGEX_BOOL, default_value: 'AND'
         | 
| 804 846 |  | 
| 847 | 
            +
              c.desc 'Cancel the last X entries matching search filter, surround with slashes for regex (e.g. "/query.*/"), start with single quote for exact match ("\'query")'
         | 
| 848 | 
            +
              c.arg_name 'QUERY'
         | 
| 849 | 
            +
              c.flag [:search]
         | 
| 850 | 
            +
             | 
| 851 | 
            +
              c.desc 'Force exact search string matching (case sensitive)'
         | 
| 852 | 
            +
              c.switch %i[x exact], default_value: false, negatable: false
         | 
| 853 | 
            +
             | 
| 854 | 
            +
              c.desc 'Finish items that *don\'t* match search/tag filters'
         | 
| 855 | 
            +
              c.switch [:not], default_value: false, negatable: false
         | 
| 856 | 
            +
             | 
| 857 | 
            +
              c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]'
         | 
| 858 | 
            +
              c.arg_name 'TYPE'
         | 
| 859 | 
            +
              c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
         | 
| 860 | 
            +
             | 
| 805 861 | 
             
              c.desc 'Cancel last entry (or entries) not already marked @done'
         | 
| 806 862 | 
             
              c.switch %i[u unfinished], negatable: false, default_value: false
         | 
| 807 863 |  | 
| @@ -831,7 +887,17 @@ command :cancel do |c| | |
| 831 887 | 
             
                  count = args[0] ? args[0].to_i : 1
         | 
| 832 888 | 
             
                end
         | 
| 833 889 |  | 
| 890 | 
            +
                search = nil
         | 
| 891 | 
            +
             | 
| 892 | 
            +
                if options[:search]
         | 
| 893 | 
            +
                  search = options[:search]
         | 
| 894 | 
            +
                  search.sub!(/^'?/, "'") if options[:exact]
         | 
| 895 | 
            +
                end
         | 
| 896 | 
            +
             | 
| 834 897 | 
             
                opts = {
         | 
| 898 | 
            +
                  search: search,
         | 
| 899 | 
            +
                  case: options[:case].normalize_case,
         | 
| 900 | 
            +
                  not: options[:not],
         | 
| 835 901 | 
             
                  archive: options[:a],
         | 
| 836 902 | 
             
                  count: count,
         | 
| 837 903 | 
             
                  date: false,
         | 
| @@ -852,6 +918,10 @@ desc 'Mark last X entries as @done' | |
| 852 918 | 
             
            long_desc 'Marks the last X entries with a @done tag and current date. Does not alter already completed entries.'
         | 
| 853 919 | 
             
            arg_name 'COUNT'
         | 
| 854 920 | 
             
            command :finish do |c|
         | 
| 921 | 
            +
              c.example 'doing finish', desc: 'Mark the last entry @done'
         | 
| 922 | 
            +
              c.example 'doing finish --auto --section Later 10', desc: 'Add @done to any unfinished entries in the last 10 in Later, setting the finish time based on the start time of the task after it'
         | 
| 923 | 
            +
              c.example 'doing finish --search "a specific entry" --at "yesterday 3pm"', desc: 'Search for an entry containing string and set its @done time to yesterday at 3pm'
         | 
| 924 | 
            +
             | 
| 855 925 | 
             
              c.desc 'Include date'
         | 
| 856 926 | 
             
              c.switch [:date], negatable: true, default_value: true
         | 
| 857 927 |  | 
| @@ -882,6 +952,10 @@ command :finish do |c| | |
| 882 952 | 
             
              c.desc 'Finish items that *don\'t* match search/tag filters'
         | 
| 883 953 | 
             
              c.switch [:not], default_value: false, negatable: false
         | 
| 884 954 |  | 
| 955 | 
            +
              c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]'
         | 
| 956 | 
            +
              c.arg_name 'TYPE'
         | 
| 957 | 
            +
              c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
         | 
| 958 | 
            +
             | 
| 885 959 | 
             
              c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters'
         | 
| 886 960 | 
             
              c.arg_name 'BOOLEAN'
         | 
| 887 961 | 
             
              c.flag [:bool], must_match: REGEX_BOOL, default_value: 'AND'
         | 
| @@ -963,6 +1037,7 @@ command :finish do |c| | |
| 963 1037 | 
             
                  count: count,
         | 
| 964 1038 | 
             
                  date: options[:date],
         | 
| 965 1039 | 
             
                  search: search,
         | 
| 1040 | 
            +
                  case: options[:case].normalize_case,
         | 
| 966 1041 | 
             
                  not: options[:not],
         | 
| 967 1042 | 
             
                  section: options[:section],
         | 
| 968 1043 | 
             
                  sequential: options[:auto],
         | 
| @@ -1003,6 +1078,10 @@ command %i[again resume] do |c| | |
| 1003 1078 | 
             
              c.desc 'Resume items that *don\'t* match search/tag filters'
         | 
| 1004 1079 | 
             
              c.switch [:not], default_value: false, negatable: false
         | 
| 1005 1080 |  | 
| 1081 | 
            +
              c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]'
         | 
| 1082 | 
            +
              c.arg_name 'TYPE'
         | 
| 1083 | 
            +
              c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
         | 
| 1084 | 
            +
             | 
| 1006 1085 | 
             
              c.desc 'Boolean used to combine multiple tags'
         | 
| 1007 1086 | 
             
              c.arg_name 'BOOLEAN'
         | 
| 1008 1087 | 
             
              c.flag [:bool], must_match: REGEX_BOOL, default_value: 'AND'
         | 
| @@ -1020,6 +1099,8 @@ command %i[again resume] do |c| | |
| 1020 1099 | 
             
              c.action do |_global_options, options, _args|
         | 
| 1021 1100 | 
             
                tags = options[:tag].nil? ? [] : options[:tag].to_tags
         | 
| 1022 1101 |  | 
| 1102 | 
            +
                options[:case] = options[:case].normalize_case
         | 
| 1103 | 
            +
             | 
| 1023 1104 | 
             
                if options[:search]
         | 
| 1024 1105 | 
             
                  search = options[:search]
         | 
| 1025 1106 | 
             
                  search.sub!(/^'?/, "'") if options[:exact]
         | 
| @@ -1103,6 +1184,10 @@ command :tag do |c| | |
| 1103 1184 | 
             
              c.desc 'Tag items that *don\'t* match search/tag filters'
         | 
| 1104 1185 | 
             
              c.switch [:not], default_value: false, negatable: false
         | 
| 1105 1186 |  | 
| 1187 | 
            +
              c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]'
         | 
| 1188 | 
            +
              c.arg_name 'TYPE'
         | 
| 1189 | 
            +
              c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
         | 
| 1190 | 
            +
             | 
| 1106 1191 | 
             
              c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters'
         | 
| 1107 1192 | 
             
              c.arg_name 'BOOLEAN'
         | 
| 1108 1193 | 
             
              c.flag [:bool], must_match: REGEX_BOOL, default_value: 'AND'
         | 
| @@ -1147,6 +1232,8 @@ command :tag do |c| | |
| 1147 1232 | 
             
                  count = options[:count].to_i
         | 
| 1148 1233 | 
             
                end
         | 
| 1149 1234 |  | 
| 1235 | 
            +
                options[:case] = options[:case].normalize_case
         | 
| 1236 | 
            +
             | 
| 1150 1237 | 
             
                if options[:search]
         | 
| 1151 1238 | 
             
                  search = options[:search]
         | 
| 1152 1239 | 
             
                  search.sub!(/^'?/, "'") if options[:exact]
         | 
| @@ -1229,6 +1316,10 @@ command [:mark, :flag] do |c| | |
| 1229 1316 | 
             
              c.desc 'Flag items that *don\'t* match search/tag/date filters'
         | 
| 1230 1317 | 
             
              c.switch [:not], default_value: false, negatable: false
         | 
| 1231 1318 |  | 
| 1319 | 
            +
              c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]'
         | 
| 1320 | 
            +
              c.arg_name 'TYPE'
         | 
| 1321 | 
            +
              c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
         | 
| 1322 | 
            +
             | 
| 1232 1323 | 
             
              c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters'
         | 
| 1233 1324 | 
             
              c.arg_name 'BOOLEAN'
         | 
| 1234 1325 | 
             
              c.flag [:bool], must_match: REGEX_BOOL, default_value: 'AND'
         | 
| @@ -1260,6 +1351,8 @@ command [:mark, :flag] do |c| | |
| 1260 1351 | 
             
                  count = options[:count].to_i
         | 
| 1261 1352 | 
             
                end
         | 
| 1262 1353 |  | 
| 1354 | 
            +
                options[:case] = options[:case].normalize_case
         | 
| 1355 | 
            +
             | 
| 1263 1356 | 
             
                if options[:search]
         | 
| 1264 1357 | 
             
                  search = options[:search]
         | 
| 1265 1358 | 
             
                  search.sub!(/^'?/, "'") if options[:exact]
         | 
| @@ -1346,6 +1439,10 @@ command :show do |c| | |
| 1346 1439 | 
             
              c.desc 'Show items that *don\'t* match search/tag/date filters'
         | 
| 1347 1440 | 
             
              c.switch [:not], default_value: false, negatable: false
         | 
| 1348 1441 |  | 
| 1442 | 
            +
              c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]'
         | 
| 1443 | 
            +
              c.arg_name 'TYPE'
         | 
| 1444 | 
            +
              c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
         | 
| 1445 | 
            +
             | 
| 1349 1446 | 
             
              c.desc 'Sort order (asc/desc)'
         | 
| 1350 1447 | 
             
              c.arg_name 'ORDER'
         | 
| 1351 1448 | 
             
              c.flag %i[s sort], must_match: REGEX_SORT_ORDER, default_value: 'asc'
         | 
| @@ -1450,6 +1547,8 @@ command :show do |c| | |
| 1450 1547 |  | 
| 1451 1548 | 
             
                tags_color = settings.key?('tags_color') ? settings['tags_color'] : nil
         | 
| 1452 1549 |  | 
| 1550 | 
            +
                options[:case] = options[:case].normalize_case
         | 
| 1551 | 
            +
             | 
| 1453 1552 | 
             
                if options[:search]
         | 
| 1454 1553 | 
             
                  search = options[:search]
         | 
| 1455 1554 | 
             
                  search.sub!(/^'?/, "'") if options[:exact]
         | 
| @@ -1521,12 +1620,13 @@ command %i[grep search] do |c| | |
| 1521 1620 | 
             
              c.desc 'Force exact string matching (case sensitive)'
         | 
| 1522 1621 | 
             
              c.switch %i[x exact], default_value: false, negatable: false
         | 
| 1523 1622 |  | 
| 1524 | 
            -
              c.desc 'Force case sensitive matching'
         | 
| 1525 | 
            -
              c.switch %i[case]
         | 
| 1526 | 
            -
             | 
| 1527 1623 | 
             
              c.desc 'Show items that *don\'t* match search string'
         | 
| 1528 1624 | 
             
              c.switch [:not], default_value: false, negatable: false
         | 
| 1529 1625 |  | 
| 1626 | 
            +
              c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]'
         | 
| 1627 | 
            +
              c.arg_name 'TYPE'
         | 
| 1628 | 
            +
              c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
         | 
| 1629 | 
            +
             | 
| 1530 1630 | 
             
              c.desc 'Display an interactive menu of results to perform further operations'
         | 
| 1531 1631 | 
             
              c.switch %i[i interactive], default_value: false, negatable: false
         | 
| 1532 1632 |  | 
| @@ -1536,6 +1636,9 @@ command %i[grep search] do |c| | |
| 1536 1636 | 
             
                tags_color = settings.key?('tags_color') ? settings['tags_color'] : nil
         | 
| 1537 1637 |  | 
| 1538 1638 | 
             
                section = wwid.guess_section(options[:section]) if options[:section]
         | 
| 1639 | 
            +
             | 
| 1640 | 
            +
                options[:case] = options[:case].normalize_case
         | 
| 1641 | 
            +
             | 
| 1539 1642 | 
             
                search = args.join(' ')
         | 
| 1540 1643 | 
             
                search.sub!(/^'?/, "'") if options[:exact]
         | 
| 1541 1644 |  | 
| @@ -1866,6 +1969,10 @@ command :last do |c| | |
| 1866 1969 | 
             
              c.desc 'Show items that *don\'t* match search string or tag filter'
         | 
| 1867 1970 | 
             
              c.switch [:not], default_value: false, negatable: false
         | 
| 1868 1971 |  | 
| 1972 | 
            +
              c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]'
         | 
| 1973 | 
            +
              c.arg_name 'TYPE'
         | 
| 1974 | 
            +
              c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
         | 
| 1975 | 
            +
             | 
| 1869 1976 | 
             
              c.action do |global_options, options, _args|
         | 
| 1870 1977 | 
             
                raise InvalidArgument, '--tag and --search can not be used together' if options[:tag] && options[:search]
         | 
| 1871 1978 |  | 
| @@ -1884,6 +1991,8 @@ command :last do |c| | |
| 1884 1991 |  | 
| 1885 1992 | 
             
                end
         | 
| 1886 1993 |  | 
| 1994 | 
            +
                options[:case] = options[:case].normalize_case
         | 
| 1995 | 
            +
             | 
| 1887 1996 | 
             
                search = nil
         | 
| 1888 1997 |  | 
| 1889 1998 | 
             
                if options[:search]
         | 
| @@ -1892,10 +2001,10 @@ command :last do |c| | |
| 1892 2001 | 
             
                end
         | 
| 1893 2002 |  | 
| 1894 2003 | 
             
                if options[:editor]
         | 
| 1895 | 
            -
                  wwid.edit_last(section: options[:s], options: { search: search, tag: tags, tag_bool: options[:bool], not: options[:not] })
         | 
| 2004 | 
            +
                  wwid.edit_last(section: options[:s], options: { search: search, case: options[:case], tag: tags, tag_bool: options[:bool], not: options[:not] })
         | 
| 1896 2005 | 
             
                else
         | 
| 1897 2006 | 
             
                  Doing::Pager::page wwid.last(times: true, section: options[:s],
         | 
| 1898 | 
            -
                                 options: { search: search, negate: options[:not], tag: tags, tag_bool: options[:bool] }).strip
         | 
| 2007 | 
            +
                                 options: { search: search, case: options[:case], negate: options[:not], tag: tags, tag_bool: options[:bool] }).strip
         | 
| 1899 2008 | 
             
                end
         | 
| 1900 2009 | 
             
              end
         | 
| 1901 2010 | 
             
            end
         | 
| @@ -2059,6 +2168,10 @@ command :view do |c| | |
| 2059 2168 | 
             
              c.desc 'Show items that *don\'t* match search string'
         | 
| 2060 2169 | 
             
              c.switch [:not], default_value: false, negatable: false
         | 
| 2061 2170 |  | 
| 2171 | 
            +
              c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]'
         | 
| 2172 | 
            +
              c.arg_name 'TYPE'
         | 
| 2173 | 
            +
              c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
         | 
| 2174 | 
            +
             | 
| 2062 2175 | 
             
              c.desc 'Sort tags by (name|time)'
         | 
| 2063 2176 | 
             
              c.arg_name 'KEY'
         | 
| 2064 2177 | 
             
              c.flag [:tag_sort], must_match: /^(?:name|time)$/i
         | 
| @@ -2190,6 +2303,8 @@ command :view do |c| | |
| 2190 2303 | 
             
                    dates = [start, finish]
         | 
| 2191 2304 | 
             
                  end
         | 
| 2192 2305 |  | 
| 2306 | 
            +
                  options[:case] = options[:case].normalize_case
         | 
| 2307 | 
            +
             | 
| 2193 2308 | 
             
                  search = nil
         | 
| 2194 2309 |  | 
| 2195 2310 | 
             
                  if options[:search]
         | 
| @@ -2197,7 +2312,7 @@ command :view do |c| | |
| 2197 2312 | 
             
                    search.sub!(/^'?/, "'") if options[:exact]
         | 
| 2198 2313 | 
             
                  end
         | 
| 2199 2314 |  | 
| 2200 | 
            -
                  opts = options
         | 
| 2315 | 
            +
                  opts = options.dup
         | 
| 2201 2316 | 
             
                  opts[:search] = search
         | 
| 2202 2317 | 
             
                  opts[:output] = output_format
         | 
| 2203 2318 | 
             
                  opts[:count] = count
         | 
| @@ -2277,6 +2392,10 @@ command %i[archive move] do |c| | |
| 2277 2392 | 
             
              c.desc 'Show items that *don\'t* match search string'
         | 
| 2278 2393 | 
             
              c.switch [:not], default_value: false, negatable: false
         | 
| 2279 2394 |  | 
| 2395 | 
            +
              c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]'
         | 
| 2396 | 
            +
              c.arg_name 'TYPE'
         | 
| 2397 | 
            +
              c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
         | 
| 2398 | 
            +
             | 
| 2280 2399 | 
             
              c.desc 'Archive entries older than date
         | 
| 2281 2400 | 
             
                (Flexible date format, e.g. 1/27/2021, 2020-07-19, or Monday 3pm)'
         | 
| 2282 2401 | 
             
              c.arg_name 'DATE_STRING'
         | 
| @@ -2302,12 +2421,14 @@ command %i[archive move] do |c| | |
| 2302 2421 |  | 
| 2303 2422 | 
             
                search = nil
         | 
| 2304 2423 |  | 
| 2424 | 
            +
                options[:case] = options[:case].normalize_case
         | 
| 2425 | 
            +
             | 
| 2305 2426 | 
             
                if options[:search]
         | 
| 2306 2427 | 
             
                  search = options[:search]
         | 
| 2307 2428 | 
             
                  search.sub!(/^'?/, "'") if options[:exact]
         | 
| 2308 2429 | 
             
                end
         | 
| 2309 2430 |  | 
| 2310 | 
            -
                opts = options
         | 
| 2431 | 
            +
                opts = options.dup
         | 
| 2311 2432 | 
             
                opts[:search] = search
         | 
| 2312 2433 | 
             
                opts[:bool] = options[:bool].normalize_bool
         | 
| 2313 2434 | 
             
                opts[:destination] = options[:to]
         | 
| @@ -2349,6 +2470,10 @@ command :rotate do |c| | |
| 2349 2470 | 
             
              c.desc 'Rotate items that *don\'t* match search string or tag filter'
         | 
| 2350 2471 | 
             
              c.switch [:not], default_value: false, negatable: false
         | 
| 2351 2472 |  | 
| 2473 | 
            +
              c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]'
         | 
| 2474 | 
            +
              c.arg_name 'TYPE'
         | 
| 2475 | 
            +
              c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
         | 
| 2476 | 
            +
             | 
| 2352 2477 | 
             
              c.desc 'Rotate entries older than date
         | 
| 2353 2478 | 
             
                (Flexible date format, e.g. 1/27/2021, 2020-07-19, or Monday 3pm)'
         | 
| 2354 2479 | 
             
              c.arg_name 'DATE_STRING'
         | 
| @@ -2361,6 +2486,8 @@ command :rotate do |c| | |
| 2361 2486 |  | 
| 2362 2487 | 
             
                options[:bool] = options[:bool].normalize_bool
         | 
| 2363 2488 |  | 
| 2489 | 
            +
                options[:case] = options[:case].normalize_case
         | 
| 2490 | 
            +
             | 
| 2364 2491 | 
             
                search = nil
         | 
| 2365 2492 |  | 
| 2366 2493 | 
             
                if options[:search]
         | 
| @@ -2563,6 +2690,10 @@ command :import do |c| | |
| 2563 2690 | 
             
              c.desc 'Import items that *don\'t* match search/tag/date filters'
         | 
| 2564 2691 | 
             
              c.switch [:not], default_value: false, negatable: false
         | 
| 2565 2692 |  | 
| 2693 | 
            +
              c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]'
         | 
| 2694 | 
            +
              c.arg_name 'TYPE'
         | 
| 2695 | 
            +
              c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
         | 
| 2696 | 
            +
             | 
| 2566 2697 | 
             
              c.desc 'Only import items with recorded time intervals'
         | 
| 2567 2698 | 
             
              c.switch [:only_timed], default_value: false, negatable: false
         | 
| 2568 2699 |  | 
| @@ -2620,6 +2751,8 @@ command :import do |c| | |
| 2620 2751 | 
             
                  dates = [start, finish]
         | 
| 2621 2752 | 
             
                end
         | 
| 2622 2753 |  | 
| 2754 | 
            +
                options[:case] = options[:case].normalize_case
         | 
| 2755 | 
            +
             | 
| 2623 2756 | 
             
                if options[:type] =~ Doing::Plugins.plugin_regex(type: :import)
         | 
| 2624 2757 | 
             
                  options[:no_overlap] = !options[:overlap]
         | 
| 2625 2758 | 
             
                  options[:date_filter] = dates
         | 
    
        data/doing.rdoc
    CHANGED
    
    | @@ -1,8 +1,11 @@ | |
| 1 1 | 
             
            == doing - A CLI for a What Was I Doing system
         | 
| 2 2 |  | 
| 3 | 
            -
            Doing uses a TaskPaper-like formatting to keep a plain text | 
| 3 | 
            +
            Doing uses a TaskPaper-like formatting to keep a plain text
         | 
| 4 | 
            +
            record of what you've been doing, complete with tag-based time tracking. The
         | 
| 5 | 
            +
            command line tool allows you to add entries, annotate with tags and notes, and
         | 
| 6 | 
            +
            view your entries with myriad options, with a focus on a "natural" language syntax.
         | 
| 4 7 |  | 
| 5 | 
            -
            v2.0. | 
| 8 | 
            +
            v2.0.9.pre
         | 
| 6 9 |  | 
| 7 10 | 
             
            === Global Options
         | 
| 8 11 | 
             
            === --config_file arg
         | 
| @@ -87,6 +90,14 @@ Boolean used to combine multiple tags | |
| 87 90 | 
             
            [Must Match] (?i-mx:^(?:and|all|any|or|not|none)$)
         | 
| 88 91 |  | 
| 89 92 |  | 
| 93 | 
            +
            ===== --case TYPE
         | 
| 94 | 
            +
             | 
| 95 | 
            +
            Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]
         | 
| 96 | 
            +
             | 
| 97 | 
            +
            [Default Value] smart
         | 
| 98 | 
            +
            [Must Match] (?-mix:^[csi])
         | 
| 99 | 
            +
             | 
| 100 | 
            +
             | 
| 90 101 | 
             
            ===== --in SECTION_NAME
         | 
| 91 102 |  | 
| 92 103 | 
             
            Add new entry to section (default: same section as repeated entry)
         | 
| @@ -167,6 +178,14 @@ Tag boolean (AND|OR|NOT) | |
| 167 178 | 
             
            [Must Match] (?i-mx:^(?:and|all|any|or|not|none)$)
         | 
| 168 179 |  | 
| 169 180 |  | 
| 181 | 
            +
            ===== --case TYPE
         | 
| 182 | 
            +
             | 
| 183 | 
            +
            Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]
         | 
| 184 | 
            +
             | 
| 185 | 
            +
            [Default Value] smart
         | 
| 186 | 
            +
            [Must Match] (?-mix:^[csi])
         | 
| 187 | 
            +
             | 
| 188 | 
            +
             | 
| 170 189 | 
             
            ===== -k|--keep X
         | 
| 171 190 |  | 
| 172 191 | 
             
            How many items to keep (ignored if archiving by tag or search)
         | 
| @@ -284,6 +303,14 @@ Boolean (AND|OR|NOT) with which to combine multiple tag filters | |
| 284 303 | 
             
            [Must Match] (?i-mx:^(?:and|all|any|or|not|none)$)
         | 
| 285 304 |  | 
| 286 305 |  | 
| 306 | 
            +
            ===== --case TYPE
         | 
| 307 | 
            +
             | 
| 308 | 
            +
            Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]
         | 
| 309 | 
            +
             | 
| 310 | 
            +
            [Default Value] smart
         | 
| 311 | 
            +
            [Must Match] (?-mix:^[csi])
         | 
| 312 | 
            +
             | 
| 313 | 
            +
             | 
| 287 314 | 
             
            ===== -s|--section NAME
         | 
| 288 315 |  | 
| 289 316 | 
             
            Section
         | 
| @@ -291,6 +318,13 @@ Section | |
| 291 318 | 
             
            [Default Value] None
         | 
| 292 319 |  | 
| 293 320 |  | 
| 321 | 
            +
            ===== --search QUERY
         | 
| 322 | 
            +
             | 
| 323 | 
            +
            Cancel the last X entries matching search filter, surround with slashes for regex (e.g. "/query.*/"), start with single quote for exact match ("'query")
         | 
| 324 | 
            +
             | 
| 325 | 
            +
            [Default Value] None
         | 
| 326 | 
            +
             | 
| 327 | 
            +
             | 
| 294 328 | 
             
            ===== --tag TAG
         | 
| 295 329 |  | 
| 296 330 | 
             
            Cancel the last X entries containing TAG. Separate multiple tags with comma (--tag=tag1,tag2)
         | 
| @@ -308,11 +342,21 @@ Select item(s) to cancel from a menu of matching entries | |
| 308 342 |  | 
| 309 343 |  | 
| 310 344 |  | 
| 345 | 
            +
            ===== --not
         | 
| 346 | 
            +
            Finish items that *don't* match search/tag filters
         | 
| 347 | 
            +
             | 
| 348 | 
            +
             | 
| 349 | 
            +
             | 
| 311 350 | 
             
            ===== -u|--unfinished
         | 
| 312 351 | 
             
            Cancel last entry (or entries) not already marked @done
         | 
| 313 352 |  | 
| 314 353 |  | 
| 315 354 |  | 
| 355 | 
            +
            ===== -x|--exact
         | 
| 356 | 
            +
            Force exact search string matching (case sensitive)
         | 
| 357 | 
            +
             | 
| 358 | 
            +
             | 
| 359 | 
            +
             | 
| 316 360 | 
             
            ==== Command: <tt>choose </tt>
         | 
| 317 361 | 
             
            Select a section to display from a menu
         | 
| 318 362 |  | 
| @@ -493,6 +537,14 @@ Boolean (AND|OR|NOT) with which to combine multiple tag filters | |
| 493 537 | 
             
            [Must Match] (?i-mx:^(?:and|all|any|or|not|none)$)
         | 
| 494 538 |  | 
| 495 539 |  | 
| 540 | 
            +
            ===== --case TYPE
         | 
| 541 | 
            +
             | 
| 542 | 
            +
            Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]
         | 
| 543 | 
            +
             | 
| 544 | 
            +
            [Default Value] smart
         | 
| 545 | 
            +
            [Must Match] (?-mix:^[csi])
         | 
| 546 | 
            +
             | 
| 547 | 
            +
             | 
| 496 548 | 
             
            ===== -s|--section NAME
         | 
| 497 549 |  | 
| 498 550 | 
             
            Section
         | 
| @@ -585,6 +637,14 @@ Constrain search to entries older than date | |
| 585 637 | 
             
            [Default Value] None
         | 
| 586 638 |  | 
| 587 639 |  | 
| 640 | 
            +
            ===== --case TYPE
         | 
| 641 | 
            +
             | 
| 642 | 
            +
            Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]
         | 
| 643 | 
            +
             | 
| 644 | 
            +
            [Default Value] smart
         | 
| 645 | 
            +
            [Must Match] (?-mix:^[csi])
         | 
| 646 | 
            +
             | 
| 647 | 
            +
             | 
| 588 648 | 
             
            ===== -o|--output FORMAT
         | 
| 589 649 |  | 
| 590 650 | 
             
            Output to export format (csv|doing|html|markdown|say|taskpaper|template|timeline|wiki)
         | 
| @@ -607,11 +667,6 @@ Sort tags by (name|time) | |
| 607 667 | 
             
            [Must Match] (?i-mx:^(?:name|time)$)
         | 
| 608 668 |  | 
| 609 669 |  | 
| 610 | 
            -
            ===== --[no-]case
         | 
| 611 | 
            -
            Force case sensitive matching
         | 
| 612 | 
            -
             | 
| 613 | 
            -
             | 
| 614 | 
            -
             | 
| 615 670 | 
             
            ===== -i|--interactive
         | 
| 616 671 | 
             
            Display an interactive menu of results to perform further operations
         | 
| 617 672 |  | 
| @@ -671,6 +726,14 @@ Import entries older than date | |
| 671 726 | 
             
            [Default Value] None
         | 
| 672 727 |  | 
| 673 728 |  | 
| 729 | 
            +
            ===== --case TYPE
         | 
| 730 | 
            +
             | 
| 731 | 
            +
            Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]
         | 
| 732 | 
            +
             | 
| 733 | 
            +
            [Default Value] smart
         | 
| 734 | 
            +
            [Must Match] (?-mix:^[csi])
         | 
| 735 | 
            +
             | 
| 736 | 
            +
             | 
| 674 737 | 
             
            ===== -f|--from DATE_OR_RANGE
         | 
| 675 738 |  | 
| 676 739 | 
             
            Date range to import. Date range argument should be quoted. Date specifications can be natural language.
         | 
| @@ -753,6 +816,14 @@ Tag boolean | |
| 753 816 | 
             
            [Must Match] (?i-mx:^(?:and|all|any|or|not|none)$)
         | 
| 754 817 |  | 
| 755 818 |  | 
| 819 | 
            +
            ===== --case TYPE
         | 
| 820 | 
            +
             | 
| 821 | 
            +
            Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]
         | 
| 822 | 
            +
             | 
| 823 | 
            +
            [Default Value] smart
         | 
| 824 | 
            +
            [Must Match] (?-mix:^[csi])
         | 
| 825 | 
            +
             | 
| 826 | 
            +
             | 
| 756 827 | 
             
            ===== -s|--section NAME
         | 
| 757 828 |  | 
| 758 829 | 
             
            Specify a section
         | 
| @@ -834,6 +905,14 @@ How many recent entries to tag (0 for all) | |
| 834 905 | 
             
            [Must Match] (?-mix:^\d+$)
         | 
| 835 906 |  | 
| 836 907 |  | 
| 908 | 
            +
            ===== --case TYPE
         | 
| 909 | 
            +
             | 
| 910 | 
            +
            Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]
         | 
| 911 | 
            +
             | 
| 912 | 
            +
            [Default Value] smart
         | 
| 913 | 
            +
            [Must Match] (?-mix:^[csi])
         | 
| 914 | 
            +
             | 
| 915 | 
            +
             | 
| 837 916 | 
             
            ===== -s|--section SECTION_NAME
         | 
| 838 917 |  | 
| 839 918 | 
             
            Section
         | 
| @@ -944,6 +1023,14 @@ Boolean (AND|OR|NOT) with which to combine multiple tag filters | |
| 944 1023 | 
             
            [Must Match] (?i-mx:^(?:and|all|any|or|not|none)$)
         | 
| 945 1024 |  | 
| 946 1025 |  | 
| 1026 | 
            +
            ===== --case TYPE
         | 
| 1027 | 
            +
             | 
| 1028 | 
            +
            Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]
         | 
| 1029 | 
            +
             | 
| 1030 | 
            +
            [Default Value] smart
         | 
| 1031 | 
            +
            [Must Match] (?-mix:^[csi])
         | 
| 1032 | 
            +
             | 
| 1033 | 
            +
             | 
| 947 1034 | 
             
            ===== -s|--section NAME
         | 
| 948 1035 |  | 
| 949 1036 | 
             
            Section
         | 
| @@ -1158,6 +1245,14 @@ Boolean (AND|OR|NOT) with which to combine multiple tag filters | |
| 1158 1245 | 
             
            [Must Match] (?i-mx:^(?:and|all|any|or|not|none)$)
         | 
| 1159 1246 |  | 
| 1160 1247 |  | 
| 1248 | 
            +
            ===== --case TYPE
         | 
| 1249 | 
            +
             | 
| 1250 | 
            +
            Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]
         | 
| 1251 | 
            +
             | 
| 1252 | 
            +
            [Default Value] smart
         | 
| 1253 | 
            +
            [Must Match] (?-mix:^[csi])
         | 
| 1254 | 
            +
             | 
| 1255 | 
            +
             | 
| 1161 1256 | 
             
            ===== -s|--section NAME
         | 
| 1162 1257 |  | 
| 1163 1258 | 
             
            Limit search to section
         | 
| @@ -1220,6 +1315,14 @@ Tag boolean (AND|OR|NOT) | |
| 1220 1315 | 
             
            [Must Match] (?i-mx:^(?:and|all|any|or|not|none)$)
         | 
| 1221 1316 |  | 
| 1222 1317 |  | 
| 1318 | 
            +
            ===== --case TYPE
         | 
| 1319 | 
            +
             | 
| 1320 | 
            +
            Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]
         | 
| 1321 | 
            +
             | 
| 1322 | 
            +
            [Default Value] smart
         | 
| 1323 | 
            +
            [Must Match] (?-mix:^[csi])
         | 
| 1324 | 
            +
             | 
| 1325 | 
            +
             | 
| 1223 1326 | 
             
            ===== -k|--keep X
         | 
| 1224 1327 |  | 
| 1225 1328 | 
             
            How many items to keep in each section (most recent)
         | 
| @@ -1278,6 +1381,14 @@ Multiple selections are allowed, hit tab to add the highlighted entry to the | |
| 1278 1381 | 
             
            selection, and use ctrl-a to select all visible items. Return processes the
         | 
| 1279 1382 | 
             
            selected entries.
         | 
| 1280 1383 | 
             
            ===== Options
         | 
| 1384 | 
            +
            ===== --case TYPE
         | 
| 1385 | 
            +
             | 
| 1386 | 
            +
            Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]
         | 
| 1387 | 
            +
             | 
| 1388 | 
            +
            [Default Value] smart
         | 
| 1389 | 
            +
            [Must Match] (?-mix:^[csi])
         | 
| 1390 | 
            +
             | 
| 1391 | 
            +
             | 
| 1281 1392 | 
             
            ===== -m|--move SECTION
         | 
| 1282 1393 |  | 
| 1283 1394 | 
             
            Move selected items to section
         | 
| @@ -1422,6 +1533,14 @@ Max count to show | |
| 1422 1533 | 
             
            [Default Value] 0
         | 
| 1423 1534 |  | 
| 1424 1535 |  | 
| 1536 | 
            +
            ===== --case TYPE
         | 
| 1537 | 
            +
             | 
| 1538 | 
            +
            Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]
         | 
| 1539 | 
            +
             | 
| 1540 | 
            +
            [Default Value] smart
         | 
| 1541 | 
            +
            [Must Match] (?-mix:^[csi])
         | 
| 1542 | 
            +
             | 
| 1543 | 
            +
             | 
| 1425 1544 | 
             
            ===== -f|--from DATE_OR_RANGE
         | 
| 1426 1545 |  | 
| 1427 1546 | 
             
            Date range to show, or a single day to filter date on.
         | 
| @@ -1577,6 +1696,14 @@ How many recent entries to tag (0 for all) | |
| 1577 1696 | 
             
            [Must Match] (?-mix:^\d+$)
         | 
| 1578 1697 |  | 
| 1579 1698 |  | 
| 1699 | 
            +
            ===== --case TYPE
         | 
| 1700 | 
            +
             | 
| 1701 | 
            +
            Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]
         | 
| 1702 | 
            +
             | 
| 1703 | 
            +
            [Default Value] smart
         | 
| 1704 | 
            +
            [Must Match] (?-mix:^[csi])
         | 
| 1705 | 
            +
             | 
| 1706 | 
            +
             | 
| 1580 1707 | 
             
            ===== --rename ORIG_TAG
         | 
| 1581 1708 |  | 
| 1582 1709 | 
             
            Replace existing tag with tag argument, wildcards (*,?) allowed, or use with --regex
         | 
| @@ -1655,9 +1782,7 @@ Force exact search string matching (case sensitive) | |
| 1655 1782 | 
             
            Output HTML, CSS, and Markdown (ERB) templates for customization
         | 
| 1656 1783 |  | 
| 1657 1784 | 
             
            Templates are printed to STDOUT for piping to a file.
         | 
| 1658 | 
            -
              Save them and use them in the configuration file under  | 
| 1659 | 
            -
             | 
| 1660 | 
            -
              Example `doing template haml > ~/styles/my_doing.haml`
         | 
| 1785 | 
            +
              Save them and use them in the configuration file under export_templates.
         | 
| 1661 1786 | 
             
            ===== Options
         | 
| 1662 1787 | 
             
            ===== -c
         | 
| 1663 1788 | 
             
            List in single column for completion
         | 
| @@ -1771,6 +1896,14 @@ Count to display | |
| 1771 1896 | 
             
            [Must Match] (?-mix:^\d+$)
         | 
| 1772 1897 |  | 
| 1773 1898 |  | 
| 1899 | 
            +
            ===== --case TYPE
         | 
| 1900 | 
            +
             | 
| 1901 | 
            +
            Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]
         | 
| 1902 | 
            +
             | 
| 1903 | 
            +
            [Default Value] smart
         | 
| 1904 | 
            +
            [Must Match] (?-mix:^[csi])
         | 
| 1905 | 
            +
             | 
| 1906 | 
            +
             | 
| 1774 1907 | 
             
            ===== -o|--output FORMAT
         | 
| 1775 1908 |  | 
| 1776 1909 | 
             
            Output to export format (csv|doing|html|markdown|say|taskpaper|template|timeline|wiki)
         | 
    
        data/lib/doing/item.rb
    CHANGED
    
    | @@ -75,7 +75,7 @@ module Doing | |
| 75 75 | 
             
                  negate ? !matches : matches
         | 
| 76 76 | 
             
                end
         | 
| 77 77 |  | 
| 78 | 
            -
                def search(search, negate: false)
         | 
| 78 | 
            +
                def search(search, negate: false, case_type: :smart)
         | 
| 79 79 | 
             
                  text = @title + @note.to_s
         | 
| 80 80 | 
             
                  pattern = case search.strip
         | 
| 81 81 | 
             
                            when %r{^/.*?/$}
         | 
| @@ -84,7 +84,12 @@ module Doing | |
| 84 84 | 
             
                              case_sensitive = true
         | 
| 85 85 | 
             
                              search.sub(/^'(.*?)'?$/, '\1')
         | 
| 86 86 | 
             
                            else
         | 
| 87 | 
            -
                               | 
| 87 | 
            +
                              if case_type == :smart
         | 
| 88 | 
            +
                                case_sensitive = true if search =~ /[A-Z]/
         | 
| 89 | 
            +
                              else
         | 
| 90 | 
            +
                                case_sensitive = case_type == :sensitive
         | 
| 91 | 
            +
                              end
         | 
| 92 | 
            +
             | 
| 88 93 | 
             
                              search.split('').join('.{0,3}')
         | 
| 89 94 | 
             
                            end
         | 
| 90 95 | 
             
                  rx = Regexp.new(pattern, !case_sensitive)
         | 
    
        data/lib/doing/string.rb
    CHANGED
    
    | @@ -164,6 +164,28 @@ module Doing | |
| 164 164 | 
             
                  end
         | 
| 165 165 | 
             
                end
         | 
| 166 166 |  | 
| 167 | 
            +
                ##
         | 
| 168 | 
            +
                ## @brief      Convert a case sensitivity string to a symbol
         | 
| 169 | 
            +
                ##
         | 
| 170 | 
            +
                ## @return     Symbol :smart, :sensitive, :insensitive
         | 
| 171 | 
            +
                ##
         | 
| 172 | 
            +
                def normalize_case!
         | 
| 173 | 
            +
                  replace normalize_case
         | 
| 174 | 
            +
                end
         | 
| 175 | 
            +
             | 
| 176 | 
            +
                def normalize_case(default = :smart)
         | 
| 177 | 
            +
                  case self
         | 
| 178 | 
            +
                  when /^c/i
         | 
| 179 | 
            +
                    :sensitive
         | 
| 180 | 
            +
                  when /^i/i
         | 
| 181 | 
            +
                    :insensitive
         | 
| 182 | 
            +
                  when /^s/i
         | 
| 183 | 
            +
                    :smart
         | 
| 184 | 
            +
                  else
         | 
| 185 | 
            +
                    default.is_a?(Symbol) ? default : default.normalize_case
         | 
| 186 | 
            +
                  end
         | 
| 187 | 
            +
                end
         | 
| 188 | 
            +
             | 
| 167 189 | 
             
                ##
         | 
| 168 190 | 
             
                ## @brief      Convert a boolean string to a symbol
         | 
| 169 191 | 
             
                ##
         | 
    
        data/lib/doing/version.rb
    CHANGED
    
    
    
        data/lib/doing/wwid.rb
    CHANGED
    
    | @@ -700,12 +700,17 @@ module Doing | |
| 700 700 | 
             
                    end
         | 
| 701 701 |  | 
| 702 702 | 
             
                    if keep && opt[:search]
         | 
| 703 | 
            -
                       | 
| 703 | 
            +
                      opt[:case] = opt[:case].normalize_case unless opt[:case].is_a?(Symbol)
         | 
| 704 | 
            +
                      search_match = if opt[:search].nil? || opt[:search].empty?
         | 
| 705 | 
            +
                                       true
         | 
| 706 | 
            +
                                     else
         | 
| 707 | 
            +
                                       item.search(opt[:search], case_type: opt[:case])
         | 
| 708 | 
            +
                                     end
         | 
| 709 | 
            +
             | 
| 704 710 | 
             
                      keep = false unless search_match
         | 
| 705 711 | 
             
                      keep = opt[:not] ? !keep : keep
         | 
| 706 712 | 
             
                    end
         | 
| 707 713 |  | 
| 708 | 
            -
             | 
| 709 714 | 
             
                    if keep && opt[:date_filter]&.length == 2
         | 
| 710 715 | 
             
                      start_date = opt[:date_filter][0]
         | 
| 711 716 | 
             
                      end_date = opt[:date_filter][1]
         | 
| @@ -773,14 +778,13 @@ module Doing | |
| 773 778 | 
             
                  if opt[:search]
         | 
| 774 779 | 
             
                    search = opt[:search]
         | 
| 775 780 | 
             
                    search.sub!(/^'?/, "'") if opt[:exact]
         | 
| 776 | 
            -
                    search.downcase! if opt[:case] == false
         | 
| 777 781 | 
             
                    opt[:search] = search
         | 
| 778 782 | 
             
                  end
         | 
| 779 783 |  | 
| 780 784 | 
             
                  opt[:query] = opt[:search] if opt[:search] && !opt[:query]
         | 
| 781 785 | 
             
                  opt[:query] = "!#{opt[:query]}" if opt[:not]
         | 
| 782 786 | 
             
                  opt[:multiple] = true
         | 
| 783 | 
            -
                  items = filter_items([], opt: { section: section, search: opt[:search] })
         | 
| 787 | 
            +
                  items = filter_items([], opt: { section: section, search: opt[:search], case: opt[:case] })
         | 
| 784 788 |  | 
| 785 789 | 
             
                  selection = choose_from_items(items, opt, include_section: section =~ /^all$/i)
         | 
| 786 790 |  | 
| @@ -957,7 +961,7 @@ module Doing | |
| 957 961 | 
             
                  if opt[:delete]
         | 
| 958 962 | 
             
                    res = opt[:force] ? true : yn("Delete #{items.size} items?", default_response: 'y')
         | 
| 959 963 | 
             
                    if res
         | 
| 960 | 
            -
                      items.each { |item| delete_item(item) }
         | 
| 964 | 
            +
                      items.each { |item| delete_item(item, single: items.count == 1) }
         | 
| 961 965 | 
             
                      write(@doing_file)
         | 
| 962 966 | 
             
                    end
         | 
| 963 967 | 
             
                    return
         | 
| @@ -1015,7 +1019,7 @@ module Doing | |
| 1015 1019 | 
             
                      title = input_lines[0]&.strip
         | 
| 1016 1020 |  | 
| 1017 1021 | 
             
                      if title.nil? || title =~ /^#{divider.strip}$/ || title.strip.empty?
         | 
| 1018 | 
            -
                        delete_item(items[i])
         | 
| 1022 | 
            +
                        delete_item(items[i], single: new_items.count == 1)
         | 
| 1019 1023 | 
             
                      else
         | 
| 1020 1024 | 
             
                        note = input_lines.length > 1 ? input_lines[1..-1] : []
         | 
| 1021 1025 |  | 
| @@ -1265,13 +1269,13 @@ module Doing | |
| 1265 1269 | 
             
                ##
         | 
| 1266 1270 | 
             
                ## @param      item  The item
         | 
| 1267 1271 | 
             
                ##
         | 
| 1268 | 
            -
                def delete_item(item)
         | 
| 1272 | 
            +
                def delete_item(item, single: false)
         | 
| 1269 1273 | 
             
                  section = item.section
         | 
| 1270 1274 |  | 
| 1271 1275 | 
             
                  section_items = @content[section][:items]
         | 
| 1272 1276 | 
             
                  deleted = section_items.delete(item)
         | 
| 1273 1277 | 
             
                  logger.count(:deleted)
         | 
| 1274 | 
            -
                  logger.info('Entry deleted:', deleted.title)
         | 
| 1278 | 
            +
                  logger.info('Entry deleted:', deleted.title) if single
         | 
| 1275 1279 | 
             
                end
         | 
| 1276 1280 |  | 
| 1277 1281 | 
             
                ##
         | 
| @@ -1897,6 +1901,7 @@ module Doing | |
| 1897 1901 | 
             
                  end
         | 
| 1898 1902 |  | 
| 1899 1903 | 
             
                  opts[:search] = options[:search] if options[:search]
         | 
| 1904 | 
            +
                  opts[:case] = options[:case]
         | 
| 1900 1905 | 
             
                  opts[:not] = options[:negate]
         | 
| 1901 1906 | 
             
                  list_section(opts)
         | 
| 1902 1907 | 
             
                end
         | 
| @@ -2070,7 +2075,7 @@ EOS | |
| 2070 2075 | 
             
                      (max - k.length).times do
         | 
| 2071 2076 | 
             
                        spacer += ' '
         | 
| 2072 2077 | 
             
                      end
         | 
| 2073 | 
            -
                       | 
| 2078 | 
            +
                      _d, h, m = format_time(v, human: true)
         | 
| 2074 2079 | 
             
                      output.push("┃ #{spacer}#{k}:#{format('%<h> 4dh %<m>02dm', h: h, m: m)} ┃")
         | 
| 2075 2080 | 
             
                    end
         | 
| 2076 2081 |  |